Context
src/review/finding-taxonomy.ts and src/review/enrichment-analyzers-taxonomy.ts each build a small, static, read-only JSON document:
buildFindingTaxonomyDocument() (src/review/finding-taxonomy.ts:13) returns the canonical AI-review finding categories + severities ladder, keyed to FINDING_TAXONOMY_URI = "loopover://finding-taxonomy" (src/review/finding-taxonomy.ts:5).
buildEnrichmentAnalyzersTaxonomyDocument() (src/review/enrichment-analyzers-taxonomy.ts:29) returns the REES enrichment analyzer taxonomy (name/category/cost class/profiles), keyed to ENRICHMENT_ANALYZERS_URI = "gittensory://enrichment-analyzers" (src/review/enrichment-analyzers-taxonomy.ts:4).
Both are registered as MCP resources in src/mcp/server.ts (server.registerResource("loopover_finding_taxonomy", FINDING_TAXONOMY_URI, ...) and server.registerResource("loopover_enrichment_analyzers", ENRICHMENT_ANALYZERS_URI, ...), around lines 2816-2854) — but neither has a REST mirror in src/api/routes.ts (a 6000+ line file that otherwise exposes essentially every other piece of review/registry/scoring data over /v1/*, e.g. /v1/registry/snapshot, /v1/scoring/model, /v1/upstream/ruleset). A caller without MCP access (a plain HTTP client, a dashboard, a non-MCP integration) currently has no way to fetch either taxonomy.
Both builder functions are pure, take no arguments, require no auth beyond what every other public /v1/* read route already requires, and return no PR/user/private data — they are static discovery documents (categories, severities, analyzer metadata), the same class of data as the already-public /v1/registry/snapshot and /v1/upstream/ruleset routes.
Requirements
- Add
GET /v1/finding-taxonomy to src/api/routes.ts that returns buildFindingTaxonomyDocument() (imported from src/review/finding-taxonomy.ts) as JSON, following the exact same handler shape as the existing app.get("/v1/scoring/model", async (c) => c.json(await getOrCreateScoringModelSnapshot(c.env))); route (no request body, no params, plain c.json(...)).
- Add
GET /v1/enrichment-analyzers to src/api/routes.ts that returns buildEnrichmentAnalyzersTaxonomyDocument() (imported from src/review/enrichment-analyzers-taxonomy.ts) as JSON, same handler shape.
- Both new routes MUST be registered in
src/openapi/spec.ts so spec.paths["/v1/finding-taxonomy"] and spec.paths["/v1/enrichment-analyzers"] are defined — test/unit/openapi.test.ts asserts specific paths exist in buildOpenApiSpec(), and npm run ui:openapi:check / npm run ui:openapi:settings-parity gate on the spec staying in sync with apps/loopover-ui/public/openapi.json. Do not add a route without a matching OpenAPI path entry.
- Do NOT change the existing MCP resource registrations in
src/mcp/server.ts — this is an additive REST mirror, not a replacement. FINDING_TAXONOMY_URI and ENRICHMENT_ANALYZERS_URI stay MCP-only identifiers; the new REST routes are plain /v1/... paths, not those URIs.
- Both new routes must be unauthenticated GET routes consistent with the other public static-data routes in the same file (
/v1/registry/snapshot, /v1/upstream/ruleset, /v1/scoring/model) — do not add new auth middleware for these two routes.
Deliverables
Test Coverage Requirements
This repo's Codecov patch gate is 99%+, hard, for src/**/packages/**. Both touched files (src/api/routes.ts, src/openapi/spec.ts) are under src/, so the gate applies in full. Add:
- A test (in the existing routes/API test suite, e.g. alongside other
/v1/* route tests) asserting GET /v1/finding-taxonomy returns 200 with a body matching buildFindingTaxonomyDocument()'s shape (categories, severities arrays).
- A test asserting
GET /v1/enrichment-analyzers returns 200 with a body matching buildEnrichmentAnalyzersTaxonomyDocument()'s shape (defaultProfile, analyzers array).
- Extend
test/unit/openapi.test.ts's existing spec.paths[...] assertion list with the two new paths (mirroring how every other route in that file is asserted).
Expected Outcome
GET /v1/finding-taxonomy and GET /v1/enrichment-analyzers return the same JSON documents already available via the loopover://finding-taxonomy and gittensory://enrichment-analyzers MCP resources, so any plain HTTP client (not just MCP-capable ones) can discover the review finding taxonomy and REES analyzer metadata. The OpenAPI spec and its parity checks stay green.
Links & Resources
Context
src/review/finding-taxonomy.tsandsrc/review/enrichment-analyzers-taxonomy.tseach build a small, static, read-only JSON document:buildFindingTaxonomyDocument()(src/review/finding-taxonomy.ts:13) returns the canonical AI-review findingcategories+severitiesladder, keyed toFINDING_TAXONOMY_URI = "loopover://finding-taxonomy"(src/review/finding-taxonomy.ts:5).buildEnrichmentAnalyzersTaxonomyDocument()(src/review/enrichment-analyzers-taxonomy.ts:29) returns the REES enrichment analyzer taxonomy (name/category/cost class/profiles), keyed toENRICHMENT_ANALYZERS_URI = "gittensory://enrichment-analyzers"(src/review/enrichment-analyzers-taxonomy.ts:4).Both are registered as MCP resources in
src/mcp/server.ts(server.registerResource("loopover_finding_taxonomy", FINDING_TAXONOMY_URI, ...)andserver.registerResource("loopover_enrichment_analyzers", ENRICHMENT_ANALYZERS_URI, ...), around lines 2816-2854) — but neither has a REST mirror insrc/api/routes.ts(a 6000+ line file that otherwise exposes essentially every other piece of review/registry/scoring data over/v1/*, e.g./v1/registry/snapshot,/v1/scoring/model,/v1/upstream/ruleset). A caller without MCP access (a plain HTTP client, a dashboard, a non-MCP integration) currently has no way to fetch either taxonomy.Both builder functions are pure, take no arguments, require no auth beyond what every other public
/v1/*read route already requires, and return no PR/user/private data — they are static discovery documents (categories, severities, analyzer metadata), the same class of data as the already-public/v1/registry/snapshotand/v1/upstream/rulesetroutes.Requirements
GET /v1/finding-taxonomytosrc/api/routes.tsthat returnsbuildFindingTaxonomyDocument()(imported fromsrc/review/finding-taxonomy.ts) as JSON, following the exact same handler shape as the existingapp.get("/v1/scoring/model", async (c) => c.json(await getOrCreateScoringModelSnapshot(c.env)));route (no request body, no params, plainc.json(...)).GET /v1/enrichment-analyzerstosrc/api/routes.tsthat returnsbuildEnrichmentAnalyzersTaxonomyDocument()(imported fromsrc/review/enrichment-analyzers-taxonomy.ts) as JSON, same handler shape.src/openapi/spec.tssospec.paths["/v1/finding-taxonomy"]andspec.paths["/v1/enrichment-analyzers"]are defined —test/unit/openapi.test.tsasserts specific paths exist inbuildOpenApiSpec(), andnpm run ui:openapi:check/npm run ui:openapi:settings-paritygate on the spec staying in sync withapps/loopover-ui/public/openapi.json. Do not add a route without a matching OpenAPI path entry.src/mcp/server.ts— this is an additive REST mirror, not a replacement.FINDING_TAXONOMY_URIandENRICHMENT_ANALYZERS_URIstay MCP-only identifiers; the new REST routes are plain/v1/...paths, not those URIs./v1/registry/snapshot,/v1/upstream/ruleset,/v1/scoring/model) — do not add new auth middleware for these two routes.Deliverables
app.get("/v1/finding-taxonomy", ...)added tosrc/api/routes.ts, returningbuildFindingTaxonomyDocument().app.get("/v1/enrichment-analyzers", ...)added tosrc/api/routes.ts, returningbuildEnrichmentAnalyzersTaxonomyDocument().src/openapi/spec.tsupdated with path entries for both new routes.Test Coverage Requirements
This repo's Codecov patch gate is 99%+, hard, for
src/**/packages/**. Both touched files (src/api/routes.ts,src/openapi/spec.ts) are undersrc/, so the gate applies in full. Add:/v1/*route tests) assertingGET /v1/finding-taxonomyreturns 200 with a body matchingbuildFindingTaxonomyDocument()'s shape (categories,severitiesarrays).GET /v1/enrichment-analyzersreturns 200 with a body matchingbuildEnrichmentAnalyzersTaxonomyDocument()'s shape (defaultProfile,analyzersarray).test/unit/openapi.test.ts's existingspec.paths[...]assertion list with the two new paths (mirroring how every other route in that file is asserted).Expected Outcome
GET /v1/finding-taxonomyandGET /v1/enrichment-analyzersreturn the same JSON documents already available via theloopover://finding-taxonomyandgittensory://enrichment-analyzersMCP resources, so any plain HTTP client (not just MCP-capable ones) can discover the review finding taxonomy and REES analyzer metadata. The OpenAPI spec and its parity checks stay green.Links & Resources
src/review/finding-taxonomy.ts,src/review/enrichment-analyzers-taxonomy.ts(the existing pure builders)src/mcp/server.ts(existing MCP resource registrations, ~lines 2816-2854)src/api/routes.ts(target file for the new routes; see/v1/registry/snapshotand/v1/scoring/modelfor the pattern to follow)src/openapi/spec.ts,test/unit/openapi.test.ts(OpenAPI parity requirement)loopover_finding_taxonomyMCP resource), feat(mcp): register a gittensory://enrichment-analyzers resource from REES analyzer metadata #2226 (registered theloopover_enrichment_analyzersMCP resource) — both MCP-only, never given a REST counterpart.