Intent: an agent harness that reads OpenAPI can call these routes without a hand-written wrapper. Today src/contract/openapi.ts has no row for them.
Done:
[ ] src/contract/openapi.ts has one row each for: GET /api/v1/openapi.json, POST /api/v1/migrate, GET /api/v1/migrate/{job} and its /stream (an event stream: the row says so), and GET {REPO}/app/{env}/open. Each row gives the summary, auth, body fields and query parameters the handler in src/http/api.ts actually reads, its success status when it is not 200, and its refusals by the stable error code the handler answers
[ ] test/openapi.test.ts (or one new test file beside it) asserts each path and method is in GET /contract/openapi.json, and that one refusal code per row matches what the route answers
[ ] the routes themselves are unchanged
Files: src/contract/openapi.ts and one test. Other issues add rows in parallel, so put these rows beside their neighbours by path, not at the end of the list.
Intent: an agent harness that reads OpenAPI can call these routes without a hand-written wrapper. Today src/contract/openapi.ts has no row for them.
Done:
auth, body fields and query parameters the handler in src/http/api.ts actually reads, its success status when it is not 200, and its refusals by the stableerrorcode the handler answersFiles: src/contract/openapi.ts and one test. Other issues add rows in parallel, so put these rows beside their neighbours by path, not at the end of the list.