improvement(api): retire route contracts that no route serves - #7206
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Greptile SummaryRetires route metadata for operations that now execute in process while preserving their validation schemas, and adds an audit comparing declared contract methods with live route handlers.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| scripts/check-api-contract-routes.ts | Adds runtime contract discovery and route-method comparison, including exact and catch-all route resolution. |
| apps/sim/lib/api/contracts/knowledge/documents.ts | Replaces the retired document-creation route contract with standalone request and response schemas. |
| apps/sim/lib/internal/knowledge/execute-tool.ts | Updates in-process knowledge document creation to validate directly against standalone schemas. |
| apps/sim/lib/internal/confluence/execute-tool.ts | Generalizes schema-based input parsing for retired Confluence update and delete routes. |
| apps/sim/lib/internal/tool-operations/parse-contract-input.ts | Adds a schema-bundle parsing entry point while retaining contract-specific type inference. |
| apps/sim/lib/api/contracts/types.ts | Documents boundary and in-process contract consumption modes. |
| package.json | Registers the new API contract route audit. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Contract modules] --> B[Import exported contract objects]
B --> C[Resolve exact or catch-all route]
C --> D[Read exported HTTP methods]
D --> E{Declared method served?}
E -->|Yes| F[Audit passes entry]
E -->|No| G[Report stale route declaration]
H[Retired in-process operation] --> I[Plain Zod schemas]
I --> J[Internal tool executor]
Reviews (2): Last reviewed commit: "fix(api): read contracts by import, and ..." | Re-trigger Greptile
The staging integ alarm fired because the session knowledge-document inline-create check got a 405. #7179 moved tool operations in process and deleted the routes that only existed to serve them, but `createKnowledgeDocumentsContract` kept declaring `POST /api/knowledge/[id]/documents` — a path whose surviving GET/PATCH make Next.js answer POST with 405 rather than an honest 404. Nothing in the repo called it: the KB UI creates documents through the presigned upload flow, and the capability itself is unaffected because `knowledge_create_document` reaches the same use case in process. Audited all 1125 contracts for the same drift. It was the only one whose path resolves to a live route missing the declared method; 259 others declare paths of routes that were deleted outright, which 404 honestly and are left alone. - Drop the create-documents route contract for plain `params`/`body` schemas plus a named response schema, so nothing declares an endpoint we do not serve. The schemas stay in the contracts tree next to the siblings they share (`documentDataSchema` is used by the v2 contracts, and `createKnowledgeDocumentsBodySchema` already backed the in-process operation). - Delete four contracts with no consumer at all — both TTS contracts, docusign, and mistral. Their handlers own better schemas: TTS dispatches by `toolId` with eight per-provider schemas instead of one passthrough superset, and mistral bounds `pages` by the OCR request policy. crowdstrike and windchill look similar but are load-bearing (schema and derived types are imported by live code), so they stay. - Add `check:api-contract-routes`, picked up automatically by `run-audits`. `check:route-verbs` scans routes to contracts, so a contract whose route method was deleted is invisible to it — verified it passes clean against the exact regression this catches. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tions Greptile flagged the audit's brace counter as blind to braces inside strings, template literals, regexes and comments. It was, but the bigger problem was that a text scan can only see contracts whose `method`/`path` are inline literals — the 70-plus built through `definePostSelector(path, …)` and friends were never checked at all. Comparing raw `defineRouteContract(` occurrences against parsed ones showed the scanner silently skipping declarations. Read the contracts by importing each contract module and inspecting its exported objects instead, the way `check-route-verbs.ts` already resolves the contract behind a route. Contract modules are pure Zod so importing them is safe; route files stay a static scan because importing one drags in `@sim/db`, auth and `next/server`. Barrels re-export the same object, so entries are keyed by identity. Coverage goes from 1125 contracts to 1283. That immediately surfaced two more instances of exactly what this PR retires. `/api/tools/confluence/page` kept its `PUT` and `DELETE` contracts after #7179 reduced the route to the selector `POST`, so both declared verbs the live route answers with 405. Neither is fetched — `lib/internal/confluence/execute-tool.ts` is the only consumer — so they become plain schemas like the knowledge one, and `executeOperation` now delegates to a schema form rather than growing a second pattern beside it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
icecrasher321
force-pushed
the
fix/retire-orphaned-route-contracts
branch
from
August 28, 2026 07:47
a5b06c6 to
1bf6017
Compare
Collaborator
Author
Collaborator
Author
|
@cubic review |
@icecrasher321 I have started the AI code review. It will take a few minutes to complete. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The staging
integ-failurealarm fired becauseinteg-session-kb-document-lifecycle/create-document-from-inline-contentgot HTTP 405 instead of 200.Root cause: #7179 moved tool operations in process and deleted the routes that only existed to serve them, but
createKnowledgeDocumentsContractkept declaringPOST /api/knowledge/[id]/documents. The survivingGET/PATCHon that path make Next.js answerPOSTwith 405 rather than an honest 404 — which reads as "wrong verb, endpoint is fine" and sends the caller looking in the wrong place.Nothing in the repo called that endpoint: the KB UI creates documents through the presigned upload flow, and no SDK, desktop, docs, or client fetch references it. The capability is unaffected either way —
knowledge_create_documentis a shipped tool that reaches the same use case in process. So this retires the declaration rather than restoring the route.Audit
Checked all 1125 contracts for the same drift. The knowledge one was the only contract whose path resolves to a live route missing its declared method. 259 others declare paths of routes deleted outright — those 404 honestly and are left alone.
Changes
params/bodyschemas plus a named response schema, so nothing declares an endpoint we don't serve. Schemas stay in the contracts tree beside the siblings they share (documentDataSchemais used by the v2 contracts;createKnowledgeDocumentsBodySchemaalready backed the in-process operation).toolIdacross 8 per-provider schemas instead of one.passthrough()superset covering 7 providers, and mistral boundspagesby the OCR request policy. This removes duplication rather than creating it.crowdstrikeQueryBodySchemais parsed bylib/internal/crowdstrike/execute-tool.ts,windchillOperationResponseSchemabytools/windchill/utils.ts, plus derived types across both.check:api-contract-routes, auto-discovered byrun-audits. Also documents the two contract consumption modes onApiRouteContract, with membership derived (--list-in-process) rather than annotated per file.Why the new audit isn't redundant with
check:route-verbscheck-route-verbsscans routes → contracts, so a contract whose route method was deleted is invisible to it. Verified against the exact regression state:check:route-verbspasses clean (359 handlers) while the new check fails with the precise diagnosis.Not in scope
The repo is split on where in-process schemas live — 54
lib/internaldomains declare them inline, 36 import from contracts, 18 are mixed. Converging on the contracts tree is worth doing but is a 54-domain migration, not this PR. Nothing here makes that split worse: the four deletions each removed a dead duplicate, leaving one source of truth.Testing
bunx turbo run type-check— cleanbun run lint:check— cleanbun run check:audits— 38/38 pass, including the new audit🤖 Generated with Claude Code