diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index aefbf14..7d710f2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -39,6 +39,39 @@ jobs:
echo "Repository hygiene checks passed."
+ api-contract:
+ name: API Contract Drift
+ needs: repository-hygiene
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ cache: npm
+ cache-dependency-path: apps/frontend/package-lock.json
+
+ - name: Setup Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.13"
+ cache: pip
+
+ - name: Install frontend dependencies
+ run: npm ci --prefix apps/frontend
+
+ - name: Install backend dependencies
+ run: |
+ python -m pip install -r apps/backend/requirements-dev.txt
+ python -m pip install -e apps/backend --no-deps
+
+ - name: Check generated frontend API contract
+ run: npm --prefix apps/frontend run generate:api-contract -- --check
+
frontend:
name: Frontend
needs: repository-hygiene
diff --git a/apps/backend/app/schemas/ai.py b/apps/backend/app/schemas/ai.py
index daad490..bb74db3 100644
--- a/apps/backend/app/schemas/ai.py
+++ b/apps/backend/app/schemas/ai.py
@@ -1,6 +1,8 @@
from datetime import UTC, datetime
from typing import Literal
+from pydantic import Field
+
from app.schemas.base import CamelModel
AiProvider = Literal["openai", "anthropic", "gemini", "openrouter", "ollama"]
@@ -65,4 +67,4 @@ class AiProviderTestRequest(CamelModel):
class AiProviderTestResponse(CamelModel):
ok: bool
message: str
- checked_at: datetime = datetime.now(UTC)
+ checked_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
diff --git a/apps/frontend/README.md b/apps/frontend/README.md
index d04707e..6aa2d1d 100644
--- a/apps/frontend/README.md
+++ b/apps/frontend/README.md
@@ -37,9 +37,17 @@ npm --prefix apps/frontend run lint # eslint
npm --prefix apps/frontend run test # vitest, with coverage
npm --prefix apps/frontend run test:watch
npm --prefix apps/frontend run build # tsc -b && vite build
+npm run generate:api-contract # regenerate DTOs from FastAPI OpenAPI
+npm --prefix apps/frontend run generate:api-contract -- --check # fail on drift
npm run test:prototype # disposable fixtures + Playwright journeys
```
+The generated contract lives at
+`src/shared/services/api/generated.ts` and must not be edited directly. The
+generator imports backend module `app.main:app` from `apps/backend`, strips only import-time dynamic
+datetime defaults, and runs the pinned `openapi-typescript@7.13.0` tool. The CI
+API Contract Drift job installs both app lockfiles and runs the check command.
+
From the repository root: `npm run dev:frontend`, `npm run lint:frontend`,
`npm run build:frontend`, and `npm run test:prototype`. There is no root alias
for the Vitest suite — run `npm --prefix apps/frontend run test`.
diff --git a/apps/frontend/package-lock.json b/apps/frontend/package-lock.json
index 4dfe440..dcb1f06 100644
--- a/apps/frontend/package-lock.json
+++ b/apps/frontend/package-lock.json
@@ -40,6 +40,7 @@
"eslint-plugin-react-refresh": "^0.5.3",
"globals": "^17.8.0",
"jsdom": "^29.1.1",
+ "openapi-typescript": "7.13.0",
"postcss": "^8.5.23",
"tailwindcss": "^3.4.10",
"typescript": "^5.5.4",
@@ -941,6 +942,72 @@
"node": ">=20"
}
},
+ "node_modules/@redocly/ajv": {
+ "version": "8.11.2",
+ "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz",
+ "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js-replace": "^1.0.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@redocly/ajv/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@redocly/config": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz",
+ "integrity": "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@redocly/openapi-core": {
+ "version": "1.34.17",
+ "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.17.tgz",
+ "integrity": "sha512-wsV2keCt6B806XpSdezbWZ9aFJYf14YVh+XQf0ESt7M90yqVuxH9//PxvtC70sgj9OCkRM3nRaLfu4MsGQZRig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@redocly/ajv": "8.11.2",
+ "@redocly/config": "0.22.0",
+ "colorette": "1.4.0",
+ "https-proxy-agent": "7.0.6",
+ "js-levenshtein": "1.1.6",
+ "js-yaml": "4.2.0",
+ "minimatch": "5.1.9",
+ "pluralize": "8.0.0",
+ "yaml-ast-parser": "0.0.43"
+ },
+ "engines": {
+ "node": ">=18.17.0",
+ "npm": ">=9.5.0"
+ }
+ },
+ "node_modules/@redocly/openapi-core/node_modules/minimatch": {
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
+ "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz",
@@ -1937,6 +2004,16 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/ajv": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
@@ -1954,6 +2031,16 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/ansi-colors": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -2004,6 +2091,13 @@
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
"license": "MIT"
},
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
"node_modules/aria-query": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
@@ -2243,6 +2337,13 @@
"node": ">=18"
}
},
+ "node_modules/change-case": {
+ "version": "5.4.4",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz",
+ "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -2294,6 +2395,13 @@
"node": ">=6"
}
},
+ "node_modules/colorette": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
+ "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -3137,6 +3245,20 @@
"integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==",
"license": "MIT"
},
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -3167,6 +3289,19 @@
"node": ">=8"
}
},
+ "node_modules/index-to-position": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz",
+ "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -3286,12 +3421,45 @@
"jiti": "bin/jiti.js"
}
},
+ "node_modules/js-levenshtein": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
+ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT"
},
+ "node_modules/js-yaml": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
+ "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodeca"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
"node_modules/jsdom": {
"version": "29.1.1",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz",
@@ -3990,6 +4158,40 @@
"node": ">=12.20.0"
}
},
+ "node_modules/openapi-typescript": {
+ "version": "7.13.0",
+ "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.13.0.tgz",
+ "integrity": "sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@redocly/openapi-core": "^1.34.6",
+ "ansi-colors": "^4.1.3",
+ "change-case": "^5.4.4",
+ "parse-json": "^8.3.0",
+ "supports-color": "^10.2.2",
+ "yargs-parser": "^21.1.1"
+ },
+ "bin": {
+ "openapi-typescript": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "typescript": "^5.x"
+ }
+ },
+ "node_modules/openapi-typescript/node_modules/supports-color": {
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
+ "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -4040,6 +4242,24 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parse-json": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz",
+ "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.26.2",
+ "index-to-position": "^1.1.0",
+ "type-fest": "^4.39.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/parse5": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz",
@@ -4169,6 +4389,16 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/pluralize": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
+ "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/postcss": {
"version": "8.5.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
@@ -5026,6 +5256,19 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/type-fest": {
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+ "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
@@ -5115,6 +5358,13 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/uri-js-replace": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz",
+ "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/use-sync-external-store": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
@@ -5439,6 +5689,23 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/yaml-ast-parser": {
+ "version": "0.0.43",
+ "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz",
+ "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/apps/frontend/package.json b/apps/frontend/package.json
index c613f2b..1f5fef2 100644
--- a/apps/frontend/package.json
+++ b/apps/frontend/package.json
@@ -6,6 +6,7 @@
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
+ "generate:api-contract": "node ../../scripts/generate-api-contract.mjs",
"preview": "vite preview",
"lint": "eslint .",
"test": "vitest run --coverage",
@@ -45,6 +46,7 @@
"eslint-plugin-react-refresh": "^0.5.3",
"globals": "^17.8.0",
"jsdom": "^29.1.1",
+ "openapi-typescript": "7.13.0",
"postcss": "^8.5.23",
"tailwindcss": "^3.4.10",
"typescript": "^5.5.4",
@@ -54,6 +56,7 @@
},
"overrides": {
"dompurify": "3.4.12",
- "brace-expansion": "^5.0.8"
+ "brace-expansion": "^5.0.8",
+ "js-yaml": "4.3.0"
}
}
diff --git a/apps/frontend/src/features/explorer/components/CodePreview.tsx b/apps/frontend/src/features/explorer/components/CodePreview.tsx
index d8e1818..caa5e2b 100644
--- a/apps/frontend/src/features/explorer/components/CodePreview.tsx
+++ b/apps/frontend/src/features/explorer/components/CodePreview.tsx
@@ -108,7 +108,7 @@ export function CodePreview({ node, repositoryId, citation }: CodePreviewProps)
setContent(file.content);
setIsBinary(file.isBinary);
setIsImage(file.isImage);
- setMediaType(file.mediaType);
+ setMediaType(file.mediaType ?? null);
setTruncated(file.truncated);
})
.catch((caught) => {
diff --git a/apps/frontend/src/features/explorer/components/FileTreeView.tsx b/apps/frontend/src/features/explorer/components/FileTreeView.tsx
index 34407a9..4ecf4c9 100644
--- a/apps/frontend/src/features/explorer/components/FileTreeView.tsx
+++ b/apps/frontend/src/features/explorer/components/FileTreeView.tsx
@@ -151,7 +151,7 @@ function TreeItem({ node, depth, searchQuery }: TreeItemProps) {
)}>
{node.name}
- {node.size !== undefined && node.type === 'file' && (
+ {node.size != null && node.type === 'file' && (
{formatSize(node.size)}
diff --git a/apps/frontend/src/shared/services/api/architecture.ts b/apps/frontend/src/shared/services/api/architecture.ts
index 40efa4d..8f21c6e 100644
--- a/apps/frontend/src/shared/services/api/architecture.ts
+++ b/apps/frontend/src/shared/services/api/architecture.ts
@@ -1,5 +1,6 @@
import { api } from './client';
import type { RequestConfig } from './client';
+import type { components } from './generated';
import type {
ArchitectureResponse,
AuthenticationExplanationResponse,
@@ -9,14 +10,23 @@ import type {
export const architectureService = {
getArchitecture(repositoryId: string, config?: RequestConfig): Promise {
- return api.get(`/analysis/${repositoryId}/architecture`, config);
+ return api.get(`/analysis/${repositoryId}/architecture`, config)
+ .then((response) => ({ ...response, diagnostics: response.diagnostics ?? [] }));
},
getAuthenticationExplanation(
repositoryId: string,
config?: RequestConfig,
): Promise {
- return api.get(`/analysis/${repositoryId}/architecture/authentication`, config);
+ return api.get(
+ `/analysis/${repositoryId}/architecture/authentication`, config,
+ ).then((response) => ({
+ ...response,
+ claims: response.claims ?? [],
+ relationships: response.relationships ?? [],
+ chains: response.chains ?? [],
+ diagnostics: response.diagnostics ?? [],
+ }));
},
getRevisionManifest(repositoryId: string, config?: RequestConfig): Promise {
diff --git a/apps/frontend/src/shared/services/api/dependencies.ts b/apps/frontend/src/shared/services/api/dependencies.ts
index 4e9fb97..48d1321 100644
--- a/apps/frontend/src/shared/services/api/dependencies.ts
+++ b/apps/frontend/src/shared/services/api/dependencies.ts
@@ -1,9 +1,11 @@
import { api } from './client';
import type { RequestConfig } from './client';
+import type { components } from './generated';
import type { DependencyGraphResponse } from './types';
export const dependencyService = {
getDependencyGraph(repositoryId: string, config?: RequestConfig): Promise {
- return api.get(`/analysis/${repositoryId}/dependencies`, config);
+ return api.get(`/analysis/${repositoryId}/dependencies`, config)
+ .then((response) => ({ ...response, diagnostics: response.diagnostics ?? [] }));
},
};
diff --git a/apps/frontend/src/shared/services/api/errors.test.ts b/apps/frontend/src/shared/services/api/errors.test.ts
index 837769c..dfb9a32 100644
--- a/apps/frontend/src/shared/services/api/errors.test.ts
+++ b/apps/frontend/src/shared/services/api/errors.test.ts
@@ -5,8 +5,10 @@ import {
NetworkError,
TimeoutError,
isApiError,
+ isErrorResponse,
isNetworkError,
isTimeoutError,
+ getErrorDetail,
parseRetryAfter,
} from './errors';
@@ -96,4 +98,33 @@ describe('type guards', () => {
expect(isApiError(undefined)).toBe(false);
expect(isNetworkError('nope')).toBe(false);
});
+
+ it('validates the generated error envelope at the untrusted response boundary', () => {
+ expect(isErrorResponse({ code: 'unauthorized', message: 'Sign in required' })).toBe(true);
+ expect(isErrorResponse({ code: 'unauthorized' })).toBe(false);
+ expect(isErrorResponse(null)).toBe(false);
+ });
+});
+
+describe('getErrorDetail', () => {
+ it('only renders details from a valid backend error envelope', () => {
+ const valid = new ApiError(
+ 422,
+ 'Unprocessable Entity',
+ { code: 'validation_error', message: 'Invalid request', details: ['name is required'] },
+ '/x',
+ );
+ const invalid = new ApiError(
+ 422,
+ 'Unprocessable Entity',
+ { details: ['must not render without code and message'] },
+ '/x',
+ );
+
+ expect(getErrorDetail(valid)).toEqual({
+ message: 'Invalid request',
+ details: ['name is required'],
+ });
+ expect(getErrorDetail(invalid).details).toEqual([]);
+ });
});
diff --git a/apps/frontend/src/shared/services/api/errors.ts b/apps/frontend/src/shared/services/api/errors.ts
index c1781c2..5fca9e2 100644
--- a/apps/frontend/src/shared/services/api/errors.ts
+++ b/apps/frontend/src/shared/services/api/errors.ts
@@ -1,3 +1,7 @@
+import type { components } from './generated';
+
+export type ApiErrorResponse = components['schemas']['ErrorResponse'];
+
export class ApiError extends Error {
constructor(
public status: number,
@@ -145,14 +149,14 @@ export function getErrorDetail(error: unknown): { message: string; details: stri
}
function getBackendMessage(body: unknown): string | null {
- if (!body || typeof body !== 'object') return null;
- const maybeMessage = (body as { message?: unknown }).message;
+ if (!isErrorResponse(body)) return null;
+ const maybeMessage = body.message;
return typeof maybeMessage === 'string' && maybeMessage.trim() ? maybeMessage : null;
}
function getBackendDetails(body: unknown): string[] {
- if (!body || typeof body !== 'object') return [];
- const raw = (body as { details?: unknown }).details;
+ if (!isErrorResponse(body)) return [];
+ const raw = body.details;
if (Array.isArray(raw)) {
return raw
.map((item) => {
@@ -172,7 +176,17 @@ function getBackendDetails(body: unknown): string[] {
}
function getBackendRequestId(body: unknown): string | null {
- if (!body || typeof body !== 'object') return null;
- const maybeRequestId = (body as { request_id?: unknown }).request_id;
+ if (!isErrorResponse(body)) return null;
+ const maybeRequestId = body.request_id;
return typeof maybeRequestId === 'string' && maybeRequestId.trim() ? maybeRequestId : null;
}
+
+/** Runtime boundary for untrusted backend error responses. */
+export function isErrorResponse(body: unknown): body is ApiErrorResponse {
+ return Boolean(
+ body &&
+ typeof body === 'object' &&
+ typeof (body as { code?: unknown }).code === 'string' &&
+ typeof (body as { message?: unknown }).message === 'string',
+ );
+}
diff --git a/apps/frontend/src/shared/services/api/generated-contract.test.ts b/apps/frontend/src/shared/services/api/generated-contract.test.ts
new file mode 100644
index 0000000..cabb875
--- /dev/null
+++ b/apps/frontend/src/shared/services/api/generated-contract.test.ts
@@ -0,0 +1,41 @@
+import { describe, expect, it } from 'vitest';
+import type { components, paths } from './generated';
+import generated from './generated.ts?raw';
+
+// These type aliases make the proof-workflow fields compile against the
+// generated document, so a schema rename/removal fails the frontend build.
+type ProofWorkflowContract = Pick<
+ components['schemas']['RiSnapshotMetadataResponse'],
+ 'schemaVersion' | 'snapshotId' | 'revisionValue' | 'canonicalGraphHash' | 'sealedAt'
+> & Pick<
+ components['schemas']['EvidenceSourceResponse'],
+ 'factId' | 'path' | 'startLine' | 'endLine' | 'status' | 'content'
+> & Pick<
+ components['schemas']['ArchitectureDiagnostic'],
+ 'code' | 'severity' | 'message' | 'path' | 'startLine' | 'endLine'
+>;
+
+type ErrorEnvelope = Pick;
+type ReviewOperation = paths['/analysis/{repository_id}/review']['get'];
+type ReviewResponse = NonNullable['application/json'];
+
+// Exported solely so the compiler checks the selected generated component
+// fields and the response operation above under strict TypeScript settings.
+export type GeneratedContractCoverage = ProofWorkflowContract & ErrorEnvelope & ReviewResponse;
+
+describe('generated frontend API contract', () => {
+ it('contains proof-workflow, diagnostics, and error-envelope schemas', () => {
+ expect(generated).toContain('RiSnapshotMetadataResponse');
+ expect(generated).toContain('EvidenceSourceResponse');
+ expect(generated).toContain('ArchitectureDiagnostic');
+ expect(generated).toContain('EngineeringReviewResponse');
+ expect(generated).toContain('ErrorResponse');
+ expect(generated).toContain('canonicalGraphHash');
+ expect(generated).toContain('request_id');
+ });
+
+ it('contains no environment URLs or embedded secret-like values', () => {
+ expect(generated).not.toMatch(/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|host\.docker\.internal)/i);
+ expect(generated).not.toMatch(/(?:api[_-]?key|password|secret|token)\s*[:=]\s*["'`][^"'`]+["'`]/i);
+ });
+});
diff --git a/apps/frontend/src/shared/services/api/generated.ts b/apps/frontend/src/shared/services/api/generated.ts
new file mode 100644
index 0000000..322292e
--- /dev/null
+++ b/apps/frontend/src/shared/services/api/generated.ts
@@ -0,0 +1,7026 @@
+/**
+ * This file was auto-generated by openapi-typescript.
+ * Do not make direct changes to the file.
+ */
+
+// Source: apps/backend/app.main:app.openapi()
+// Generator: openapi-typescript@7.13.0
+
+export interface paths {
+ "/ai/config": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Ai Config */
+ get: operations["get_ai_config_ai_config_get"];
+ /** Save Ai Config */
+ put: operations["save_ai_config_ai_config_put"];
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/ai/query": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Query Ai */
+ post: operations["query_ai_ai_query_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/ai/test": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Test Ai Config */
+ post: operations["test_ai_config_ai_test_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/architecture": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Architecture */
+ get: operations["get_architecture_analysis__repository_id__architecture_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/architecture/authentication": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Authentication Explanation */
+ get: operations["get_authentication_explanation_analysis__repository_id__architecture_authentication_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/cancel": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Cancel Analysis */
+ post: operations["cancel_analysis_analysis__repository_id__cancel_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/dependencies": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Dependencies */
+ get: operations["get_dependencies_analysis__repository_id__dependencies_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/evidence": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Evidence Source */
+ get: operations["get_evidence_source_analysis__repository_id__evidence_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/insights": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Insights */
+ get: operations["get_insights_analysis__repository_id__insights_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/review": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Review */
+ get: operations["get_review_analysis__repository_id__review_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/revision-manifest": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Revision Manifest */
+ get: operations["get_revision_manifest_analysis__repository_id__revision_manifest_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/revision-manifest/verify": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Verify Revision Manifest */
+ post: operations["verify_revision_manifest_analysis__repository_id__revision_manifest_verify_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/start": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Start Analysis */
+ post: operations["start_analysis_analysis__repository_id__start_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/analysis/{repository_id}/status": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Analysis Status */
+ get: operations["get_analysis_status_analysis__repository_id__status_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/auth/login": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Login */
+ post: operations["login_auth_login_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/auth/logout": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Logout */
+ post: operations["logout_auth_logout_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/auth/me": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Me */
+ get: operations["me_auth_me_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/auth/refresh": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Refresh */
+ post: operations["refresh_auth_refresh_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/auth/register": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Register */
+ post: operations["register_auth_register_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/documentation/generate": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Generate Documentation */
+ post: operations["generate_documentation_documentation_generate_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/export": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Export Report */
+ post: operations["export_report_export_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/health": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Health */
+ get: operations["health_health_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/intelligence/v1/snapshots/{snapshot_id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Snapshot */
+ get: operations["get_snapshot_intelligence_v1_snapshots__snapshot_id__get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/intelligence/v1/snapshots/{snapshot_id}/assertions": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** List Assertions */
+ get: operations["list_assertions_intelligence_v1_snapshots__snapshot_id__assertions_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/intelligence/v1/snapshots/{snapshot_id}/evidence": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** List Evidence */
+ get: operations["list_evidence_intelligence_v1_snapshots__snapshot_id__evidence_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/intelligence/v1/snapshots/{snapshot_id}/impact": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Impact */
+ get: operations["get_impact_intelligence_v1_snapshots__snapshot_id__impact_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/intelligence/v1/snapshots/{snapshot_id}/neighbours": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** List Neighbours */
+ get: operations["list_neighbours_intelligence_v1_snapshots__snapshot_id__neighbours_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/intelligence/v1/snapshots/{snapshot_id}/paths": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** List Paths */
+ get: operations["list_paths_intelligence_v1_snapshots__snapshot_id__paths_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/intelligence/v1/snapshots/{snapshot_id}/references": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** List References */
+ get: operations["list_references_intelligence_v1_snapshots__snapshot_id__references_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/intelligence/v1/snapshots/{snapshot_id}/symbols": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** List Symbols */
+ get: operations["list_symbols_intelligence_v1_snapshots__snapshot_id__symbols_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/metrics": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Metrics */
+ get: operations["metrics_metrics_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/ready": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Readiness */
+ get: operations["readiness_ready_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/repositories": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** List Repositories */
+ get: operations["list_repositories_repositories_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/repositories/{repository_id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Repository */
+ get: operations["get_repository_repositories__repository_id__get"];
+ put?: never;
+ post?: never;
+ /** Delete Repository */
+ delete: operations["delete_repository_repositories__repository_id__delete"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/repositories/{repository_id}/file": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /** Get Repository File */
+ get: operations["get_repository_file_repositories__repository_id__file_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/repositories/github": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Import Github Repository */
+ post: operations["import_github_repository_repositories_github_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/repositories/upload": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Upload Repository */
+ post: operations["upload_repository_repositories_upload_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+}
+export type webhooks = Record;
+export interface components {
+ schemas: {
+ /** AiCitation */
+ AiCitation: {
+ /** Content */
+ content: string;
+ /**
+ * Endline
+ * @default 1
+ */
+ endLine: number;
+ /** File */
+ file: string;
+ /**
+ * Startline
+ * @default 1
+ */
+ startLine: number;
+ };
+ /** AiMessage */
+ AiMessage: {
+ /** Citations */
+ citations?: components["schemas"]["AiCitation"][] | null;
+ /** Content */
+ content: string;
+ /**
+ * Role
+ * @enum {string}
+ */
+ role: "user" | "assistant";
+ /**
+ * Timestamp
+ * Format: date-time
+ */
+ timestamp: string;
+ };
+ /** AiProviderConfig */
+ AiProviderConfig: {
+ /** Apikey */
+ apiKey?: string | null;
+ /** Baseurl */
+ baseUrl?: string | null;
+ /** Model */
+ model?: string | null;
+ /**
+ * Provider
+ * @enum {string}
+ */
+ provider: "openai" | "anthropic" | "gemini" | "openrouter" | "ollama";
+ };
+ /** AiProviderPublicConfig */
+ AiProviderPublicConfig: {
+ /** Apikeylast4 */
+ apiKeyLast4?: string | null;
+ /** Baseurl */
+ baseUrl?: string | null;
+ /**
+ * Hasapikey
+ * @default false
+ */
+ hasApiKey: boolean;
+ /** Model */
+ model?: string | null;
+ /** Provider */
+ provider?: ("openai" | "anthropic" | "gemini" | "openrouter" | "ollama") | null;
+ };
+ /** AiProviderTestRequest */
+ AiProviderTestRequest: {
+ /** Apikey */
+ apiKey?: string | null;
+ /** Baseurl */
+ baseUrl?: string | null;
+ /** Model */
+ model?: string | null;
+ /** Provider */
+ provider?: ("openai" | "anthropic" | "gemini" | "openrouter" | "ollama") | null;
+ };
+ /** AiProviderTestResponse */
+ AiProviderTestResponse: {
+ /**
+ * Checkedat
+ * Format: date-time
+ */
+ checkedAt?: string;
+ /** Message */
+ message: string;
+ /** Ok */
+ ok: boolean;
+ };
+ /** AiQueryContext */
+ AiQueryContext: {
+ /** Conversationhistory */
+ conversationHistory?: components["schemas"]["AiMessage"][] | null;
+ /** Selectedfile */
+ selectedFile?: string | null;
+ /** Selectednodeid */
+ selectedNodeId?: string | null;
+ };
+ /** AiQueryRequest */
+ AiQueryRequest: {
+ context?: components["schemas"]["AiQueryContext"] | null;
+ /** Query */
+ query: string;
+ /** Repositoryid */
+ repositoryId: string;
+ };
+ /** AiQueryResponse */
+ AiQueryResponse: {
+ message: components["schemas"]["AiMessage"];
+ /**
+ * Suggestions
+ * @default []
+ */
+ suggestions: string[];
+ };
+ /** AnalysisStartResponse */
+ AnalysisStartResponse: {
+ /** Jobid */
+ jobId?: string | null;
+ /** Repositoryid */
+ repositoryId: string;
+ /**
+ * Status
+ * @enum {string}
+ */
+ status: "queued" | "running" | "completed" | "failed" | "cancelled";
+ };
+ /** AnalysisStatusResponse */
+ AnalysisStatusResponse: {
+ /** Completedat */
+ completedAt?: string | null;
+ /** Error */
+ error?: string | null;
+ /** Jobid */
+ jobId?: string | null;
+ /** Progress */
+ progress: number;
+ /** Repositoryid */
+ repositoryId: string;
+ /** Stage */
+ stage?: ("uploading" | "extracting" | "reading-structure" | "detecting-languages" | "detecting-framework" | "building-file-tree" | "extracting-modules" | "building-dependency-graph" | "preparing-architecture" | "completed") | null;
+ /** Startedat */
+ startedAt?: string | null;
+ /**
+ * Status
+ * @enum {string}
+ */
+ status: "queued" | "running" | "completed" | "failed" | "cancelled";
+ };
+ /** ArchEdge */
+ ArchEdge: {
+ /** Evidence */
+ evidence: components["schemas"]["ArchEvidence"][];
+ /** Id */
+ id: string;
+ /** Label */
+ label?: string | null;
+ /** Predicate */
+ predicate: string;
+ /** Source */
+ source: string;
+ /** Target */
+ target: string;
+ /**
+ * Truthclass
+ * @enum {string}
+ */
+ truthClass: "resolved" | "inferred";
+ /**
+ * Type
+ * @enum {string}
+ */
+ type: "dependency" | "import" | "api-call" | "data-flow" | "event" | "reads" | "writes" | "calls" | "config-usage";
+ };
+ /** ArchEvidence */
+ ArchEvidence: {
+ /** Endline */
+ endLine: number;
+ /** Factid */
+ factId: string;
+ /** Path */
+ path: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Startline */
+ startLine: number;
+ };
+ /** ArchitectureDiagnostic */
+ ArchitectureDiagnostic: {
+ /** Category */
+ category: string;
+ /** Code */
+ code: string;
+ /** Details */
+ details?: {
+ [key: string]: unknown;
+ } | null;
+ /** Endline */
+ endLine?: number | null;
+ /** Message */
+ message: string;
+ /** Nodeids */
+ nodeIds?: string[] | null;
+ /** Objectkey */
+ objectKey?: string | null;
+ /** Path */
+ path?: string | null;
+ /**
+ * Severity
+ * @enum {string}
+ */
+ severity: "fatal" | "error" | "warning" | "info";
+ /** Startline */
+ startLine?: number | null;
+ /** Subjectkey */
+ subjectKey?: string | null;
+ };
+ /** ArchitectureResponse */
+ ArchitectureResponse: {
+ /** Architecturetype */
+ architectureType: string;
+ /** Detectedlayers */
+ detectedLayers: components["schemas"]["ArchLayer"][];
+ /** Diagnostics */
+ diagnostics?: components["schemas"]["ArchitectureDiagnostic"][];
+ /** Edges */
+ edges: components["schemas"]["ArchEdge"][];
+ /** Modules */
+ modules: components["schemas"]["ArchModule"][];
+ /** Nodes */
+ nodes: components["schemas"]["ArchNode"][];
+ /** Relationshipsnapshotid */
+ relationshipSnapshotId?: string | null;
+ /** Repositoryid */
+ repositoryId: string;
+ /** Repositoryname */
+ repositoryName: string;
+ /** Requestflow */
+ requestFlow: components["schemas"]["RequestFlowStep"][];
+ summary: components["schemas"]["ArchitectureSummary"];
+ };
+ /** ArchitectureSummary */
+ ArchitectureSummary: {
+ /** Architecturepattern */
+ architecturePattern: string;
+ /** Entrypoint */
+ entryPoint: string;
+ /** Framework */
+ framework: string;
+ /** Language */
+ language: string;
+ /** Totalmodules */
+ totalModules: number;
+ /** Totalnodes */
+ totalNodes: number;
+ };
+ /** ArchLayer */
+ ArchLayer: {
+ /** Id */
+ id: string;
+ /** Name */
+ name: string;
+ /** Nodes */
+ nodes: string[];
+ /** Order */
+ order: number;
+ };
+ /** ArchModule */
+ ArchModule: {
+ /** Description */
+ description: string;
+ /** Filecount */
+ fileCount: number;
+ /** Id */
+ id: string;
+ /** Layer */
+ layer: string;
+ /** Name */
+ name: string;
+ /** Nodeids */
+ nodeIds: string[];
+ };
+ /** ArchNode */
+ ArchNode: {
+ /** Dependencies */
+ dependencies: string[];
+ /** Dependents */
+ dependents: string[];
+ /** Description */
+ description: string;
+ /**
+ * Estimatedcomplexity
+ * @enum {string}
+ */
+ estimatedComplexity: "low" | "medium" | "high" | "not_computed";
+ /** Estimatedlines */
+ estimatedLines: number | "not_computed";
+ /** Files */
+ files: string[];
+ /** Id */
+ id: string;
+ /** Layer */
+ layer: string;
+ /** Name */
+ name: string;
+ /** Parentmodule */
+ parentModule?: string | null;
+ /**
+ * Relationshipstate
+ * @default not-extracted
+ * @enum {string}
+ */
+ relationshipState: "connected" | "no-observed-relationships" | "unresolved" | "not-extracted";
+ /** Responsibilities */
+ responsibilities: string[];
+ /** Tags */
+ tags: string[];
+ /**
+ * Type
+ * @enum {string}
+ */
+ type: "frontend" | "backend" | "controller" | "route" | "service" | "repository" | "database" | "configuration" | "authentication" | "middleware" | "utilities" | "models" | "external-api" | "shared-library" | "environment" | "queue" | "cache";
+ };
+ /**
+ * AuthChain
+ * @description One ordered, evidence-backed path from a route to everything it reaches.
+ *
+ * ``hops`` is ordered route -> handler -> guard -> (service/model/dependency
+ * calls, in traversal order) so a consumer can render a single readable
+ * chain instead of reconstructing one from the flat ``relationships`` list.
+ */
+ AuthChain: {
+ /** Hops */
+ hops: components["schemas"]["AuthRelationship"][];
+ /** Route */
+ route: string;
+ };
+ /** AuthClaim */
+ AuthClaim: {
+ /**
+ * Confidence
+ * @enum {string}
+ */
+ confidence: "observed" | "heuristic";
+ /** Evidence */
+ evidence: components["schemas"]["AuthEvidenceRef"][];
+ /**
+ * Kind
+ * @enum {string}
+ */
+ kind: "route" | "middleware" | "service" | "model" | "dependency";
+ /** Name */
+ name: string;
+ };
+ /** AuthenticationDiagnostic */
+ AuthenticationDiagnostic: {
+ /** Category */
+ category: string;
+ /** Code */
+ code: string;
+ /** Endline */
+ endLine?: number | null;
+ /** Message */
+ message: string;
+ /** Path */
+ path?: string | null;
+ /**
+ * Severity
+ * @enum {string}
+ */
+ severity: "fatal" | "error" | "warning" | "info";
+ /** Startline */
+ startLine?: number | null;
+ };
+ /** AuthenticationExplanationResponse */
+ AuthenticationExplanationResponse: {
+ /** Chains */
+ chains?: components["schemas"]["AuthChain"][];
+ /** Claims */
+ claims?: components["schemas"]["AuthClaim"][];
+ /** Diagnostics */
+ diagnostics?: components["schemas"]["AuthenticationDiagnostic"][];
+ /** Relationships */
+ relationships?: components["schemas"]["AuthRelationship"][];
+ /** Repositoryid */
+ repositoryId: string;
+ /** Repositoryname */
+ repositoryName: string;
+ /** Revisionkind */
+ revisionKind: string | null;
+ /** Revisionvalue */
+ revisionValue: string | null;
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "auth-explanation.v1";
+ /** Snapshotid */
+ snapshotId: string | null;
+ /**
+ * Status
+ * @enum {string}
+ */
+ status: "ready" | "missing_snapshot";
+ /** Summary */
+ summary: string;
+ };
+ /** AuthEvidenceRef */
+ AuthEvidenceRef: {
+ /** Endline */
+ endLine: number;
+ /** Factid */
+ factId: string;
+ /** Path */
+ path: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Startline */
+ startLine: number;
+ };
+ /** AuthRelationship */
+ AuthRelationship: {
+ /** Evidence */
+ evidence: components["schemas"]["AuthEvidenceRef"][];
+ /** Object */
+ object: string;
+ /**
+ * Objectkind
+ * @enum {string}
+ */
+ objectKind: "route" | "handler" | "middleware" | "service" | "model" | "dependency";
+ /** Predicate */
+ predicate: string;
+ /** Subject */
+ subject: string;
+ /**
+ * Subjectkind
+ * @enum {string}
+ */
+ subjectKind: "route" | "handler" | "middleware" | "service" | "model" | "dependency";
+ };
+ /** AuthResponse */
+ AuthResponse: {
+ /** Accesstoken */
+ accessToken: string;
+ /**
+ * Tokentype
+ * @default bearer
+ * @constant
+ */
+ tokenType: "bearer";
+ user: components["schemas"]["UserResponse"];
+ };
+ /** Body_upload_repository_repositories_upload_post */
+ Body_upload_repository_repositories_upload_post: {
+ /** File */
+ file: string;
+ };
+ /** ChangeOverTimeAssessment */
+ ChangeOverTimeAssessment: {
+ /**
+ * Assessmentstate
+ * @default not_assessed
+ * @constant
+ */
+ assessmentState: "not_assessed";
+ /**
+ * Message
+ * @default Change-over-time insights are not available yet.
+ */
+ message: string;
+ };
+ /** DependencyAssessment */
+ DependencyAssessment: {
+ /**
+ * Status
+ * @constant
+ */
+ status: "not_computed";
+ };
+ /** DependencyDeclaration */
+ DependencyDeclaration: {
+ /** Ecosystem */
+ ecosystem: string;
+ /** Endline */
+ endLine: number;
+ /** Extractor */
+ extractor: string;
+ /** Extractorversion */
+ extractorVersion: string;
+ /** Manifestpath */
+ manifestPath: string;
+ /** Name */
+ name: string;
+ /** Startline */
+ startLine: number;
+ /**
+ * Type
+ * @enum {string}
+ */
+ type: "production" | "development" | "peer" | "optional";
+ /** Version */
+ version: string | null;
+ /** Workspacepath */
+ workspacePath: string;
+ };
+ /** DependencyDiagnostic */
+ DependencyDiagnostic: {
+ /** Category */
+ category: string;
+ /** Code */
+ code: string;
+ /** Details */
+ details?: {
+ [key: string]: unknown;
+ } | null;
+ /** Message */
+ message: string;
+ /** Path */
+ path?: string | null;
+ /** Producer */
+ producer: string;
+ /**
+ * Severity
+ * @enum {string}
+ */
+ severity: "fatal" | "error" | "warning" | "info";
+ };
+ /** DependencyEdge */
+ DependencyEdge: {
+ /** Id */
+ id: string;
+ /** Source */
+ source: string;
+ /** Target */
+ target: string;
+ /**
+ * Type
+ * @constant
+ */
+ type: "depends-on";
+ };
+ /** DependencyGraphResponse */
+ DependencyGraphResponse: {
+ /** Canonicalgraphhash */
+ canonicalGraphHash: string;
+ /** Diagnostics */
+ diagnostics?: components["schemas"]["DependencyDiagnostic"][];
+ /** Edges */
+ edges: components["schemas"]["DependencyEdge"][];
+ /**
+ * Generatedat
+ * Format: date-time
+ */
+ generatedAt: string;
+ /**
+ * Manifestcount
+ * @default 0
+ */
+ manifestCount: number;
+ /** Manifestdigest */
+ manifestDigest: string;
+ /** Nodes */
+ nodes: components["schemas"]["DependencyNode"][];
+ outdatedAssessment: components["schemas"]["DependencyAssessment"];
+ provenance: components["schemas"]["DependencyProvenance"];
+ /** Repositoryid */
+ repositoryId: string;
+ /** Repositoryname */
+ repositoryName: string;
+ /**
+ * Revisionkind
+ * @enum {string}
+ */
+ revisionKind: "git" | "upload";
+ /** Revisionvalue */
+ revisionValue: string;
+ /**
+ * Schemaversion
+ * @default dependency-graph.v2
+ * @constant
+ */
+ schemaVersion: "dependency-graph.v2";
+ /** Snapshotid */
+ snapshotId: string;
+ /** Snapshotschemaversion */
+ snapshotSchemaVersion: string;
+ /** Totaldependencies */
+ totalDependencies: number;
+ vulnerabilityAssessment: components["schemas"]["DependencyAssessment"];
+ };
+ /** DependencyNode */
+ DependencyNode: {
+ /** Declarations */
+ declarations: components["schemas"]["DependencyDeclaration"][];
+ /** Ecosystem */
+ ecosystem: string;
+ /** Id */
+ id: string;
+ /** Name */
+ name: string;
+ /**
+ * Type
+ * @enum {string}
+ */
+ type: "production" | "development" | "peer" | "optional" | "multiple";
+ /** Version */
+ version: string | null;
+ };
+ /** DependencyProvenance */
+ DependencyProvenance: {
+ /** Canonicalgraphhash */
+ canonicalGraphHash: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Snapshotschemaversion */
+ snapshotSchemaVersion: string;
+ /**
+ * Source
+ * @default ri.v1
+ * @constant
+ */
+ source: "ri.v1";
+ };
+ /** EngineeringReviewResponse */
+ EngineeringReviewResponse: {
+ /**
+ * Assessmentstatus
+ * @enum {string}
+ */
+ assessmentStatus: "assessed" | "partially_assessed" | "not_assessed" | "insufficient_evidence";
+ /** Canonicalgraphhash */
+ canonicalGraphHash: string;
+ /** Categories */
+ categories?: components["schemas"]["ReviewCategoryAssessment"][];
+ /** Findings */
+ findings?: components["schemas"]["ReviewFinding"][];
+ /**
+ * Generatedat
+ * Format: date-time
+ */
+ generatedAt: string;
+ /** Manifestdigest */
+ manifestDigest: string;
+ provenance: components["schemas"]["ReviewProvenance"];
+ /** Repositoryid */
+ repositoryId: string;
+ /** Repositoryname */
+ repositoryName: string;
+ /**
+ * Revisionkind
+ * @enum {string}
+ */
+ revisionKind: "git" | "upload";
+ /** Revisionvalue */
+ revisionValue: string;
+ /**
+ * Schemaversion
+ * @default engineering-review.v2
+ * @constant
+ */
+ schemaVersion: "engineering-review.v2";
+ /** Snapshotid */
+ snapshotId: string;
+ /** Snapshotschemaversion */
+ snapshotSchemaVersion: string;
+ summary: components["schemas"]["ReviewSummary"];
+ };
+ /** ErrorResponse */
+ ErrorResponse: {
+ /** Code */
+ code: string;
+ /** Details */
+ details?: {
+ [key: string]: unknown;
+ } | null;
+ /** Message */
+ message: string;
+ /** Request Id */
+ request_id?: string | null;
+ };
+ /**
+ * EvidenceSourceResponse
+ * @description The exact source text a citation points at, bound to its cited snapshot.
+ *
+ * ``status="unavailable"`` covers every case where the exact cited fact and
+ * revision cannot be honestly displayed (fact/span mismatch, source-hash
+ * mismatch, missing source, out-of-range span, binary content): ``content``
+ * is always ``None`` in that case rather than falling back to different
+ * content under a trusted-looking snapshot/revision identity.
+ */
+ EvidenceSourceResponse: {
+ /** Content */
+ content?: string | null;
+ /** Endline */
+ endLine: number;
+ /** Factid */
+ factId: string;
+ /** Path */
+ path: string;
+ /** Reason */
+ reason?: string | null;
+ /** Repositoryid */
+ repositoryId: string;
+ /** Revisionkind */
+ revisionKind: string | null;
+ /** Revisionvalue */
+ revisionValue: string | null;
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "evidence-source.v1";
+ /**
+ * Size
+ * @default 0
+ */
+ size: number;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Startline */
+ startLine: number;
+ /**
+ * Status
+ * @enum {string}
+ */
+ status: "ready" | "unavailable";
+ /**
+ * Truncated
+ * @default false
+ */
+ truncated: boolean;
+ };
+ /** ExportRequest */
+ ExportRequest: {
+ /**
+ * Format
+ * @enum {string}
+ */
+ format: "json" | "markdown" | "html" | "pdf";
+ /** Repositoryid */
+ repositoryId: string;
+ /**
+ * Target
+ * @enum {string}
+ */
+ target: "review" | "documentation" | "architecture" | "dependencies";
+ };
+ /** ExportResponse */
+ ExportResponse: {
+ /** Content */
+ content: string;
+ /**
+ * Encoding
+ * @enum {string}
+ */
+ encoding: "utf-8" | "base64";
+ /** Filename */
+ filename: string;
+ /** Mediatype */
+ mediaType: string;
+ };
+ /** FileTreeNode */
+ FileTreeNode: {
+ /** Children */
+ children?: components["schemas"]["FileTreeNode"][] | null;
+ /** Extension */
+ extension?: string | null;
+ /** Id */
+ id: string;
+ /** Language */
+ language?: string | null;
+ /** Name */
+ name: string;
+ /** Path */
+ path: string;
+ /** Size */
+ size?: number | null;
+ /**
+ * Type
+ * @enum {string}
+ */
+ type: "file" | "folder";
+ };
+ /** GenerateDocRequest */
+ GenerateDocRequest: {
+ /**
+ * Format
+ * @default markdown
+ * @enum {string}
+ */
+ format: "markdown" | "html";
+ /** Repositoryid */
+ repositoryId: string;
+ /** Sections */
+ sections?: string[] | null;
+ };
+ /** GenerateDocResponse */
+ GenerateDocResponse: {
+ /** Content */
+ content: string;
+ /**
+ * Format
+ * @enum {string}
+ */
+ format: "markdown" | "html";
+ /**
+ * Generatedat
+ * Format: date-time
+ */
+ generatedAt: string;
+ /**
+ * Revisionkind
+ * @enum {string}
+ */
+ revisionKind: "git" | "upload";
+ /** Revisionref */
+ revisionRef?: string | null;
+ /** Revisionvalue */
+ revisionValue: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /**
+ * Snapshotschemaversion
+ * @constant
+ */
+ snapshotSchemaVersion: "ri.v1";
+ /**
+ * Source
+ * @constant
+ */
+ source: "ri.v1";
+ };
+ /** GitHubImportRequest */
+ GitHubImportRequest: {
+ /** Branch */
+ branch?: string | null;
+ /**
+ * Url
+ * Format: uri
+ */
+ url: string;
+ };
+ /** HTTPValidationError */
+ HTTPValidationError: {
+ /** Detail */
+ detail?: components["schemas"]["ValidationError"][];
+ };
+ /** InsightBreakdown */
+ InsightBreakdown: {
+ /** Key */
+ key: string;
+ /** Label */
+ label: string;
+ /** Value */
+ value: number;
+ };
+ /** InsightExtractor */
+ InsightExtractor: {
+ /** Evidencerecordcount */
+ evidenceRecordCount: number;
+ /** Name */
+ name: string;
+ /** Version */
+ version: string;
+ };
+ /** InsightMetric */
+ InsightMetric: {
+ /**
+ * Assessmentstate
+ * @enum {string}
+ */
+ assessmentState: "assessed" | "not_assessed" | "insufficient_evidence";
+ /** Definition */
+ definition: string;
+ /** Denominator */
+ denominator?: number | null;
+ /** Id */
+ id: string;
+ /** Label */
+ label: string;
+ /** Numerator */
+ numerator?: number | null;
+ provenance: components["schemas"]["InsightProvenance"];
+ /** Snapshotid */
+ snapshotId: string;
+ /** Unit */
+ unit: string;
+ /** Value */
+ value: number | string | null;
+ };
+ /** InsightProvenance */
+ InsightProvenance: {
+ /** Canonicalgraphhash */
+ canonicalGraphHash: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Snapshotschemaversion */
+ snapshotSchemaVersion: string;
+ /**
+ * Source
+ * @default ri.v1
+ * @constant
+ */
+ source: "ri.v1";
+ };
+ /** LoginRequest */
+ LoginRequest: {
+ /**
+ * Email
+ * Format: email
+ */
+ email: string;
+ /** Password */
+ password: string;
+ };
+ /**
+ * ManifestExtractor
+ * @description One producer that contributed facts to the snapshot.
+ */
+ ManifestExtractor: {
+ /** Name */
+ name: string;
+ /** Version */
+ version: string;
+ };
+ /** RegisterRequest */
+ RegisterRequest: {
+ /**
+ * Email
+ * Format: email
+ */
+ email: string;
+ /** Password */
+ password: string;
+ };
+ /** RepositoryFileResponse */
+ RepositoryFileResponse: {
+ /** Content */
+ content: string;
+ /**
+ * Isbinary
+ * @default false
+ */
+ isBinary: boolean;
+ /**
+ * Isimage
+ * @default false
+ */
+ isImage: boolean;
+ /** Mediatype */
+ mediaType?: string | null;
+ /** Path */
+ path: string;
+ /** Size */
+ size: number;
+ /**
+ * Truncated
+ * @default false
+ */
+ truncated: boolean;
+ };
+ /** RepositoryInsightsResponse */
+ RepositoryInsightsResponse: {
+ /** Canonicalgraphhash */
+ canonicalGraphHash: string;
+ changeOverTime?: components["schemas"]["ChangeOverTimeAssessment"];
+ /**
+ * Computedat
+ * Format: date-time
+ */
+ computedAt: string;
+ /** Diagnosticsbycode */
+ diagnosticsByCode?: components["schemas"]["InsightBreakdown"][];
+ /** Diagnosticsbyseverity */
+ diagnosticsBySeverity?: components["schemas"]["InsightBreakdown"][];
+ /** Extractorset */
+ extractorSet?: components["schemas"]["InsightExtractor"][];
+ /** Languages */
+ languages?: components["schemas"]["InsightBreakdown"][];
+ /** Manifestdigest */
+ manifestDigest: string;
+ /** Metrics */
+ metrics?: components["schemas"]["InsightMetric"][];
+ provenance: components["schemas"]["InsightProvenance"];
+ /** Relationshipsbypredicate */
+ relationshipsByPredicate?: components["schemas"]["InsightBreakdown"][];
+ /** Repositoryid */
+ repositoryId: string;
+ /** Repositoryname */
+ repositoryName: string;
+ /**
+ * Revisionkind
+ * @enum {string}
+ */
+ revisionKind: "git" | "upload";
+ /** Revisionvalue */
+ revisionValue: string;
+ /**
+ * Schemaversion
+ * @default repository-insights.v1
+ * @constant
+ */
+ schemaVersion: "repository-insights.v1";
+ /**
+ * Snapshotcreatedat
+ * Format: date-time
+ */
+ snapshotCreatedAt: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Snapshotschemaversion */
+ snapshotSchemaVersion: string;
+ /**
+ * Snapshotsealedat
+ * Format: date-time
+ */
+ snapshotSealedAt: string;
+ };
+ /** RepositoryListResponse */
+ RepositoryListResponse: {
+ /** Data */
+ data: components["schemas"]["RepositoryResponse"][];
+ /** Total */
+ total: number;
+ };
+ /** RepositoryMeta */
+ RepositoryMeta: {
+ /** Configfiles */
+ configFiles: string[];
+ /** Entrypoint */
+ entryPoint: string | null;
+ /** Framework */
+ framework: string;
+ /** Haslicense */
+ hasLicense: boolean;
+ /** Hasreadme */
+ hasReadme: boolean;
+ /** Language */
+ language: string;
+ /** Licensename */
+ licenseName: string | null;
+ /** Packagemanager */
+ packageManager: string | null;
+ /** Totalfiles */
+ totalFiles: number;
+ /** Totalfolders */
+ totalFolders: number;
+ };
+ /** RepositoryResponse */
+ RepositoryResponse: {
+ /** Analysedat */
+ analysedAt?: string | null;
+ /** Analysisprogress */
+ analysisProgress: number;
+ /** Analysisstage */
+ analysisStage?: ("uploading" | "extracting" | "reading-structure" | "detecting-languages" | "detecting-framework" | "building-file-tree" | "extracting-modules" | "building-dependency-graph" | "preparing-architecture" | "completed") | null;
+ /** Branch */
+ branch?: string | null;
+ /** Commitsha */
+ commitSha?: string | null;
+ /** Description */
+ description?: string | null;
+ /** Errormessage */
+ errorMessage?: string | null;
+ /** Filecount */
+ fileCount: number;
+ /** Filetree */
+ fileTree?: components["schemas"]["FileTreeNode"][];
+ /** Id */
+ id: string;
+ meta?: components["schemas"]["RepositoryMeta"] | null;
+ /** Name */
+ name: string;
+ revision?: components["schemas"]["RepositoryRevision"] | null;
+ /** Size */
+ size: number;
+ /**
+ * Source
+ * @enum {string}
+ */
+ source: "upload" | "github";
+ /** Sourceurl */
+ sourceUrl?: string | null;
+ /**
+ * Status
+ * @enum {string}
+ */
+ status: "uploading" | "analysing" | "completed" | "cancelled" | "error";
+ /**
+ * Uploadedat
+ * Format: date-time
+ */
+ uploadedAt: string;
+ };
+ /**
+ * RepositoryRevision
+ * @description First-class repository revision identity (#87, RFC §3.2).
+ *
+ * ``value`` is the immutable identity: a 40-char lowercase git commit SHA for
+ * GitHub imports, or a ``sha256:`` archive content hash for uploads.
+ * ``ref`` (e.g. ``refs/heads/main``) is a moving pointer — descriptive
+ * metadata only, never identity, and always ``null`` for uploads.
+ */
+ RepositoryRevision: {
+ /**
+ * Kind
+ * @enum {string}
+ */
+ kind: "git" | "upload";
+ /** Ref */
+ ref?: string | null;
+ /** Value */
+ value: string;
+ };
+ /** RequestFlowStep */
+ RequestFlowStep: {
+ /** Description */
+ description: string;
+ /** Details */
+ details: string[];
+ /** Id */
+ id: string;
+ /** Name */
+ name: string;
+ /**
+ * Type
+ * @enum {string}
+ */
+ type: "frontend" | "backend" | "controller" | "route" | "service" | "repository" | "database" | "configuration" | "authentication" | "middleware" | "utilities" | "models" | "external-api" | "shared-library" | "environment" | "queue" | "cache";
+ };
+ /** ReviewCategoryAssessment */
+ ReviewCategoryAssessment: {
+ /** Explanation */
+ explanation: string;
+ /**
+ * Findingcount
+ * @default 0
+ */
+ findingCount: number;
+ /**
+ * Id
+ * @enum {string}
+ */
+ id: "architecture_boundaries" | "relationship_resolution" | "source_extraction" | "dependency_declarations" | "security_vulnerability_scanning" | "authentication_evidence" | "repository_structure" | "analysis_integrity";
+ /** Label */
+ label: string;
+ /**
+ * State
+ * @enum {string}
+ */
+ state: "assessed" | "partially_assessed" | "not_assessed" | "insufficient_evidence";
+ };
+ /** ReviewEvidenceReference */
+ ReviewEvidenceReference: {
+ /** Endline */
+ endLine: number;
+ /** Evidenceid */
+ evidenceId: string;
+ /** Extractorname */
+ extractorName: string;
+ /** Extractorversion */
+ extractorVersion: string;
+ /** Factid */
+ factId: string;
+ /** Path */
+ path: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Startline */
+ startLine: number;
+ };
+ /** ReviewFinding */
+ ReviewFinding: {
+ /**
+ * Category
+ * @enum {string}
+ */
+ category: "architecture_boundaries" | "relationship_resolution" | "source_extraction" | "dependency_declarations" | "security_vulnerability_scanning" | "authentication_evidence" | "repository_structure" | "analysis_integrity";
+ /** Diagnosticcode */
+ diagnosticCode: string;
+ /** Endline */
+ endLine: number;
+ evidence: components["schemas"]["ReviewEvidenceReference"];
+ /** Evidenceid */
+ evidenceId: string;
+ /** Explanation */
+ explanation: string;
+ /** Extractorname */
+ extractorName: string;
+ /** Extractorversion */
+ extractorVersion: string;
+ /** Factid */
+ factId: string;
+ /** Id */
+ id: string;
+ /** Path */
+ path: string;
+ provenance: components["schemas"]["ReviewProvenance"];
+ /** Remediationguidance */
+ remediationGuidance: string;
+ /** Ruleid */
+ ruleId: string;
+ /**
+ * Severity
+ * @enum {string}
+ */
+ severity: "info" | "low" | "medium" | "high" | "critical";
+ /** Snapshotid */
+ snapshotId: string;
+ /** Startline */
+ startLine: number;
+ /**
+ * Supportstatus
+ * @default supported
+ * @enum {string}
+ */
+ supportStatus: "supported" | "file_scoped";
+ /** Title */
+ title: string;
+ };
+ /** ReviewProvenance */
+ ReviewProvenance: {
+ /** Canonicalgraphhash */
+ canonicalGraphHash: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Snapshotschemaversion */
+ snapshotSchemaVersion: string;
+ /**
+ * Source
+ * @default ri.v1
+ * @constant
+ */
+ source: "ri.v1";
+ };
+ /** ReviewSeverityCounts */
+ ReviewSeverityCounts: {
+ /**
+ * Critical
+ * @default 0
+ */
+ critical: number;
+ /**
+ * High
+ * @default 0
+ */
+ high: number;
+ /**
+ * Info
+ * @default 0
+ */
+ info: number;
+ /**
+ * Low
+ * @default 0
+ */
+ low: number;
+ /**
+ * Medium
+ * @default 0
+ */
+ medium: number;
+ };
+ /** ReviewSummary */
+ ReviewSummary: {
+ /** Assessedcategories */
+ assessedCategories: number;
+ /** Evidencebackedfindingcount */
+ evidenceBackedFindingCount: number;
+ /**
+ * Filescopedfindingcount
+ * @default 0
+ */
+ fileScopedFindingCount: number;
+ findingsBySeverity: components["schemas"]["ReviewSeverityCounts"];
+ /** Insufficientevidencecategories */
+ insufficientEvidenceCategories: number;
+ /** Message */
+ message: string;
+ /** Notassessedcategories */
+ notAssessedCategories: number;
+ /**
+ * Omittedunsupporteddiagnosticcount
+ * @default 0
+ */
+ omittedUnsupportedDiagnosticCount: number;
+ /** Partiallyassessedcategories */
+ partiallyAssessedCategories: number;
+ /**
+ * Vulnerabilityscanning
+ * @default not_assessed
+ * @constant
+ */
+ vulnerabilityScanning: "not_assessed";
+ };
+ /**
+ * RevisionManifest
+ * @description The manifest body. Every field is copied from the sealed snapshot.
+ *
+ * This model is what gets hashed into ``manifestDigest``; the digest is
+ * therefore a function of exactly these fields, in canonical JSON form.
+ */
+ RevisionManifest: {
+ /** Canonicalgraphhash */
+ canonicalGraphHash: string | null;
+ /** Confighash */
+ configHash: string;
+ /**
+ * Createdat
+ * Format: date-time
+ */
+ createdAt: string;
+ /** Extractors */
+ extractors: components["schemas"]["ManifestExtractor"][];
+ /** Producersethash */
+ producerSetHash: string;
+ /** Repositoryid */
+ repositoryId: string;
+ /**
+ * Revisionkind
+ * @enum {string}
+ */
+ revisionKind: "git" | "upload";
+ /** Revisionref */
+ revisionRef?: string | null;
+ /** Revisionvalue */
+ revisionValue: string;
+ /**
+ * Schemaversion
+ * @default revision-manifest.v1
+ * @constant
+ */
+ schemaVersion: "revision-manifest.v1";
+ /** Sealedat */
+ sealedAt: string | null;
+ /** Snapshotid */
+ snapshotId: string;
+ /** Snapshotschemaversion */
+ snapshotSchemaVersion: string;
+ };
+ /** RevisionManifestResponse */
+ RevisionManifestResponse: {
+ manifest: components["schemas"]["RevisionManifest"];
+ /** Manifestdigest */
+ manifestDigest: string;
+ /**
+ * Verificationmethod
+ * @default sha256-canonical-json
+ */
+ verificationMethod: string;
+ /** Verificationnote */
+ verificationNote: string;
+ /**
+ * Verificationstate
+ * @enum {string}
+ */
+ verificationState: "verified" | "superseded" | "mismatch" | "unverifiable";
+ };
+ /**
+ * RevisionManifestVerificationRequest
+ * @description A manifest a user previously exported, submitted for re-checking.
+ */
+ RevisionManifestVerificationRequest: {
+ manifest: components["schemas"]["RevisionManifest"];
+ /** Manifestdigest */
+ manifestDigest: string;
+ };
+ /** RevisionManifestVerificationResponse */
+ RevisionManifestVerificationResponse: {
+ /** Detail */
+ detail: string;
+ /** Matchesstoredsnapshot */
+ matchesStoredSnapshot: boolean;
+ /** Mismatchedfields */
+ mismatchedFields: string[];
+ /**
+ * Verificationmethod
+ * @default sha256-canonical-json
+ */
+ verificationMethod: string;
+ /**
+ * Verificationstate
+ * @enum {string}
+ */
+ verificationState: "verified" | "superseded" | "mismatch" | "unverifiable";
+ };
+ /** RiAssertionResponse */
+ RiAssertionResponse: {
+ /** Assertionid */
+ assertionId: string;
+ /** Derivedfrom */
+ derivedFrom?: {
+ [key: string]: string;
+ }[];
+ /** Predicate */
+ predicate: string;
+ /** Producer */
+ producer: string;
+ /** Producerversion */
+ producerVersion: string;
+ /** Subjectkey */
+ subjectKey: string;
+ /** Subjectkind */
+ subjectKind: string;
+ /**
+ * Truthclass
+ * @constant
+ */
+ truthClass: "inferred";
+ /** Value */
+ value: {
+ [key: string]: unknown;
+ };
+ };
+ /** RiAssertionsResponse */
+ RiAssertionsResponse: {
+ /** Data */
+ data: components["schemas"]["RiAssertionResponse"][];
+ pagination: components["schemas"]["RiPagination"];
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ };
+ /** RiEdgeResponse */
+ RiEdgeResponse: {
+ /** Derivedfrom */
+ derivedFrom?: {
+ [key: string]: string;
+ }[];
+ /** Edgeid */
+ edgeId: string;
+ /** Evidence */
+ evidence?: components["schemas"]["RiEvidenceResponse"][];
+ /** Objectkey */
+ objectKey: string;
+ /** Objectkind */
+ objectKind: string;
+ /** Predicate */
+ predicate: string;
+ /** Producer */
+ producer: string;
+ /** Producerversion */
+ producerVersion: string;
+ /** Subjectkey */
+ subjectKey: string;
+ /** Subjectkind */
+ subjectKind: string;
+ /**
+ * Truthclass
+ * @constant
+ */
+ truthClass: "resolved";
+ };
+ /** RiEvidenceResponse */
+ RiEvidenceResponse: {
+ /** Endline */
+ endLine: number;
+ /** Extractor */
+ extractor: string;
+ /** Extractorversion */
+ extractorVersion: string;
+ /** Factid */
+ factId: string;
+ /**
+ * Factkind
+ * @enum {string}
+ */
+ factKind: "node" | "edge" | "observation";
+ /**
+ * Granularity
+ * @enum {string}
+ */
+ granularity: "span" | "file";
+ /** Path */
+ path: string;
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ /** Startline */
+ startLine: number;
+ };
+ /** RiEvidenceResponsePage */
+ RiEvidenceResponsePage: {
+ /** Data */
+ data: components["schemas"]["RiEvidenceResponse"][];
+ pagination: components["schemas"]["RiPagination"];
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ };
+ /**
+ * RiImpactDirectionResponse
+ * @description One bounded traversal direction.
+ *
+ * ``limit_reached`` means the response omitted further reachable nodes at the
+ * requested depth rather than claiming that the listed nodes are exhaustive.
+ */
+ RiImpactDirectionResponse: {
+ /** Data */
+ data: components["schemas"]["RiImpactStepResponse"][];
+ /** Limitreached */
+ limitReached: boolean;
+ };
+ /** RiImpactResponse */
+ RiImpactResponse: {
+ dependencies: components["schemas"]["RiImpactDirectionResponse"];
+ dependents: components["schemas"]["RiImpactDirectionResponse"];
+ /** Depth */
+ depth: number;
+ /** Nodekey */
+ nodeKey: string;
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ };
+ /**
+ * RiImpactStepResponse
+ * @description A reached node and the stored edge that proves the traversal hop.
+ */
+ RiImpactStepResponse: {
+ /** Depth */
+ depth: number;
+ /** Nodekey */
+ nodeKey: string;
+ via: components["schemas"]["RiEdgeResponse"];
+ };
+ /** RiNeighboursResponse */
+ RiNeighboursResponse: {
+ /** Data */
+ data: components["schemas"]["RiEdgeResponse"][];
+ /** Nodekey */
+ nodeKey: string;
+ pagination: components["schemas"]["RiPagination"];
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ };
+ /** RiNodeResponse */
+ RiNodeResponse: {
+ /** Evidence */
+ evidence?: components["schemas"]["RiEvidenceResponse"][];
+ /** Language */
+ language?: string | null;
+ /** Name */
+ name?: string | null;
+ /** Nodekind */
+ nodeKind: string;
+ /** Properties */
+ properties?: {
+ [key: string]: unknown;
+ } | null;
+ /** Stablekey */
+ stableKey: string;
+ /**
+ * Truthclass
+ * @constant
+ */
+ truthClass: "observed";
+ };
+ /** RiPagination */
+ RiPagination: {
+ /** Limit */
+ limit: number;
+ /** Offset */
+ offset: number;
+ /** Total */
+ total: number;
+ };
+ /** RiPathResponse */
+ RiPathResponse: {
+ node: components["schemas"]["RiNodeResponse"];
+ /** Path */
+ path: string;
+ };
+ /** RiPathsResponse */
+ RiPathsResponse: {
+ /** Data */
+ data: components["schemas"]["RiPathResponse"][];
+ pagination: components["schemas"]["RiPagination"];
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ };
+ /** RiReferencesResponse */
+ RiReferencesResponse: {
+ /** Data */
+ data: components["schemas"]["RiEdgeResponse"][];
+ pagination: components["schemas"]["RiPagination"];
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ };
+ /** RiSnapshotMetadataResponse */
+ RiSnapshotMetadataResponse: {
+ /** Canonicalgraphhash */
+ canonicalGraphHash: string;
+ /** Confighash */
+ configHash: string;
+ /**
+ * Createdat
+ * Format: date-time
+ */
+ createdAt: string;
+ /** Producersethash */
+ producerSetHash: string;
+ /** Producerversionset */
+ producerVersionSet: string[];
+ /** Repositoryid */
+ repositoryId: string;
+ /**
+ * Revisionkind
+ * @enum {string}
+ */
+ revisionKind: "git" | "upload";
+ /** Revisionref */
+ revisionRef?: string | null;
+ /** Revisionvalue */
+ revisionValue: string;
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ /**
+ * Sealedat
+ * Format: date-time
+ */
+ sealedAt: string;
+ /** Snapshotid */
+ snapshotId: string;
+ /**
+ * State
+ * @constant
+ */
+ state: "completed";
+ /**
+ * Updatedat
+ * Format: date-time
+ */
+ updatedAt: string;
+ };
+ /** RiSymbolsResponse */
+ RiSymbolsResponse: {
+ /** Data */
+ data: components["schemas"]["RiNodeResponse"][];
+ pagination: components["schemas"]["RiPagination"];
+ /**
+ * Schemaversion
+ * @constant
+ */
+ schemaVersion: "ri.v1";
+ };
+ /** UserResponse */
+ UserResponse: {
+ /**
+ * Createdat
+ * Format: date-time
+ */
+ createdAt: string;
+ /** Email */
+ email: string;
+ /** Id */
+ id: string;
+ };
+ /** ValidationError */
+ ValidationError: {
+ /** Context */
+ ctx?: Record;
+ /** Input */
+ input?: unknown;
+ /** Location */
+ loc: (string | number)[];
+ /** Message */
+ msg: string;
+ /** Error Type */
+ type: string;
+ };
+ };
+ responses: never;
+ parameters: never;
+ requestBodies: never;
+ headers: never;
+ pathItems: never;
+}
+export type $defs = Record;
+export interface operations {
+ get_ai_config_ai_config_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Saved provider configuration without the full API key. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "provider": "openai",
+ * "model": "gpt-4.1-mini",
+ * "hasApiKey": true,
+ * "apiKeyLast4": "1234"
+ * }
+ */
+ "application/json": components["schemas"]["AiProviderPublicConfig"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ save_ai_config_ai_config_put: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["AiProviderConfig"];
+ };
+ };
+ responses: {
+ /** @description Provider configuration saved without returning the full API key. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "provider": "openai",
+ * "model": "gpt-4.1-mini",
+ * "hasApiKey": true,
+ * "apiKeyLast4": "1234"
+ * }
+ */
+ "application/json": components["schemas"]["AiProviderPublicConfig"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ query_ai_ai_query_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["AiQueryRequest"];
+ };
+ };
+ responses: {
+ /** @description Repository-aware AI response. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "message": {
+ * "role": "assistant",
+ * "content": "Authentication is handled by the auth module.",
+ * "timestamp": "2026-07-17T00:00:00Z",
+ * "citations": []
+ * },
+ * "suggestions": []
+ * }
+ */
+ "application/json": components["schemas"]["AiQueryResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An upstream service could not complete the request. */
+ 502: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "external_service_error",
+ * "message": "AI provider request failed.",
+ * "details": {
+ * "provider": "openai"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ test_ai_config_ai_test_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["AiProviderTestRequest"];
+ };
+ };
+ responses: {
+ /** @description Provider connectivity result. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "ok": true,
+ * "message": "Provider connection succeeded.",
+ * "checkedAt": "2026-07-17T00:00:00Z"
+ * }
+ */
+ "application/json": components["schemas"]["AiProviderTestResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An upstream service could not complete the request. */
+ 502: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "external_service_error",
+ * "message": "AI provider request failed.",
+ * "details": {
+ * "provider": "openai"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_architecture_analysis__repository_id__architecture_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Architecture model derived from the sealed repository-intelligence snapshot bound to the repository's current revision. A repository with no sealed snapshot yet returns 404, never a fallback graph (#217). */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "repositoryName": "example-service",
+ * "architectureType": "Layered application",
+ * "detectedLayers": [],
+ * "nodes": [],
+ * "edges": [],
+ * "modules": [],
+ * "requestFlow": [],
+ * "relationshipSnapshotId": "snap_example",
+ * "diagnostics": [],
+ * "summary": {
+ * "language": "Python",
+ * "framework": "FastAPI",
+ * "totalModules": 0,
+ * "totalNodes": 0,
+ * "entryPoint": "/app/main.py",
+ * "architecturePattern": "Layered application"
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["ArchitectureResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_authentication_explanation_analysis__repository_id__architecture_authentication_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Evidence-backed explanation of how authentication works, read exclusively from the sealed Repository Intelligence snapshot query layer. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "auth-explanation.v1",
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "repositoryName": "example-service",
+ * "revisionKind": "upload",
+ * "revisionValue": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
+ * "snapshotId": "snap_example",
+ * "status": "ready",
+ * "summary": "Found 1 authentication-relevant route(s), 1 middleware/guard dependency(ies), 1 service(s), and 1 model(s), each backed by a citation to its exact stored source span.",
+ * "claims": [
+ * {
+ * "kind": "route",
+ * "name": "/me",
+ * "confidence": "observed",
+ * "evidence": [
+ * {
+ * "snapshotId": "snap_example",
+ * "factId": "src/routes.py::(anonymous:route#1)",
+ * "path": "src/routes.py",
+ * "startLine": 10,
+ * "endLine": 10
+ * }
+ * ]
+ * }
+ * ],
+ * "relationships": [],
+ * "diagnostics": []
+ * }
+ */
+ "application/json": components["schemas"]["AuthenticationExplanationResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ cancel_analysis_analysis__repository_id__cancel_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Analysis cancellation was accepted; a running job is cancelled cooperatively. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "status": "cancelled",
+ * "jobId": "22222222-2222-2222-2222-222222222222",
+ * "progress": 0,
+ * "completedAt": "2026-07-17T00:00:01Z"
+ * }
+ */
+ "application/json": components["schemas"]["AnalysisStatusResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request conflicts with existing state. */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "conflict_error",
+ * "message": "Repository has already been imported.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_dependencies_analysis__repository_id__dependencies_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Dependency inventory and resolved depends_on relationships from the selected sealed ri.v1 snapshot. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "dependency-graph.v2",
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "repositoryName": "example-service",
+ * "revisionKind": "upload",
+ * "revisionValue": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
+ * "snapshotId": "snap_example",
+ * "snapshotSchemaVersion": "ri.v1",
+ * "canonicalGraphHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
+ * "manifestDigest": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
+ * "provenance": {
+ * "source": "ri.v1",
+ * "snapshotId": "snap_example",
+ * "snapshotSchemaVersion": "ri.v1",
+ * "canonicalGraphHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111"
+ * },
+ * "generatedAt": "2026-07-17T00:00:00Z",
+ * "nodes": [
+ * {
+ * "id": "dep:npm:react",
+ * "name": "react",
+ * "version": "^18.3.0",
+ * "type": "production",
+ * "ecosystem": "npm",
+ * "declarations": [
+ * {
+ * "name": "react",
+ * "manifestPath": "apps/frontend/package.json",
+ * "workspacePath": "apps/frontend",
+ * "startLine": 3,
+ * "endLine": 3,
+ * "extractor": "dependency-manifest",
+ * "extractorVersion": "1.2.0",
+ * "ecosystem": "npm",
+ * "version": "^18.3.0",
+ * "type": "production"
+ * }
+ * ]
+ * }
+ * ],
+ * "edges": [
+ * {
+ * "id": "edge_example",
+ * "source": "repo:root",
+ * "target": "dep:npm:react",
+ * "type": "depends-on"
+ * }
+ * ],
+ * "totalDependencies": 1,
+ * "manifestCount": 1,
+ * "diagnostics": [],
+ * "vulnerabilityAssessment": {
+ * "status": "not_computed"
+ * },
+ * "outdatedAssessment": {
+ * "status": "not_computed"
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["DependencyGraphResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_evidence_source_analysis__repository_id__evidence_get: {
+ parameters: {
+ query: {
+ endLine: number;
+ factId: string;
+ path: string;
+ snapshotId: string;
+ startLine: number;
+ };
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Source text for one evidence citation, verified against the exact snapshot revision it was cited from. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "evidence-source.v1",
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "snapshotId": "snap_example",
+ * "factId": "src/routes.py::(anonymous:route#1)",
+ * "revisionKind": "upload",
+ * "revisionValue": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
+ * "path": "src/routes.py",
+ * "startLine": 10,
+ * "endLine": 10,
+ * "status": "ready",
+ * "content": "@app.get(\"/me\")\n",
+ * "truncated": false,
+ * "size": 16
+ * }
+ */
+ "application/json": components["schemas"]["EvidenceSourceResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_insights_analysis__repository_id__insights_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Defined repository metrics computed only from the selected sealed ri.v1 snapshot. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "repository-insights.v1",
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "repositoryName": "example-service",
+ * "revisionKind": "upload",
+ * "revisionValue": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
+ * "snapshotId": "snap_example",
+ * "snapshotSchemaVersion": "ri.v1",
+ * "canonicalGraphHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
+ * "manifestDigest": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
+ * "provenance": {
+ * "source": "ri.v1",
+ * "snapshotId": "snap_example",
+ * "snapshotSchemaVersion": "ri.v1",
+ * "canonicalGraphHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111"
+ * },
+ * "computedAt": "2026-07-17T00:00:00Z",
+ * "snapshotCreatedAt": "2026-07-17T00:00:00Z",
+ * "snapshotSealedAt": "2026-07-17T00:00:00Z",
+ * "extractorSet": [],
+ * "metrics": [],
+ * "relationshipsByPredicate": [],
+ * "diagnosticsBySeverity": [],
+ * "diagnosticsByCode": [],
+ * "languages": [],
+ * "changeOverTime": {
+ * "assessmentState": "not_assessed",
+ * "message": "Change-over-time insights are not available yet."
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["RepositoryInsightsResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_review_analysis__repository_id__review_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Deterministic evidence-backed findings for the selected sealed ri.v1 snapshot. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "engineering-review.v2",
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "repositoryName": "example-service",
+ * "revisionKind": "upload",
+ * "revisionValue": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
+ * "snapshotId": "snap_example",
+ * "snapshotSchemaVersion": "ri.v1",
+ * "canonicalGraphHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
+ * "manifestDigest": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
+ * "provenance": {
+ * "source": "ri.v1",
+ * "snapshotId": "snap_example",
+ * "snapshotSchemaVersion": "ri.v1",
+ * "canonicalGraphHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111"
+ * },
+ * "generatedAt": "2026-07-17T00:00:00Z",
+ * "assessmentStatus": "partially_assessed",
+ * "categories": [],
+ * "findings": [],
+ * "summary": {
+ * "message": "0 evidence-backed findings were identified in this revision. Security vulnerability scanning was not performed.",
+ * "findingsBySeverity": {
+ * "info": 0,
+ * "low": 0,
+ * "medium": 0,
+ * "high": 0,
+ * "critical": 0
+ * },
+ * "assessedCategories": 2,
+ * "partiallyAssessedCategories": 4,
+ * "notAssessedCategories": 0,
+ * "insufficientEvidenceCategories": 1,
+ * "evidenceBackedFindingCount": 0,
+ * "fileScopedFindingCount": 0,
+ * "omittedUnsupportedDiagnosticCount": 0,
+ * "vulnerabilityScanning": "not_assessed"
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["EngineeringReviewResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_revision_manifest_analysis__repository_id__revision_manifest_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Verifiable identity of the sealed snapshot backing this repository's evidence: revision, snapshot, extractor versions and canonical digest. The digest is a canonical content hash, not a digital signature. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "manifest": {
+ * "schemaVersion": "revision-manifest.v1",
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "revisionKind": "upload",
+ * "revisionValue": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
+ * "snapshotId": "snap_example",
+ * "snapshotSchemaVersion": "ri.v1",
+ * "extractors": [
+ * {
+ * "name": "typescript-extractor",
+ * "version": "1.0.0"
+ * },
+ * {
+ * "name": "relationship-resolver",
+ * "version": "1.0.0"
+ * }
+ * ],
+ * "producerSetHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
+ * "configHash": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
+ * "canonicalGraphHash": "sha256:3333333333333333333333333333333333333333333333333333333333333333",
+ * "createdAt": "2026-07-25T00:00:00Z",
+ * "sealedAt": "2026-07-25T00:00:05Z"
+ * },
+ * "manifestDigest": "sha256:4444444444444444444444444444444444444444444444444444444444444444",
+ * "verificationMethod": "sha256-canonical-json",
+ * "verificationState": "verified",
+ * "verificationNote": "This digest is a SHA-256 over the canonical JSON encoding of the manifest fields above. It is a content hash, not a digital signature."
+ * }
+ */
+ "application/json": components["schemas"]["RevisionManifestResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ verify_revision_manifest_analysis__repository_id__revision_manifest_verify_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["RevisionManifestVerificationRequest"];
+ };
+ };
+ responses: {
+ /** @description Re-check a previously exported manifest against the stored snapshot. Reports a mismatch when the supplied digest does not match the supplied manifest, or when the manifest does not match stored facts. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "verificationState": "verified",
+ * "verificationMethod": "sha256-canonical-json",
+ * "matchesStoredSnapshot": true,
+ * "mismatchedFields": [],
+ * "detail": "The manifest matches the sealed snapshot stored for this repository."
+ * }
+ */
+ "application/json": components["schemas"]["RevisionManifestVerificationResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ start_analysis_analysis__repository_id__start_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Analysis was durably enqueued (or already complete); the request never blocks on the worker. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "status": "queued",
+ * "jobId": "22222222-2222-2222-2222-222222222222"
+ * }
+ */
+ "application/json": components["schemas"]["AnalysisStartResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_analysis_status_analysis__repository_id__status_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Current durable analysis-job status. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111",
+ * "status": "completed",
+ * "jobId": "22222222-2222-2222-2222-222222222222",
+ * "stage": "completed",
+ * "progress": 100,
+ * "startedAt": "2026-07-17T00:00:00Z",
+ * "completedAt": "2026-07-17T00:00:02Z"
+ * }
+ */
+ "application/json": components["schemas"]["AnalysisStatusResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ login_auth_login_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["LoginRequest"];
+ };
+ };
+ responses: {
+ /** @description Authenticated session with an access token and refresh cookie. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "accessToken": "example-access-token",
+ * "tokenType": "bearer",
+ * "user": {
+ * "id": "11111111-1111-1111-1111-111111111111",
+ * "email": "developer@example.com",
+ * "createdAt": "2026-07-17T00:00:00Z"
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["AuthResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ logout_auth_logout_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: {
+ partha_refresh?: string | null;
+ };
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Successful Response */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ me_auth_me_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description The authenticated user. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "id": "11111111-1111-1111-1111-111111111111",
+ * "email": "developer@example.com",
+ * "createdAt": "2026-07-17T00:00:00Z"
+ * }
+ */
+ "application/json": components["schemas"]["UserResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ refresh_auth_refresh_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: {
+ partha_refresh?: string | null;
+ };
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Access token renewed and the refresh token rotated. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "accessToken": "example-access-token",
+ * "tokenType": "bearer",
+ * "user": {
+ * "id": "11111111-1111-1111-1111-111111111111",
+ * "email": "developer@example.com",
+ * "createdAt": "2026-07-17T00:00:00Z"
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["AuthResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ register_auth_register_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["RegisterRequest"];
+ };
+ };
+ responses: {
+ /** @description Account created and a refresh-cookie session started. */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "accessToken": "example-access-token",
+ * "tokenType": "bearer",
+ * "user": {
+ * "id": "11111111-1111-1111-1111-111111111111",
+ * "email": "developer@example.com",
+ * "createdAt": "2026-07-17T00:00:00Z"
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["AuthResponse"];
+ };
+ };
+ /** @description The request conflicts with existing state. */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "conflict_error",
+ * "message": "Repository has already been imported.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ generate_documentation_documentation_generate_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["GenerateDocRequest"];
+ };
+ };
+ responses: {
+ /** @description Generated documentation for the requested repository. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "content": "# Example service\\n\\n## Overview\\n\\nGenerated documentation.",
+ * "format": "markdown",
+ * "generatedAt": "2026-07-17T00:00:00Z",
+ * "source": "ri.v1",
+ * "snapshotId": "snap_example",
+ * "snapshotSchemaVersion": "ri.v1",
+ * "revisionKind": "git",
+ * "revisionValue": "0123456789abcdef0123456789abcdef01234567",
+ * "revisionRef": "refs/heads/main"
+ * }
+ */
+ "application/json": components["schemas"]["GenerateDocResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ export_report_export_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExportRequest"];
+ };
+ };
+ responses: {
+ /** @description Repository report rendered in the requested format; an uncomputed review returns 409. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "filename": "engineering-review.json",
+ * "mediaType": "application/json",
+ * "encoding": "utf-8",
+ * "content": "{\\n \\\"repositoryId\\\": \\\"11111111-1111-1111-1111-111111111111\\\"\\n}"
+ * }
+ */
+ "application/json": components["schemas"]["ExportResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request conflicts with existing state. */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "conflict_error",
+ * "message": "Repository has already been imported.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ health_health_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description The API process is running. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "status": "ok",
+ * "environment": "development"
+ * }
+ */
+ "application/json": {
+ [key: string]: string;
+ };
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_snapshot_intelligence_v1_snapshots__snapshot_id__get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ snapshot_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Sealed ri.v1 snapshot metadata. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "ri.v1"
+ * }
+ */
+ "application/json": components["schemas"]["RiSnapshotMetadataResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ list_assertions_intelligence_v1_snapshots__snapshot_id__assertions_get: {
+ parameters: {
+ query?: {
+ /** @description Maximum 100 results per page. */
+ limit?: number;
+ /** @description Zero-based deterministic result offset. */
+ offset?: number;
+ };
+ header?: never;
+ path: {
+ snapshot_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Stored inferred assertions with their derivations. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "ri.v1",
+ * "data": [],
+ * "pagination": {
+ * "offset": 0,
+ * "limit": 50,
+ * "total": 0
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["RiAssertionsResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ list_evidence_intelligence_v1_snapshots__snapshot_id__evidence_get: {
+ parameters: {
+ query?: {
+ /** @description Maximum 100 results per page. */
+ limit?: number;
+ /** @description Zero-based deterministic result offset. */
+ offset?: number;
+ };
+ header?: never;
+ path: {
+ snapshot_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Stored evidence spans only. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "ri.v1",
+ * "data": [],
+ * "pagination": {
+ * "offset": 0,
+ * "limit": 50,
+ * "total": 0
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["RiEvidenceResponsePage"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_impact_intelligence_v1_snapshots__snapshot_id__impact_get: {
+ parameters: {
+ query: {
+ /** @description Directed import/dependency traversal depth (1-10). */
+ depth?: number;
+ nodeKey: string;
+ };
+ header?: never;
+ path: {
+ snapshot_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Bounded, provenance-backed dependents and dependencies over stored import/dependency edges. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "ri.v1",
+ * "nodeKey": "file:src/api.py",
+ * "depth": 1,
+ * "dependents": {
+ * "data": [],
+ * "limitReached": false
+ * },
+ * "dependencies": {
+ * "data": [],
+ * "limitReached": false
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["RiImpactResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ list_neighbours_intelligence_v1_snapshots__snapshot_id__neighbours_get: {
+ parameters: {
+ query: {
+ /** @description Maximum 100 results per page. */
+ limit?: number;
+ nodeKey: string;
+ /** @description Zero-based deterministic result offset. */
+ offset?: number;
+ };
+ header?: never;
+ path: {
+ snapshot_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Stored resolved edges incident to a node. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "ri.v1",
+ * "nodeKey": "repo:root",
+ * "data": [],
+ * "pagination": {
+ * "offset": 0,
+ * "limit": 50,
+ * "total": 0
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["RiNeighboursResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ list_paths_intelligence_v1_snapshots__snapshot_id__paths_get: {
+ parameters: {
+ query?: {
+ /** @description Maximum 100 results per page. */
+ limit?: number;
+ /** @description Zero-based deterministic result offset. */
+ offset?: number;
+ };
+ header?: never;
+ path: {
+ snapshot_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Stored file facts with provenance. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "ri.v1",
+ * "data": [],
+ * "pagination": {
+ * "offset": 0,
+ * "limit": 50,
+ * "total": 0
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["RiPathsResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ list_references_intelligence_v1_snapshots__snapshot_id__references_get: {
+ parameters: {
+ query?: {
+ /** @description Maximum 100 results per page. */
+ limit?: number;
+ /** @description Zero-based deterministic result offset. */
+ offset?: number;
+ };
+ header?: never;
+ path: {
+ snapshot_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Stored resolved relationship facts only. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "ri.v1",
+ * "data": [],
+ * "pagination": {
+ * "offset": 0,
+ * "limit": 50,
+ * "total": 0
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["RiReferencesResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ list_symbols_intelligence_v1_snapshots__snapshot_id__symbols_get: {
+ parameters: {
+ query?: {
+ /** @description Maximum 100 results per page. */
+ limit?: number;
+ /** @description Zero-based deterministic result offset. */
+ offset?: number;
+ };
+ header?: never;
+ path: {
+ snapshot_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Observed symbol nodes with stored evidence. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "schemaVersion": "ri.v1",
+ * "data": [],
+ * "pagination": {
+ * "offset": 0,
+ * "limit": 50,
+ * "total": 0
+ * }
+ * }
+ */
+ "application/json": components["schemas"]["RiSymbolsResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ metrics_metrics_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Prometheus-compatible runtime metrics. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /** @example partha_http_requests_total 1\n */
+ "text/plain": string;
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ "text/plain": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ "text/plain": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ readiness_ready_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description The API can reach its database and write to repository storage. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "status": "ready",
+ * "environment": "development",
+ * "checks": {
+ * "database": "ok",
+ * "storage": "ok"
+ * }
+ * }
+ */
+ "application/json": {
+ checks: {
+ [key: string]: "ok" | "error";
+ };
+ environment: string;
+ /** @enum {string} */
+ status: "ready" | "not_ready";
+ };
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The API is running but one or more readiness checks failed. */
+ 503: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "status": "not_ready",
+ * "environment": "development",
+ * "checks": {
+ * "database": "error",
+ * "storage": "ok"
+ * }
+ * }
+ */
+ "application/json": {
+ checks: {
+ [key: string]: "ok" | "error";
+ };
+ environment: string;
+ /** @enum {string} */
+ status: "ready" | "not_ready";
+ };
+ };
+ };
+ };
+ };
+ list_repositories_repositories_get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Repositories owned by the authenticated user. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "data": [
+ * {
+ * "id": "11111111-1111-1111-1111-111111111111",
+ * "name": "example-service",
+ * "source": "github",
+ * "sourceUrl": "https://github.com/example/example-service",
+ * "branch": "main",
+ * "size": 2048,
+ * "fileCount": 12,
+ * "status": "completed",
+ * "analysisStage": "completed",
+ * "analysisProgress": 100,
+ * "uploadedAt": "2026-07-17T00:00:00Z",
+ * "analysedAt": "2026-07-17T00:00:02Z",
+ * "revision": {
+ * "kind": "git",
+ * "value": "0123456789abcdef0123456789abcdef01234567",
+ * "ref": "refs/heads/main"
+ * },
+ * "commitSha": "0123456789abcdef0123456789abcdef01234567",
+ * "fileTree": []
+ * }
+ * ],
+ * "total": 1
+ * }
+ */
+ "application/json": components["schemas"]["RepositoryListResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_repository_repositories__repository_id__get: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Repository metadata and file tree. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "id": "11111111-1111-1111-1111-111111111111",
+ * "name": "example-service",
+ * "source": "github",
+ * "sourceUrl": "https://github.com/example/example-service",
+ * "branch": "main",
+ * "size": 2048,
+ * "fileCount": 12,
+ * "status": "completed",
+ * "analysisStage": "completed",
+ * "analysisProgress": 100,
+ * "uploadedAt": "2026-07-17T00:00:00Z",
+ * "analysedAt": "2026-07-17T00:00:02Z",
+ * "revision": {
+ * "kind": "git",
+ * "value": "0123456789abcdef0123456789abcdef01234567",
+ * "ref": "refs/heads/main"
+ * },
+ * "commitSha": "0123456789abcdef0123456789abcdef01234567",
+ * "fileTree": []
+ * }
+ */
+ "application/json": components["schemas"]["RepositoryResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ delete_repository_repositories__repository_id__delete: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Successful Response */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ get_repository_file_repositories__repository_id__file_get: {
+ parameters: {
+ query: {
+ /** @description Repository-relative file path. */
+ path: string;
+ };
+ header?: never;
+ path: {
+ repository_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Preview of a repository-relative file. */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "path": "/README.md",
+ * "content": "# Example service\\n",
+ * "size": 18,
+ * "truncated": false,
+ * "isBinary": false,
+ * "isImage": false
+ * }
+ */
+ "application/json": components["schemas"]["RepositoryFileResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The requested resource does not exist or is not accessible to this user. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "not_found",
+ * "message": "Repository not found.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ import_github_repository_repositories_github_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["GitHubImportRequest"];
+ };
+ };
+ responses: {
+ /** @description Public GitHub repository cloned and parsed. */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "id": "11111111-1111-1111-1111-111111111111",
+ * "name": "example-service",
+ * "source": "github",
+ * "sourceUrl": "https://github.com/example/example-service",
+ * "branch": "main",
+ * "size": 2048,
+ * "fileCount": 12,
+ * "status": "completed",
+ * "analysisStage": "completed",
+ * "analysisProgress": 100,
+ * "uploadedAt": "2026-07-17T00:00:00Z",
+ * "analysedAt": "2026-07-17T00:00:02Z",
+ * "revision": {
+ * "kind": "git",
+ * "value": "0123456789abcdef0123456789abcdef01234567",
+ * "ref": "refs/heads/main"
+ * },
+ * "commitSha": "0123456789abcdef0123456789abcdef01234567",
+ * "fileTree": []
+ * }
+ */
+ "application/json": components["schemas"]["RepositoryResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request conflicts with existing state. */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "conflict_error",
+ * "message": "Repository has already been imported.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An upstream service could not complete the request. */
+ 502: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "external_service_error",
+ * "message": "AI provider request failed.",
+ * "details": {
+ * "provider": "openai"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An upstream service did not respond before the timeout. */
+ 504: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "timeout_error",
+ * "message": "GitHub repository clone timed out.",
+ * "details": {
+ * "timeoutSeconds": 120
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+ upload_repository_repositories_upload_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "multipart/form-data": components["schemas"]["Body_upload_repository_repositories_upload_post"];
+ };
+ };
+ responses: {
+ /** @description Repository archive accepted and parsed. */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "id": "11111111-1111-1111-1111-111111111111",
+ * "name": "example-service",
+ * "source": "github",
+ * "sourceUrl": "https://github.com/example/example-service",
+ * "branch": "main",
+ * "size": 2048,
+ * "fileCount": 12,
+ * "status": "completed",
+ * "analysisStage": "completed",
+ * "analysisProgress": 100,
+ * "uploadedAt": "2026-07-17T00:00:00Z",
+ * "analysedAt": "2026-07-17T00:00:02Z",
+ * "revision": {
+ * "kind": "git",
+ * "value": "0123456789abcdef0123456789abcdef01234567",
+ * "ref": "refs/heads/main"
+ * },
+ * "commitSha": "0123456789abcdef0123456789abcdef01234567",
+ * "fileTree": []
+ * }
+ */
+ "application/json": components["schemas"]["RepositoryResponse"];
+ };
+ };
+ /** @description Authentication is required or the access token is invalid. */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "unauthorized",
+ * "message": "Not authenticated.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request conflicts with existing state. */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "conflict_error",
+ * "message": "Repository has already been imported.",
+ * "details": {
+ * "repositoryId": "11111111-1111-1111-1111-111111111111"
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request could not be validated. */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "request_validation_error",
+ * "message": "Request validation failed.",
+ * "details": {
+ * "errors": [
+ * {
+ * "loc": [
+ * "body",
+ * "url"
+ * ],
+ * "msg": "Field required"
+ * }
+ * ]
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description The request-rate limit has been exceeded. */
+ 429: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "rate_limited",
+ * "message": "Too many requests. Try again shortly.",
+ * "details": {
+ * "retryAfterSeconds": 30
+ * },
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ /** @description An unexpected server error occurred. */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ /**
+ * @example {
+ * "code": "internal_server_error",
+ * "message": "An unexpected error occurred.",
+ * "request_id": "req_01HXYZEXAMPLE"
+ * }
+ */
+ "application/json": components["schemas"]["ErrorResponse"];
+ };
+ };
+ };
+ };
+}
diff --git a/apps/frontend/src/shared/services/api/index.ts b/apps/frontend/src/shared/services/api/index.ts
index 4258d2c..df0b266 100644
--- a/apps/frontend/src/shared/services/api/index.ts
+++ b/apps/frontend/src/shared/services/api/index.ts
@@ -1,7 +1,7 @@
export { api, configureApiClient, getApiConfig, uploadFile, requestSharedRefresh } from './client';
export type { RequestConfig, ApiClientConfig, HttpMethod } from './client';
-export { ApiError, NetworkError, TimeoutError, CancelledError, isApiError, isNetworkError, isTimeoutError, isCancelledError, getErrorMessage, getErrorDetail } from './errors';
+export { ApiError, NetworkError, TimeoutError, CancelledError, isApiError, isNetworkError, isTimeoutError, isCancelledError, isErrorResponse, getErrorMessage, getErrorDetail } from './errors';
export { authService } from './auth';
export { repositoryService, repositoryIntelligenceService } from './repositories';
@@ -14,3 +14,4 @@ export { aiService } from './ai';
export { documentationService, exportService } from './documentation';
export type * from './types';
+export type * from './generated';
diff --git a/apps/frontend/src/shared/services/api/insights.ts b/apps/frontend/src/shared/services/api/insights.ts
index 53cbd31..bc7c047 100644
--- a/apps/frontend/src/shared/services/api/insights.ts
+++ b/apps/frontend/src/shared/services/api/insights.ts
@@ -1,9 +1,20 @@
import { api } from './client';
import type { RequestConfig } from './client';
+import type { components } from './generated';
import type { RepositoryInsights } from '@/shared/types/insights';
export const insightsService = {
getInsights(repositoryId: string, config?: RequestConfig): Promise {
- return api.get(`/analysis/${repositoryId}/insights`, config);
+ return api.get(`/analysis/${repositoryId}/insights`, config)
+ .then((response) => ({
+ ...response,
+ changeOverTime: response.changeOverTime ?? { assessmentState: 'not_assessed', message: 'Change-over-time insights are not available yet.' },
+ extractorSet: response.extractorSet ?? [],
+ metrics: response.metrics ?? [],
+ relationshipsByPredicate: response.relationshipsByPredicate ?? [],
+ diagnosticsBySeverity: response.diagnosticsBySeverity ?? [],
+ diagnosticsByCode: response.diagnosticsByCode ?? [],
+ languages: response.languages ?? [],
+ }));
},
};
diff --git a/apps/frontend/src/shared/services/api/repositories.ts b/apps/frontend/src/shared/services/api/repositories.ts
index 3edaac5..5e0c3bf 100644
--- a/apps/frontend/src/shared/services/api/repositories.ts
+++ b/apps/frontend/src/shared/services/api/repositories.ts
@@ -1,17 +1,12 @@
import { api } from './client';
import type { RequestConfig } from './client';
+import type { components } from './generated';
import type {
RepositoryResponse,
RepositoryListResponse,
RepositoryFileResponse,
ImportGithubRequest,
- RiCollectionResponse,
- RiAssertion,
- RiEdge,
- RiEvidence,
RiNeighboursResponse,
- RiNode,
- RiPath,
RiSnapshotMetadata,
} from './types';
@@ -42,7 +37,7 @@ export const repositoryIntelligenceService = {
return api.get(`/intelligence/v1/snapshots/${encodeURIComponent(snapshotId)}`, config);
},
- listSymbols(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise> {
+ listSymbols(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise {
return api.get(`/intelligence/v1/snapshots/${encodeURIComponent(snapshotId)}/symbols?offset=${offset}&limit=${limit}`, config);
},
@@ -50,19 +45,19 @@ export const repositoryIntelligenceService = {
return api.get(`/intelligence/v1/snapshots/${encodeURIComponent(snapshotId)}/neighbours?nodeKey=${encodeURIComponent(nodeKey)}&offset=${offset}&limit=${limit}`, config);
},
- listReferences(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise> {
+ listReferences(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise {
return api.get(`/intelligence/v1/snapshots/${encodeURIComponent(snapshotId)}/references?offset=${offset}&limit=${limit}`, config);
},
- listAssertions(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise> {
+ listAssertions(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise {
return api.get(`/intelligence/v1/snapshots/${encodeURIComponent(snapshotId)}/assertions?offset=${offset}&limit=${limit}`, config);
},
- listPaths(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise> {
+ listPaths(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise {
return api.get(`/intelligence/v1/snapshots/${encodeURIComponent(snapshotId)}/paths?offset=${offset}&limit=${limit}`, config);
},
- listEvidence(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise> {
+ listEvidence(snapshotId: string, offset = 0, limit = 50, config?: RequestConfig): Promise {
return api.get(`/intelligence/v1/snapshots/${encodeURIComponent(snapshotId)}/evidence?offset=${offset}&limit=${limit}`, config);
},
};
diff --git a/apps/frontend/src/shared/services/api/review.ts b/apps/frontend/src/shared/services/api/review.ts
index 8e0abac..35680e6 100644
--- a/apps/frontend/src/shared/services/api/review.ts
+++ b/apps/frontend/src/shared/services/api/review.ts
@@ -1,9 +1,11 @@
import { api } from './client';
import type { RequestConfig } from './client';
+import type { components } from './generated';
import type { ReviewResponse } from './types';
export const reviewService = {
getReview(repositoryId: string, config?: RequestConfig): Promise {
- return api.get(`/analysis/${repositoryId}/review`, config);
+ return api.get(`/analysis/${repositoryId}/review`, config)
+ .then((response) => ({ ...response, categories: response.categories ?? [], findings: response.findings ?? [] }));
},
};
diff --git a/apps/frontend/src/shared/services/api/types.ts b/apps/frontend/src/shared/services/api/types.ts
index 12f8824..1cec089 100644
--- a/apps/frontend/src/shared/services/api/types.ts
+++ b/apps/frontend/src/shared/services/api/types.ts
@@ -1,7 +1,8 @@
-import type { FileTreeNode, RepositoryMeta, AnalysisStage } from '@/shared/types';
-import type { ArchitectureModel } from '@/shared/types/architecture';
-import type { EngineeringReview } from '@/shared/types/review';
+import type { components } from './generated';
+type WithGeneratedDefaults = Omit & Required>;
+
+/** Transport helpers retained for non-schema-wrapped legacy endpoints. */
export interface ApiResponse {
data: T;
meta?: {
@@ -21,487 +22,87 @@ export interface PaginatedResponse {
};
}
-// Repository
-
-// First-class revision identity (#87). `value` is the immutable identity: a
-// 40-char lowercase git commit SHA for GitHub imports, or a `sha256:`
-// archive content hash for uploads. `ref` (e.g. `refs/heads/main`) is a moving
-// pointer — descriptive metadata only, never identity, and null for uploads.
-export interface RepositoryRevision {
- kind: 'git' | 'upload';
- value: string;
- ref: string | null;
-}
-
-export interface RepositoryResponse {
- id: string;
- name: string;
- description: string | null;
- source: 'upload' | 'github';
- sourceUrl: string | null;
- branch?: string | null;
- size: number;
- fileCount: number;
- status: 'uploading' | 'analysing' | 'completed' | 'cancelled' | 'error';
- analysisStage: AnalysisStage | null;
- analysisProgress: number;
- uploadedAt: string;
- analysedAt: string | null;
- errorMessage: string | null;
- revision: RepositoryRevision | null;
- // Backward-compatible alias of `revision.value`.
- commitSha: string | null;
- meta: RepositoryMeta | null;
- fileTree: FileTreeNode[];
-}
-
-export interface CreateRepositoryRequest {
- name: string;
- description?: string;
- source: 'upload' | 'github';
- sourceUrl?: string;
-}
-
-export interface ImportGithubRequest {
- url: string;
- branch?: string;
-}
-
-export interface RepositoryListResponse {
- data: RepositoryResponse[];
- total: number;
-}
-
-export interface RepositoryFileResponse {
- path: string;
- content: string;
- size: number;
- truncated: boolean;
- isBinary: boolean;
- isImage: boolean;
- mediaType: string | null;
-}
-
-// Repository Intelligence snapshot queries (`/intelligence/v1`). These are
-// read-only views of sealed, owner-scoped normalized facts, not legacy metadata.
-export type RiSchemaVersion = 'ri.v1';
-
-export interface RiPagination {
- offset: number;
- limit: number;
- total: number;
-}
-
-export interface RiEvidence {
- schemaVersion: RiSchemaVersion;
- factKind: 'node' | 'edge' | 'observation';
- factId: string;
- path: string;
- startLine: number;
- endLine: number;
- granularity: 'span' | 'file';
- extractor: string;
- extractorVersion: string;
-}
-
-export interface RiNode {
- stableKey: string;
- nodeKind: string;
- name: string | null;
- language: string | null;
- truthClass: 'observed';
- properties: Record | null;
- evidence: RiEvidence[];
-}
-
-export interface RiEdge {
- edgeId: string;
- subjectKind: string;
- subjectKey: string;
- predicate: string;
- objectKind: string;
- objectKey: string;
- truthClass: 'resolved';
- producer: string;
- producerVersion: string;
- evidence: RiEvidence[];
- derivedFrom: Array<{ kind: string; identity: string }>;
-}
-
-export interface RiAssertion {
- assertionId: string;
- subjectKind: string;
- subjectKey: string;
- predicate: string;
- value: Record;
- truthClass: 'inferred';
- producer: string;
- producerVersion: string;
- derivedFrom: Array<{ kind: string; identity: string }>;
-}
-
-export interface RiSnapshotMetadata {
- schemaVersion: RiSchemaVersion;
- snapshotId: string;
- repositoryId: string;
- revisionKind: 'git' | 'upload';
- revisionValue: string;
- revisionRef: string | null;
- state: 'completed';
- producerVersionSet: string[];
- producerSetHash: string;
- configHash: string;
- canonicalGraphHash: string;
- createdAt: string;
- updatedAt: string;
- sealedAt: string;
-}
-
-export interface RiCollectionResponse {
- schemaVersion: RiSchemaVersion;
- data: T[];
- pagination: RiPagination;
-}
-
-export interface RiPath {
- path: string;
- node: RiNode;
-}
-
-export interface RiNeighboursResponse extends RiCollectionResponse {
- nodeKey: string;
-}
-
-// Analysis
-export type AnalysisJobStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled';
-
-export interface AnalysisStartResponse {
- repositoryId: string;
- status: AnalysisJobStatus;
- jobId: string | null;
-}
-
-export interface AnalysisStatusResponse {
- repositoryId: string;
- status: AnalysisJobStatus;
- jobId: string | null;
- stage: AnalysisStage | null;
- progress: number;
- startedAt: string | null;
- completedAt: string | null;
- error: string | null;
-}
-
-// Architecture
-export type ArchitectureResponse = ArchitectureModel;
-
-// Authentication explanation (evidence-backed, snapshot-only)
-export type AuthSchemaVersion = 'auth-explanation.v1';
-export type AuthClaimKind = 'route' | 'middleware' | 'service' | 'model' | 'dependency';
-export type AuthRelationshipNodeKind = 'route' | 'handler' | 'middleware' | 'service' | 'model' | 'dependency';
-export type AuthConfidence = 'observed' | 'heuristic';
-export type AuthStatus = 'ready' | 'missing_snapshot';
-
-export interface AuthEvidenceRef {
- snapshotId: string;
- factId: string;
- path: string;
- startLine: number;
- endLine: number;
-}
-
-export interface AuthClaim {
- kind: AuthClaimKind;
- name: string;
- confidence: AuthConfidence;
- evidence: AuthEvidenceRef[];
-}
-
-export interface AuthRelationship {
- subject: string;
- subjectKind: AuthRelationshipNodeKind;
- predicate: string;
- object: string;
- objectKind: AuthRelationshipNodeKind;
- evidence: AuthEvidenceRef[];
-}
-
-export interface AuthChain {
- route: string;
- hops: AuthRelationship[];
-}
-
-export interface AuthenticationDiagnostic {
- code: string;
- category: string;
- severity: 'fatal' | 'error' | 'warning' | 'info';
- message: string;
- path: string | null;
- startLine: number | null;
- endLine: number | null;
-}
-
-export interface AuthenticationExplanationResponse {
- schemaVersion: AuthSchemaVersion;
- repositoryId: string;
- repositoryName: string;
- revisionKind: string | null;
- revisionValue: string | null;
- snapshotId: string | null;
- status: AuthStatus;
- summary: string;
- claims: AuthClaim[];
- relationships: AuthRelationship[];
- chains: AuthChain[];
- diagnostics: AuthenticationDiagnostic[];
-}
-
-// Evidence-source navigation (snapshot-and-revision-verified, #95)
-export type EvidenceSchemaVersion = 'evidence-source.v1';
-export type EvidenceSourceStatus = 'ready' | 'unavailable';
-
-export interface EvidenceSourceResponse {
- schemaVersion: EvidenceSchemaVersion;
- repositoryId: string;
- snapshotId: string;
- factId: string;
- revisionKind: string | null;
- revisionValue: string | null;
- path: string;
- startLine: number;
- endLine: number;
- status: EvidenceSourceStatus;
- reason: string | null;
- content: string | null;
- truncated: boolean;
- size: number;
-}
-
-// Dependency Graph (#158) — built exclusively from a sealed ri.v1 snapshot,
-// the same contract shape as Review/Insights: no legacy fallback.
-export interface DependencyNode {
- id: string;
- name: string;
- version: string | null;
- type: 'production' | 'development' | 'peer' | 'optional' | 'multiple';
- ecosystem: string;
- declarations: DependencyDeclaration[];
-}
-
-export interface DependencyDeclaration {
- name: string;
- manifestPath: string;
- workspacePath: string;
- startLine: number;
- endLine: number;
- extractor: string;
- extractorVersion: string;
- ecosystem: string;
- version: string | null;
- type: 'production' | 'development' | 'peer' | 'optional';
-}
-
-export interface DependencyDiagnostic {
- code: string;
- category: string;
- severity: 'fatal' | 'error' | 'warning' | 'info';
- message: string;
- path: string | null;
- producer: string;
- details: Record | null;
-}
-
-export interface DependencyEdge {
- id: string;
- source: string;
- target: string;
- type: 'depends-on';
-}
-
-export interface DependencyAssessment {
- status: 'not_computed';
-}
-
-export interface DependencyProvenance {
- source: 'ri.v1';
- snapshotId: string;
- snapshotSchemaVersion: string;
- canonicalGraphHash: string;
-}
-
-export interface DependencyGraphResponse {
- schemaVersion: 'dependency-graph.v2';
- repositoryId: string;
- repositoryName: string;
- revisionKind: 'git' | 'upload';
- revisionValue: string;
- snapshotId: string;
- snapshotSchemaVersion: string;
- canonicalGraphHash: string;
- manifestDigest: string;
- provenance: DependencyProvenance;
- generatedAt: string;
- nodes: DependencyNode[];
- edges: DependencyEdge[];
- totalDependencies: number;
- manifestCount: number;
- diagnostics: DependencyDiagnostic[];
- vulnerabilityAssessment: DependencyAssessment;
- outdatedAssessment: DependencyAssessment;
-}
-
-// Review
-export type ReviewResponse = EngineeringReview;
-
-// AI
-export interface AiQueryRequest {
- repositoryId: string;
- query: string;
- context?: {
- selectedNodeId?: string;
- selectedFile?: string;
- conversationHistory?: AiMessage[];
- };
-}
-
-export interface AiMessage {
- role: 'user' | 'assistant';
- content: string;
- timestamp: string;
- citations?: AiCitation[];
-}
-
-export interface AiCitation {
- file: string;
- startLine: number;
- endLine: number;
- content: string;
-}
-
-export interface AiQueryResponse {
- message: AiMessage;
- suggestions?: string[];
-}
-
-export type AiProvider = 'openai' | 'anthropic' | 'gemini' | 'openrouter' | 'ollama';
-
-export interface AiProviderConfig {
- provider: AiProvider;
- apiKey?: string;
- model?: string;
- baseUrl?: string;
-}
-
-export interface AiProviderPublicConfig {
- provider: AiProvider | null;
- model: string | null;
- baseUrl: string | null;
- hasApiKey: boolean;
- // Write-only key contract: the backend returns only the last four characters,
- // never the full key. Null when no key is stored.
- apiKeyLast4: string | null;
-}
-
-export interface AiProviderTestRequest {
- provider?: AiProvider;
- apiKey?: string;
- model?: string;
- baseUrl?: string;
-}
-
-export interface AiProviderTestResponse {
- ok: boolean;
- message: string;
- checkedAt: string;
-}
-
-// Documentation
-export interface GenerateDocRequest {
- repositoryId: string;
- format: 'markdown' | 'html';
- sections?: string[];
-}
-
-export interface GenerateDocResponse {
- content: string;
- format: 'markdown' | 'html';
- generatedAt: string;
- source: 'ri.v1';
- snapshotId: string;
- snapshotSchemaVersion: 'ri.v1';
- revisionKind: 'git' | 'upload';
- revisionValue: string;
- revisionRef?: string | null;
-}
-
-// Auth
-export interface UserResponse {
- id: string;
- email: string;
- createdAt: string;
-}
-
-export interface AuthResponse {
- accessToken: string;
- tokenType: 'bearer';
- user: UserResponse;
-}
-
-export interface LoginRequest {
- email: string;
- password: string;
-}
-
-export interface RegisterRequest {
- email: string;
- password: string;
-}
-
-// Export
-export type ExportFormat = 'json' | 'markdown' | 'html' | 'pdf';
-export type ExportTarget = 'review' | 'documentation' | 'architecture' | 'dependencies';
-
-export interface ExportRequest {
- repositoryId: string;
- target: ExportTarget;
- format: ExportFormat;
-}
-
-export interface ExportResponse {
- filename: string;
- mediaType: string;
- encoding: 'utf-8' | 'base64';
- content: string;
-}
-
-// Revision manifest (#113): the verifiable identity of the sealed snapshot an
-// answer was derived from. `manifestDigest` is a canonical content hash, not a
-// digital signature.
-export interface ManifestExtractor {
- name: string;
- version: string;
-}
-
-export interface RevisionManifest {
- schemaVersion: 'revision-manifest.v1';
- repositoryId: string;
- revisionKind: 'git' | 'upload';
- revisionValue: string;
- revisionRef: string | null;
- snapshotId: string;
- snapshotSchemaVersion: string;
- extractors: ManifestExtractor[];
- producerSetHash: string;
- configHash: string;
- canonicalGraphHash: string | null;
- createdAt: string;
- sealedAt: string | null;
-}
-
-export interface RevisionManifestResponse {
- manifest: RevisionManifest;
- manifestDigest: string;
- verificationMethod: string;
- verificationState: 'verified' | 'superseded' | 'mismatch' | 'unverifiable';
- verificationNote: string;
-}
+// The aliases below are compatibility names for the existing service/UI
+// modules. Their shapes are owned by the generated OpenAPI components; this
+// file intentionally contains no hand-maintained DTO fields.
+export type RepositoryRevision = components['schemas']['RepositoryRevision'];
+export type RepositoryResponse = components['schemas']['RepositoryResponse'];
+export type ImportGithubRequest = components['schemas']['GitHubImportRequest'];
+export type RepositoryListResponse = components['schemas']['RepositoryListResponse'];
+export type RepositoryFileResponse = components['schemas']['RepositoryFileResponse'];
+
+export type RiSchemaVersion = components['schemas']['RiEvidenceResponse']['schemaVersion'];
+export type RiPagination = components['schemas']['RiPagination'];
+export type RiEvidence = components['schemas']['RiEvidenceResponse'];
+export type RiNode = components['schemas']['RiNodeResponse'];
+export type RiEdge = components['schemas']['RiEdgeResponse'];
+export type RiAssertion = components['schemas']['RiAssertionResponse'];
+export type RiSnapshotMetadata = components['schemas']['RiSnapshotMetadataResponse'];
+export type RiCollectionResponse = Omit & { data: T[] };
+export type RiPath = components['schemas']['RiPathResponse'];
+export type RiNeighboursResponse = components['schemas']['RiNeighboursResponse'];
+
+export type AnalysisJobStatus = components['schemas']['AnalysisStartResponse']['status'];
+export type AnalysisStartResponse = components['schemas']['AnalysisStartResponse'];
+export type AnalysisStatusResponse = components['schemas']['AnalysisStatusResponse'];
+
+export type ArchitectureResponse = WithGeneratedDefaults;
+
+export type AuthSchemaVersion = components['schemas']['AuthenticationExplanationResponse']['schemaVersion'];
+export type AuthClaimKind = components['schemas']['AuthClaim']['kind'];
+export type AuthRelationshipNodeKind = components['schemas']['AuthRelationship']['subjectKind'];
+export type AuthConfidence = components['schemas']['AuthClaim']['confidence'];
+export type AuthStatus = components['schemas']['AuthenticationExplanationResponse']['status'];
+export type AuthEvidenceRef = components['schemas']['AuthEvidenceRef'];
+export type AuthClaim = components['schemas']['AuthClaim'];
+export type AuthRelationship = components['schemas']['AuthRelationship'];
+export type AuthChain = components['schemas']['AuthChain'];
+export type AuthenticationDiagnostic = components['schemas']['AuthenticationDiagnostic'];
+export type AuthenticationExplanationResponse = WithGeneratedDefaults<
+ components['schemas']['AuthenticationExplanationResponse'],
+ 'claims' | 'relationships' | 'chains' | 'diagnostics'
+>;
+
+export type EvidenceSchemaVersion = components['schemas']['EvidenceSourceResponse']['schemaVersion'];
+export type EvidenceSourceStatus = components['schemas']['EvidenceSourceResponse']['status'];
+export type EvidenceSourceResponse = components['schemas']['EvidenceSourceResponse'];
+
+export type DependencyNode = components['schemas']['DependencyNode'];
+export type DependencyDeclaration = components['schemas']['DependencyDeclaration'];
+export type DependencyDiagnostic = components['schemas']['DependencyDiagnostic'];
+export type DependencyEdge = components['schemas']['DependencyEdge'];
+export type DependencyAssessment = components['schemas']['DependencyAssessment'];
+export type DependencyProvenance = components['schemas']['DependencyProvenance'];
+export type DependencyGraphResponse = WithGeneratedDefaults;
+
+export type ReviewResponse = WithGeneratedDefaults<
+ components['schemas']['EngineeringReviewResponse'],
+ 'categories' | 'findings'
+>;
+
+export type AiQueryRequest = components['schemas']['AiQueryRequest'];
+export type AiMessage = components['schemas']['AiMessage'];
+export type AiCitation = components['schemas']['AiCitation'];
+export type AiQueryResponse = components['schemas']['AiQueryResponse'];
+export type AiProvider = components['schemas']['AiProviderConfig']['provider'];
+export type AiProviderConfig = components['schemas']['AiProviderConfig'];
+export type AiProviderPublicConfig = components['schemas']['AiProviderPublicConfig'];
+export type AiProviderTestRequest = components['schemas']['AiProviderTestRequest'];
+export type AiProviderTestResponse = components['schemas']['AiProviderTestResponse'];
+
+export type GenerateDocRequest = components['schemas']['GenerateDocRequest'];
+export type GenerateDocResponse = components['schemas']['GenerateDocResponse'];
+
+export type UserResponse = components['schemas']['UserResponse'];
+export type AuthResponse = components['schemas']['AuthResponse'];
+export type LoginRequest = components['schemas']['LoginRequest'];
+export type RegisterRequest = components['schemas']['RegisterRequest'];
+
+export type ExportFormat = components['schemas']['ExportRequest']['format'];
+export type ExportTarget = components['schemas']['ExportRequest']['target'];
+export type ExportRequest = components['schemas']['ExportRequest'];
+export type ExportResponse = components['schemas']['ExportResponse'];
+
+export type ManifestExtractor = components['schemas']['ManifestExtractor'];
+export type RevisionManifest = components['schemas']['RevisionManifest'];
+export type RevisionManifestResponse = components['schemas']['RevisionManifestResponse'];
diff --git a/apps/frontend/src/shared/services/backend.ts b/apps/frontend/src/shared/services/backend.ts
index 7f6047e..471db85 100644
--- a/apps/frontend/src/shared/services/backend.ts
+++ b/apps/frontend/src/shared/services/backend.ts
@@ -117,14 +117,14 @@ function mapRepositoryResponse(response: RepositoryResponse): Repository {
size: response.size,
fileCount: response.fileCount,
status: response.status,
- analysisStage: response.analysisStage,
+ analysisStage: response.analysisStage ?? null,
analysisProgress: response.analysisProgress,
uploadedAt: response.uploadedAt,
analysedAt: response.analysedAt || undefined,
errorMessage: response.errorMessage || undefined,
- revision: response.revision,
- commitSha: response.commitSha,
- meta: response.meta,
- fileTree: response.fileTree,
+ revision: response.revision ? { ...response.revision, ref: response.revision.ref ?? null } : null,
+ commitSha: response.commitSha ?? null,
+ meta: response.meta ?? null,
+ fileTree: response.fileTree ?? [],
};
}
diff --git a/apps/frontend/src/shared/types/architecture.ts b/apps/frontend/src/shared/types/architecture.ts
index 739ee86..5bf1ece 100644
--- a/apps/frontend/src/shared/types/architecture.ts
+++ b/apps/frontend/src/shared/types/architecture.ts
@@ -1,126 +1,25 @@
-export type ArchNodeType =
- | 'frontend'
- | 'backend'
- | 'controller'
- | 'route'
- | 'service'
- | 'repository'
- | 'database'
- | 'configuration'
- | 'authentication'
- | 'middleware'
- | 'utilities'
- | 'models'
- | 'external-api'
- | 'shared-library'
- | 'environment'
- | 'queue'
- | 'cache';
-
-export type ArchEdgeType = 'dependency' | 'import' | 'api-call' | 'data-flow' | 'event' | 'reads' | 'writes' | 'calls' | 'config-usage';
-export type RelationshipState = 'connected' | 'no-observed-relationships' | 'unresolved' | 'not-extracted';
-export type TruthClass = 'resolved' | 'inferred';
+import type { components } from '@/shared/services/api/generated';
+
+export type ArchNodeType = components['schemas']['ArchNode']['type'];
+export type ArchEdgeType = components['schemas']['ArchEdge']['type'];
+export type RelationshipState = components['schemas']['ArchNode']['relationshipState'];
+export type TruthClass = components['schemas']['ArchEdge']['truthClass'];
+export type ArchNode = components['schemas']['ArchNode'];
+export type ArchEvidence = components['schemas']['ArchEvidence'];
+export type ArchEdge = components['schemas']['ArchEdge'];
+export type ArchitectureDiagnostic = components['schemas']['ArchitectureDiagnostic'];
+export type ArchLayer = components['schemas']['ArchLayer'];
+export type ArchModule = components['schemas']['ArchModule'];
+export type RequestFlowStep = components['schemas']['RequestFlowStep'];
+export type ArchitectureSummary = components['schemas']['ArchitectureSummary'];
+
+// These fields have backend defaults, so the generated OpenAPI schema marks
+// them optional even though every successful response includes them.
+export type ArchitectureModel = components['schemas']['ArchitectureResponse'] &
+ Required>;
// 'complexity' and 'size' heatmap modes were removed with #217: no repository-
// intelligence producer measures either today, so there was no real signal to
// render. 'usage' (dependents count) and 'critical' are computed only from
// real graph facts.
export type HeatmapMode = 'none' | 'usage' | 'critical';
-
-export interface ArchNode {
- id: string;
- name: string;
- type: ArchNodeType;
- description: string;
- responsibilities: string[];
- files: string[];
- dependencies: string[];
- dependents: string[];
- // No producer measures complexity or line counts today (#217); 'not_computed'
- // is explicit and must never be synthesized from an unrelated real value
- // (e.g. file count).
- estimatedComplexity: 'low' | 'medium' | 'high' | 'not_computed';
- estimatedLines: number | 'not_computed';
- tags: string[];
- layer: string;
- parentModule?: string;
- relationshipState: RelationshipState;
-}
-
-export interface ArchEvidence {
- snapshotId: string;
- factId: string;
- path: string;
- startLine: number;
- endLine: number;
-}
-
-export interface ArchEdge {
- id: string;
- source: string;
- target: string;
- label?: string;
- type: ArchEdgeType;
- predicate: string;
- truthClass: TruthClass;
- evidence: ArchEvidence[];
-}
-
-export interface ArchitectureDiagnostic {
- code: string;
- category: string;
- severity: 'fatal' | 'error' | 'warning' | 'info';
- message: string;
- path?: string;
- startLine?: number;
- endLine?: number;
- subjectKey?: string;
- objectKey?: string;
- details?: Record;
- nodeIds?: string[];
-}
-
-export interface ArchLayer {
- id: string;
- name: string;
- order: number;
- nodes: string[];
-}
-
-export interface ArchModule {
- id: string;
- name: string;
- layer: string;
- nodeIds: string[];
- description: string;
- fileCount: number;
-}
-
-export interface RequestFlowStep {
- id: string;
- name: string;
- type: ArchNodeType;
- description: string;
- details: string[];
-}
-
-export interface ArchitectureModel {
- repositoryId: string;
- repositoryName: string;
- architectureType: string;
- detectedLayers: ArchLayer[];
- nodes: ArchNode[];
- edges: ArchEdge[];
- modules: ArchModule[];
- requestFlow: RequestFlowStep[];
- relationshipSnapshotId?: string;
- diagnostics: ArchitectureDiagnostic[];
- summary: {
- language: string;
- framework: string;
- totalModules: number;
- totalNodes: number;
- entryPoint: string;
- architecturePattern: string;
- };
-}
diff --git a/apps/frontend/src/shared/types/index.ts b/apps/frontend/src/shared/types/index.ts
index cb64bd5..17fd724 100644
--- a/apps/frontend/src/shared/types/index.ts
+++ b/apps/frontend/src/shared/types/index.ts
@@ -1,19 +1,11 @@
+import type { components } from '@/shared/services/api/generated';
+
export type AppStatus = 'empty' | 'repository-selected' | 'uploading' | 'analysing' | 'completed' | 'cancelled' | 'error';
export type RepositorySource = 'upload' | 'github';
export type FeatureStatus = 'idle' | 'loading' | 'success' | 'error' | 'empty';
-export type AnalysisStage =
- | 'uploading'
- | 'extracting'
- | 'reading-structure'
- | 'detecting-languages'
- | 'detecting-framework'
- | 'building-file-tree'
- | 'extracting-modules'
- | 'building-dependency-graph'
- | 'preparing-architecture'
- | 'completed';
+export type AnalysisStage = NonNullable;
export const ANALYSIS_STAGES: { key: AnalysisStage; label: string }[] = [
{ key: 'uploading', label: 'Uploading Repository' },
@@ -28,35 +20,9 @@ export const ANALYSIS_STAGES: { key: AnalysisStage; label: string }[] = [
{ key: 'completed', label: 'Analysis Complete' },
];
-export interface FileTreeNode {
- id: string;
- name: string;
- type: 'file' | 'folder';
- path: string;
- children?: FileTreeNode[];
- size?: number;
- extension?: string;
- language?: string;
-}
-
-export interface RepositoryMeta {
- language: string;
- framework: string;
- totalFiles: number;
- totalFolders: number;
- entryPoint: string | null;
- configFiles: string[];
- packageManager: string | null;
- hasReadme: boolean;
- hasLicense: boolean;
- licenseName: string | null;
-}
-
-export interface RepositoryRevision {
- kind: 'git' | 'upload';
- value: string;
- ref: string | null;
-}
+export type FileTreeNode = components['schemas']['FileTreeNode'];
+export type RepositoryMeta = components['schemas']['RepositoryMeta'];
+export type RepositoryRevision = components['schemas']['RepositoryRevision'];
export interface Repository {
id: string;
diff --git a/apps/frontend/src/shared/types/insights.ts b/apps/frontend/src/shared/types/insights.ts
index 3c8d230..74c8b8c 100644
--- a/apps/frontend/src/shared/types/insights.ts
+++ b/apps/frontend/src/shared/types/insights.ts
@@ -1,59 +1,15 @@
-export type InsightAssessmentState = 'assessed' | 'not_assessed' | 'insufficient_evidence';
-
-export interface InsightProvenance {
- source: 'ri.v1';
- snapshotId: string;
- snapshotSchemaVersion: string;
- canonicalGraphHash: string;
-}
-
-export interface InsightExtractor {
- name: string;
- version: string;
- evidenceRecordCount: number;
-}
-
-export interface InsightMetric {
- id: string;
- label: string;
- value: number | string | null;
- unit: string;
- definition: string;
- provenance: InsightProvenance;
- assessmentState: InsightAssessmentState;
- snapshotId: string;
- numerator: number | null;
- denominator: number | null;
-}
-
-export interface InsightBreakdown {
- key: string;
- label: string;
- value: number;
-}
-
-export interface RepositoryInsights {
- schemaVersion: 'repository-insights.v1';
- repositoryId: string;
- repositoryName: string;
- revisionKind: 'git' | 'upload';
- revisionValue: string;
- snapshotId: string;
- snapshotSchemaVersion: string;
- canonicalGraphHash: string;
- manifestDigest: string;
- provenance: InsightProvenance;
- computedAt: string;
- snapshotCreatedAt: string;
- snapshotSealedAt: string;
- extractorSet: InsightExtractor[];
- metrics: InsightMetric[];
- relationshipsByPredicate: InsightBreakdown[];
- diagnosticsBySeverity: InsightBreakdown[];
- diagnosticsByCode: InsightBreakdown[];
- languages: InsightBreakdown[];
- changeOverTime: {
- assessmentState: 'not_assessed';
- message: string;
- };
-}
+import type { components } from '@/shared/services/api/generated';
+
+export type InsightAssessmentState = components['schemas']['InsightMetric']['assessmentState'];
+export type InsightProvenance = components['schemas']['InsightProvenance'];
+export type InsightExtractor = components['schemas']['InsightExtractor'];
+export type InsightMetric = components['schemas']['InsightMetric'];
+export type InsightBreakdown = components['schemas']['InsightBreakdown'];
+
+export type RepositoryInsights = components['schemas']['RepositoryInsightsResponse'] & Required<
+ Pick<
+ components['schemas']['RepositoryInsightsResponse'],
+ 'changeOverTime' | 'extractorSet' | 'metrics' | 'relationshipsByPredicate' |
+ 'diagnosticsBySeverity' | 'diagnosticsByCode' | 'languages'
+ >
+>;
diff --git a/apps/frontend/src/shared/types/review.ts b/apps/frontend/src/shared/types/review.ts
index 66006aa..e4f127f 100644
--- a/apps/frontend/src/shared/types/review.ts
+++ b/apps/frontend/src/shared/types/review.ts
@@ -1,113 +1,15 @@
-export type ReviewSeverity = 'info' | 'low' | 'medium' | 'high' | 'critical';
-export type ReviewAssessmentState =
- | 'assessed'
- | 'partially_assessed'
- | 'not_assessed'
- | 'insufficient_evidence';
-
-export type ReviewCategory =
- | 'architecture_boundaries'
- | 'relationship_resolution'
- | 'source_extraction'
- | 'dependency_declarations'
- | 'security_vulnerability_scanning'
- | 'authentication_evidence'
- | 'repository_structure'
- | 'analysis_integrity';
-
-/**
- * How precisely a finding's evidence addresses its diagnostic.
- *
- * `supported` the reported lines are the diagnostic's own recorded span.
- * `file_scoped` the diagnostic named a file but no span, so the reported lines
- * cover the whole file rather than the exact defect.
- */
-export type ReviewSupportStatus = 'supported' | 'file_scoped';
-
-export interface ReviewProvenance {
- source: 'ri.v1';
- snapshotId: string;
- snapshotSchemaVersion: string;
- canonicalGraphHash: string;
-}
-
-export interface ReviewEvidenceReference {
- evidenceId: string;
- snapshotId: string;
- factId: string;
- path: string;
- startLine: number;
- endLine: number;
- extractorName: string;
- extractorVersion: string;
-}
-
-export interface ReviewFinding {
- id: string;
- category: ReviewCategory;
- severity: ReviewSeverity;
- title: string;
- explanation: string;
- path: string;
- startLine: number;
- endLine: number;
- snapshotId: string;
- factId: string;
- evidenceId: string;
- extractorName: string;
- extractorVersion: string;
- diagnosticCode: string;
- ruleId: string;
- remediationGuidance: string;
- supportStatus: ReviewSupportStatus;
- provenance: ReviewProvenance;
- evidence: ReviewEvidenceReference;
-}
-
-export interface ReviewCategoryAssessment {
- id: ReviewCategory;
- label: string;
- state: ReviewAssessmentState;
- explanation: string;
- findingCount: number;
-}
-
-export interface ReviewSeverityCounts {
- info: number;
- low: number;
- medium: number;
- high: number;
- critical: number;
-}
-
-export interface ReviewSummary {
- message: string;
- findingsBySeverity: ReviewSeverityCounts;
- assessedCategories: number;
- partiallyAssessedCategories: number;
- notAssessedCategories: number;
- insufficientEvidenceCategories: number;
- evidenceBackedFindingCount: number;
- /** Subset of evidenceBackedFindingCount scoped to a whole file, not a span. */
- fileScopedFindingCount: number;
- omittedUnsupportedDiagnosticCount: number;
- vulnerabilityScanning: 'not_assessed';
-}
-
-export interface EngineeringReview {
- schemaVersion: 'engineering-review.v2';
- repositoryId: string;
- repositoryName: string;
- revisionKind: 'git' | 'upload';
- revisionValue: string;
- snapshotId: string;
- snapshotSchemaVersion: string;
- canonicalGraphHash: string;
- manifestDigest: string;
- provenance: ReviewProvenance;
- generatedAt: string;
- assessmentStatus: ReviewAssessmentState;
- categories: ReviewCategoryAssessment[];
- findings: ReviewFinding[];
- summary: ReviewSummary;
-}
+import type { components } from '@/shared/services/api/generated';
+
+export type ReviewSeverity = components['schemas']['ReviewFinding']['severity'];
+export type ReviewAssessmentState = components['schemas']['ReviewCategoryAssessment']['state'];
+export type ReviewCategory = components['schemas']['ReviewCategoryAssessment']['id'];
+export type ReviewSupportStatus = components['schemas']['ReviewFinding']['supportStatus'];
+export type ReviewProvenance = components['schemas']['ReviewProvenance'];
+export type ReviewEvidenceReference = components['schemas']['ReviewEvidenceReference'];
+export type ReviewFinding = components['schemas']['ReviewFinding'];
+export type ReviewCategoryAssessment = components['schemas']['ReviewCategoryAssessment'];
+export type ReviewSeverityCounts = components['schemas']['ReviewSeverityCounts'];
+export type ReviewSummary = components['schemas']['ReviewSummary'];
+
+export type EngineeringReview = components['schemas']['EngineeringReviewResponse'] &
+ Required>;
diff --git a/package.json b/package.json
index cde1976..d62db84 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"partha:down": "docker compose down",
"dev:frontend": "npm --prefix apps/frontend run dev",
"build:frontend": "npm --prefix apps/frontend run build",
+ "generate:api-contract": "npm --prefix apps/frontend run generate:api-contract",
"preview:frontend": "npm --prefix apps/frontend run preview",
"lint:frontend": "npm --prefix apps/frontend run lint",
"test:backend": "node scripts/backend-python.mjs -m pytest",
diff --git a/scripts/generate-api-contract.mjs b/scripts/generate-api-contract.mjs
new file mode 100644
index 0000000..994cdc4
--- /dev/null
+++ b/scripts/generate-api-contract.mjs
@@ -0,0 +1,65 @@
+import { existsSync, readFileSync, writeFileSync } from 'node:fs';
+import { createRequire } from 'node:module';
+import { resolve } from 'node:path';
+import { spawnSync } from 'node:child_process';
+import { fileURLToPath } from 'node:url';
+
+const repoRoot = resolve(fileURLToPath(new URL('..', import.meta.url)));
+// The generator is kept at the repository root, while its tool dependency
+// belongs to the frontend workspace. Resolve from that workspace so this works
+// after `npm ci --prefix apps/frontend` in a clean CI checkout as well.
+const frontendRequire = createRequire(resolve(repoRoot, 'apps/frontend/package.json'));
+const { default: openapiTS, COMMENT_HEADER, astToString } = frontendRequire('openapi-typescript');
+const outputPath = resolve(repoRoot, 'apps/frontend/src/shared/services/api/generated.ts');
+const checkOnly = process.argv.includes('--check');
+
+function pythonExecutable() {
+ if (process.env.PARTHA_PYTHON) return process.env.PARTHA_PYTHON;
+ const venvPython = process.platform === 'win32'
+ ? resolve(repoRoot, 'apps/backend/.venv/Scripts/python.exe')
+ : resolve(repoRoot, 'apps/backend/.venv/bin/python');
+ return existsSync(venvPython) ? venvPython : (process.platform === 'win32' ? 'python' : 'python3');
+}
+
+function loadOpenApiDocument() {
+ const result = spawnSync(
+ pythonExecutable(),
+ ['-c', 'import json; from app.main import app; print(json.dumps(app.openapi(), separators=(",", ":")))'],
+ { cwd: resolve(repoRoot, 'apps/backend'), encoding: 'utf8' },
+ );
+
+ if (result.error) throw result.error;
+ if (result.status !== 0) {
+ throw new Error(`Backend OpenAPI generation failed:\n${result.stderr || result.stdout}`);
+ }
+ return JSON.parse(result.stdout);
+}
+
+function assertSafeGeneratedOutput(content) {
+ const environmentUrl = /https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|host\.docker\.internal)(?::\d+)?/i;
+ const embeddedSecret = /(?:api[_-]?key|password|secret|token)\s*[:=]\s*["'`][^"'`]+["'`]/i;
+ if (environmentUrl.test(content)) {
+ throw new Error('Generated API contract contains an environment-specific URL.');
+ }
+ if (embeddedSecret.test(content)) {
+ throw new Error('Generated API contract contains an embedded secret-like value.');
+ }
+}
+
+const document = loadOpenApiDocument();
+const contractBody = astToString(await openapiTS(document, { alphabetize: true })).replace(/\r?\n+$/, '');
+const generated = `${COMMENT_HEADER}// Source: apps/backend/app.main:app.openapi()\n// Generator: openapi-typescript@7.13.0\n\n${contractBody}\n`;
+assertSafeGeneratedOutput(generated);
+
+if (checkOnly) {
+ if (!existsSync(outputPath)) throw new Error(`Generated contract is missing: ${outputPath}`);
+ const current = readFileSync(outputPath, 'utf8');
+ if (current !== generated) {
+ const firstDifference = [...generated].findIndex((character, index) => current[index] !== character);
+ throw new Error(`Generated API contract is stale at character ${firstDifference}. Run \`npm run generate:api-contract\`.`);
+ }
+ console.log(`API contract is up to date: ${outputPath}`);
+} else {
+ writeFileSync(outputPath, generated, 'utf8');
+ console.log(`Generated API contract: ${outputPath}`);
+}