Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions .agents/skills/verify-interface/features/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ One file per feature. `covers:` lists the source files its journeys exercise, pl
| [types](types.md) | A TypeScript author compiles against the packed declarations. | declared-shapes |
| [smoke](smoke.md) | The fixed journeys every verdict runs. | core-calls, export-surface |

## Known findings

| Finding | Page | Issue |
|---|---|---|
| `@Get("")` registers the location `/users/` with a trailing slash, where the docs say it registers the controller root | `docs/2.controllers.md` | AntelopeJS/interface-api#75 |
| `@Connection` is documented as valid only on a `@WebsocketHandler` handler, and nothing enforces it | `docs/4.parameters.md` | AntelopeJS/interface-api#76 |

No journey pins either behaviour as correct.

## Not driven

The interface holds the contract and the decorators; `@antelopejs/api` serves requests. A journey here drives the packed interface next to a stub provider, with fake requests, or through real legacy decorators, so these documented behaviours are not driven, each with its reason.
Expand Down
3 changes: 1 addition & 2 deletions .agents/skills/verify-interface/features/routes.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ A module author maps a controller method to an endpoint with `@Get`, `@Post`, `@

## Sub-features

- `route-locations`: the HTTP method, handler mode, full location (method name when omitted, repeated slashes collapsed) and priority each decorator registers, and that the decorator returns nothing a class can see.
- `route-locations`: the HTTP method, handler mode, full location (method name when omitted, the controller root with no trailing slash for `@Get("")`, repeated slashes collapsed) and priority each decorator registers, and that the decorator returns nothing a class can see.
- `route-errors`: a class `Controller` did not build, a descriptor with no method and a symbol key with no location each throw a `TypeError` with the documented message, and nothing is registered.

## How to get to it (user POV)
Expand All @@ -35,5 +35,4 @@ pnpm exec antelopejs-verify journey "$RUN" routes

## Gotchas

- `docs/2.controllers.md` says `@Get("")` registers the controller root, but the registered location carries a trailing slash (`/users/`). That is a known finding (AntelopeJS/interface-api#75). The journey strips one trailing slash before comparing, so it pins neither form.
- The symbol key case is undocumented in `docs/`; it is a check of the TypeError the code raises.
2 changes: 1 addition & 1 deletion .agents/skills/verify-interface/scenarios-second.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const SECOND_SCENARIOS = {
printed: "{\"plain\":[\"TypeError\",\"Route decorators apply to Controller classes; Plain has no location\"],\"novalue\":[\"TypeError\",\"Route decorators apply to methods; nov has no value\"],\"symbol\":[\"TypeError\",\"Route decorators on a symbol-keyed method need a location; Users[Symbol(s)] has none\"],\"noController\":[\"TypeError\",\"Cannot register GET /q: RouteHandler.controller is required\"],\"none\":0}",
},
"route-locations": {
body: "class Users extends a.Controller(\"/users\") {}\ndeco(a.Get(), Users, \"listUsers\"); deco(a.Get(\"\"), Users, \"root\"); deco(a.Get(\":id\"), Users, \"one\"); deco(a.Get(\"//a//b\"), Users, \"slashes\");\ndeco(a.Post(\"p\"), Users, \"p1\"); deco(a.Put(\"u\"), Users, \"p2\"); deco(a.Delete(\"d\"), Users, \"p3\");\ndeco(a.Get(\"pm\", \"prefix\"), Users, \"pm\"); deco(a.Prefix(\"get\", \"x\", a.HandlerPriority.HIGHEST), Users, \"pre\"); deco(a.Postfix(\"get\", \"x\"), Users, \"post\"); deco(a.Monitor(\"get\", \"x\", 3), Users, \"mon\"); deco(a.WebsocketHandler(\"ws\"), Users, \"sock\"); deco(a.Route(\"handler\", \"patch\", \"r\", 1), Users, \"rt\");\nR.routes = a.getRegisteredRouteHandlers().map((r) => [r.handler.mode, r.handler.method, r.handler.location.replace(/\\/$/, \"\"), r.handler.callback.name, r.handler.priority ?? null]);\nconst out = deco(a.Get(\"ret\"), Users, \"ret\"); R.returned = [out === undefined];\ndeco(a.Post(\"m1\", \"prefix\"), Users, \"postPrefix\"); deco(a.Put(\"m2\", \"postfix\"), Users, \"putPostfix\"); deco(a.Delete(\"m3\", \"monitor\"), Users, \"deleteMonitor\");\ndeco(a.Postfix(\"get\", \"y\", a.HandlerPriority.HIGH), Users, \"postfixHigh\"); deco(a.Prefix(\"get\", \"y\", a.HandlerPriority.LOW), Users, \"prefixLow\"); deco(a.Monitor(\"get\", \"y\"), Users, \"monitorDefault\");\nR.modes = [\"postPrefix\", \"putPostfix\", \"deleteMonitor\", \"postfixHigh\", \"prefixLow\", \"monitorDefault\"].map((name) => { const h = a.getRegisteredRouteHandlers().find((r) => r.handler.callback.name === name).handler; return [name, h.mode, h.method, h.priority ?? null]; });\na.Parameter(\"id\")(Users.prototype, \"withParam\", 1); a.Parameter(\"authorization\", \"header\")(Users.prototype, \"ownerToken\");\ndeco(a.Get(\"wp\"), Users, \"withParam\");\nconst wp = a.getRegisteredRoutes().find((r) => r.callbackName === \"withParam\");\nR.computed = [wp.parameters.map((p) => (p === null ? null : \"computed\")), Object.keys(wp.properties)];\nconst pc = a.ProcessCallback(Users.prototype, \"viaProcess\", { value: named(\"viaProcess\") }, \"handler\", \"get\", \"pc\", a.HandlerPriority.LOW);\nconst pcRoute = a.getRegisteredRoutes().find((r) => r.callbackName === \"viaProcess\");\nR.processCallback = [Object.keys(pc), typeof pc.id, String(pc.id) === pcRoute.id, pcRoute.location, pcRoute.priority];\nconst before = a.getRegisteredRoutes().length; a.UnregisterRoute(pc.id); R.processUnregister = before - a.getRegisteredRoutes().length;\nclass Bare extends a.Controller(\"/bare\") {}\ndeco(a.Prefix(\"get\"), Bare, \"pfx\"); deco(a.Postfix(\"get\"), Bare, \"psx\"); deco(a.Monitor(\"get\"), Bare, \"mon\"); deco(a.WebsocketHandler(), Bare, \"sock\"); deco(a.Delete(), Bare, \"del\"); deco(a.Post(), Bare, \"pst\"); deco(a.Put(), Bare, \"put\");\nR.omitted = a.getRegisteredRouteHandlers().filter((r) => r.handler.controller === Bare).map((r) => [r.handler.mode, r.handler.method, r.handler.location]);\n",
body: "class Users extends a.Controller(\"/users\") {}\ndeco(a.Get(), Users, \"listUsers\"); deco(a.Get(\"\"), Users, \"root\"); deco(a.Get(\":id\"), Users, \"one\"); deco(a.Get(\"//a//b\"), Users, \"slashes\");\ndeco(a.Post(\"p\"), Users, \"p1\"); deco(a.Put(\"u\"), Users, \"p2\"); deco(a.Delete(\"d\"), Users, \"p3\");\ndeco(a.Get(\"pm\", \"prefix\"), Users, \"pm\"); deco(a.Prefix(\"get\", \"x\", a.HandlerPriority.HIGHEST), Users, \"pre\"); deco(a.Postfix(\"get\", \"x\"), Users, \"post\"); deco(a.Monitor(\"get\", \"x\", 3), Users, \"mon\"); deco(a.WebsocketHandler(\"ws\"), Users, \"sock\"); deco(a.Route(\"handler\", \"patch\", \"r\", 1), Users, \"rt\");\nR.routes = a.getRegisteredRouteHandlers().map((r) => [r.handler.mode, r.handler.method, r.handler.location, r.handler.callback.name, r.handler.priority ?? null]);\nconst out = deco(a.Get(\"ret\"), Users, \"ret\"); R.returned = [out === undefined];\ndeco(a.Post(\"m1\", \"prefix\"), Users, \"postPrefix\"); deco(a.Put(\"m2\", \"postfix\"), Users, \"putPostfix\"); deco(a.Delete(\"m3\", \"monitor\"), Users, \"deleteMonitor\");\ndeco(a.Postfix(\"get\", \"y\", a.HandlerPriority.HIGH), Users, \"postfixHigh\"); deco(a.Prefix(\"get\", \"y\", a.HandlerPriority.LOW), Users, \"prefixLow\"); deco(a.Monitor(\"get\", \"y\"), Users, \"monitorDefault\");\nR.modes = [\"postPrefix\", \"putPostfix\", \"deleteMonitor\", \"postfixHigh\", \"prefixLow\", \"monitorDefault\"].map((name) => { const h = a.getRegisteredRouteHandlers().find((r) => r.handler.callback.name === name).handler; return [name, h.mode, h.method, h.priority ?? null]; });\na.Parameter(\"id\")(Users.prototype, \"withParam\", 1); a.Parameter(\"authorization\", \"header\")(Users.prototype, \"ownerToken\");\ndeco(a.Get(\"wp\"), Users, \"withParam\");\nconst wp = a.getRegisteredRoutes().find((r) => r.callbackName === \"withParam\");\nR.computed = [wp.parameters.map((p) => (p === null ? null : \"computed\")), Object.keys(wp.properties)];\nconst pc = a.ProcessCallback(Users.prototype, \"viaProcess\", { value: named(\"viaProcess\") }, \"handler\", \"get\", \"pc\", a.HandlerPriority.LOW);\nconst pcRoute = a.getRegisteredRoutes().find((r) => r.callbackName === \"viaProcess\");\nR.processCallback = [Object.keys(pc), typeof pc.id, String(pc.id) === pcRoute.id, pcRoute.location, pcRoute.priority];\nconst before = a.getRegisteredRoutes().length; a.UnregisterRoute(pc.id); R.processUnregister = before - a.getRegisteredRoutes().length;\nclass Bare extends a.Controller(\"/bare\") {}\ndeco(a.Prefix(\"get\"), Bare, \"pfx\"); deco(a.Postfix(\"get\"), Bare, \"psx\"); deco(a.Monitor(\"get\"), Bare, \"mon\"); deco(a.WebsocketHandler(), Bare, \"sock\"); deco(a.Delete(), Bare, \"del\"); deco(a.Post(), Bare, \"pst\"); deco(a.Put(), Bare, \"put\");\nR.omitted = a.getRegisteredRouteHandlers().filter((r) => r.handler.controller === Bare).map((r) => [r.handler.mode, r.handler.method, r.handler.location]);\n",
printed: "{\"routes\":[[\"handler\",\"get\",\"/users/listUsers\",\"listUsers\",null],[\"handler\",\"get\",\"/users\",\"root\",null],[\"handler\",\"get\",\"/users/:id\",\"one\",null],[\"handler\",\"get\",\"/users/a/b\",\"slashes\",null],[\"handler\",\"post\",\"/users/p\",\"p1\",null],[\"handler\",\"put\",\"/users/u\",\"p2\",null],[\"handler\",\"delete\",\"/users/d\",\"p3\",null],[\"prefix\",\"get\",\"/users/pm\",\"pm\",null],[\"prefix\",\"get\",\"/users/x\",\"pre\",0],[\"postfix\",\"get\",\"/users/x\",\"post\",null],[\"monitor\",\"get\",\"/users/x\",\"mon\",3],[\"websocket\",\"get\",\"/users/ws\",\"sock\",null],[\"handler\",\"patch\",\"/users/r\",\"rt\",1]],\"returned\":[true],\"modes\":[[\"postPrefix\",\"prefix\",\"post\",null],[\"putPostfix\",\"postfix\",\"put\",null],[\"deleteMonitor\",\"monitor\",\"delete\",null],[\"postfixHigh\",\"postfix\",\"get\",1],[\"prefixLow\",\"prefix\",\"get\",3],[\"monitorDefault\",\"monitor\",\"get\",null]],\"computed\":[[null,\"computed\"],[\"ownerToken\"]],\"processCallback\":[[\"id\"],\"number\",true,\"/users/pc\",3],\"processUnregister\":1,\"omitted\":[[\"prefix\",\"get\",\"/bare/pfx\"],[\"postfix\",\"get\",\"/bare/psx\"],[\"monitor\",\"get\",\"/bare/mon\"],[\"websocket\",\"get\",\"/bare/sock\"],[\"handler\",\"delete\",\"/bare/del\"],[\"handler\",\"post\",\"/bare/pst\"],[\"handler\",\"put\",\"/bare/put\"]]}",
},
"sources": {
Expand Down
Loading