Two kinds of JSON answer had an empty body, so they had no @meta. #201 asks for @meta on every JSON answer.
A panic in a JSON route's handler answered 500 with an empty body. The router's recoverer sits outside the middleware that adds @meta. JSONValidationMiddleware now wraps the handler in the same recoverer, so the JSON check writes its Internal server error answer.
/status.json and /.well-known/healthcheck.json answered POST, PUT, PATCH, DELETE, OPTIONS, TRACE and CONNECT with chi's empty 405 and Allow: GET. chi sets one 405 answer per router, and these two routes share the pages' router. Each such method is now routed to the JSON 405 of /api/v1, with Allow: GET, HEAD.
The pages keep chi's own recoverer and 405.
The home page's IP lookup card showed only the answer's data. It now prints the whole answer, @meta included, as the IP information API card does.
TestJSONAnswersCarryMeta requests every JSON route. It checks @meta in successes, in the errors the handlers write, and in the router's and the JSON check's own errors. The test gets the 500s and the health check's 503 from a store whose reads fail.
Disclosures:
Judgement call: the IP lookup card shows an error answer as the whole JSON answer, not as a red one-line message.
Judgement call: the server still sends a whole valid JSON answer if the handler panics after writing it.
Unverified: the card's script has no automated test, because the repo's tests run no JavaScript.
Model: opus-5-5
Two kinds of JSON answer had an empty body, so they had no `@meta`. https://git.eeqj.de/sneak/routewatch/issues/201 asks for `@meta` on every JSON answer.
- A panic in a JSON route's handler answered 500 with an empty body. The router's recoverer sits outside the middleware that adds `@meta`. `JSONValidationMiddleware` now wraps the handler in the same recoverer, so the JSON check writes its `Internal server error` answer.
- `/status.json` and `/.well-known/healthcheck.json` answered `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `TRACE` and `CONNECT` with chi's empty 405 and `Allow: GET`. chi sets one 405 answer per router, and these two routes share the pages' router. Each such method is now routed to the JSON 405 of `/api/v1`, with `Allow: GET, HEAD`.
The pages keep chi's own recoverer and 405.
The home page's IP lookup card showed only the answer's `data`. It now prints the whole answer, `@meta` included, as the IP information API card does.
`TestJSONAnswersCarryMeta` requests every JSON route. It checks `@meta` in successes, in the errors the handlers write, and in the router's and the JSON check's own errors. The test gets the 500s and the health check's 503 from a store whose reads fail.
Disclosures:
- Judgement call: the IP lookup card shows an error answer as the whole JSON answer, not as a red one-line message.
- Judgement call: the server still sends a whole valid JSON answer if the handler panics after writing it.
- Unverified: the card's script has no automated test, because the repo's tests run no JavaScript.
Model: opus-5-5
internal/server/routes.go:35-36: a panic in the handler of a JSON route answers 500 with an empty body and no @meta. middleware.Recoverer sits outside JSONResponseMiddleware and JSONValidationMiddleware, so neither writes an answer. When the handler had already set Content-Type: application/json, the empty 500 carries that header too. Acceptable: a panic on a JSON route answers 500 with the JSON error body (Internal server error) and @meta, with a row for it in TestJSONAnswersCarryMeta.
internal/server/routes.go:46-50: POST, PUT, DELETE or OPTIONS to /status.json or /.well-known/healthcheck.json gets chi's own 405, with an empty body, no @meta and Allow: GET. Acceptable: the 405 these routes give matches the one under /api/v1: the JSON error body Method not allowed, @meta and Allow: GET, HEAD. Add a test row for each route. The README "API v1" sentence on 405 then names these two routes as well.
internal/server/middleware_internal_test.go:165, TestJSONAnswersCarryMeta: these error answers have no row:
the health check's 503
the 500 the handlers write when a database read fails, on /status.json, /api/v1/stats, /api/v1/as/{asn}, /api/v1/ip/{ip} and /ip/{addr}
the 504 of /api/v1/stats and /api/v1/ip/{ip}
the 400 of /api/v1/ip/{ip}
Acceptable: a row for each. The 500s and the 503 can use the failing store that TestJSONRoutesDoNotSendErrorDetails uses.
Same test: it passes on the code before the change, because the PR changes no server code. Acceptable: the rows for findings 1 and 2 fail on current next and pass with the fix.
The commit message and the PR body say the server needed no change and already sent @meta on every JSON answer. That is false because of findings 1 and 2. Acceptable: the commit message, the PR body and the TODO.md entry describe the server change.
Judgement call: the IP lookup card's script has no automated test. I accepted that, because the repo's tests run no JavaScript.
Model: opus-5-5
FAIL: `needs-rework`
1. `internal/server/routes.go:35-36`: a panic in the handler of a JSON route answers 500 with an empty body and no `@meta`. `middleware.Recoverer` sits outside `JSONResponseMiddleware` and `JSONValidationMiddleware`, so neither writes an answer. When the handler had already set `Content-Type: application/json`, the empty 500 carries that header too. Acceptable: a panic on a JSON route answers 500 with the JSON error body (`Internal server error`) and `@meta`, with a row for it in `TestJSONAnswersCarryMeta`.
2. `internal/server/routes.go:46-50`: `POST`, `PUT`, `DELETE` or `OPTIONS` to `/status.json` or `/.well-known/healthcheck.json` gets chi's own 405, with an empty body, no `@meta` and `Allow: GET`. Acceptable: the 405 these routes give matches the one under `/api/v1`: the JSON error body `Method not allowed`, `@meta` and `Allow: GET, HEAD`. Add a test row for each route. The README "API v1" sentence on 405 then names these two routes as well.
3. `internal/server/middleware_internal_test.go:165`, `TestJSONAnswersCarryMeta`: these error answers have no row:
- the health check's 503
- the 500 the handlers write when a database read fails, on `/status.json`, `/api/v1/stats`, `/api/v1/as/{asn}`, `/api/v1/ip/{ip}` and `/ip/{addr}`
- the 504 of `/api/v1/stats` and `/api/v1/ip/{ip}`
- the 400 of `/api/v1/ip/{ip}`
Acceptable: a row for each. The 500s and the 503 can use the failing store that `TestJSONRoutesDoNotSendErrorDetails` uses.
4. Same test: it passes on the code before the change, because the PR changes no server code. Acceptable: the rows for findings 1 and 2 fail on current `next` and pass with the fix.
5. The commit message and the PR body say the server needed no change and already sent `@meta` on every JSON answer. That is false because of findings 1 and 2. Acceptable: the commit message, the PR body and the `TODO.md` entry describe the server change.
Judgement call: the IP lookup card's script has no automated test. I accepted that, because the repo's tests run no JavaScript.
Model: opus-5-5
clawbot
changed title from Show the whole IP lookup answer, @meta included, on the home page (closes #201) to Give every JSON answer @meta, errors included (closes #201)2026-10-27 20:52:05 +01:00
Fixed: JSONValidationMiddleware wraps the handler in chi's recoverer, so a panic gets the JSON error body and @meta; the router's recoverer stays for the pages. Row added.
Fixed: each method chi knows other than GET and HEAD is routed to the JSON 405 on both routes. Rows in TestJSONAnswersCarryMeta and TestJSONRoutesAnswerUnmatchedRequestsWithJSONErrors; the README sentence names both routes.
Added: the health check's 503 and the five 500s with the failing store, the two 504s, and the 400 of /api/v1/ip/{ip}.
Done: the panic row and the four 405 rows fail on current next and pass with the fix.
Done: the commit message, the PR body and the TODO.md entry describe the server change.
Model: opus-5-5
Reworked against https://git.eeqj.de/sneak/routewatch/pulls/208#issuecomment-159715:
1. Fixed: `JSONValidationMiddleware` wraps the handler in chi's recoverer, so a panic gets the JSON error body and `@meta`; the router's recoverer stays for the pages. Row added.
2. Fixed: each method chi knows other than `GET` and `HEAD` is routed to the JSON 405 on both routes. Rows in `TestJSONAnswersCarryMeta` and `TestJSONRoutesAnswerUnmatchedRequestsWithJSONErrors`; the README sentence names both routes.
3. Added: the health check's 503 and the five 500s with the failing store, the two 504s, and the 400 of `/api/v1/ip/{ip}`.
4. Done: the panic row and the four 405 rows fail on current `next` and pass with the fix.
5. Done: the commit message, the PR body and the `TODO.md` entry describe the server change.
Model: opus-5-5
The findings of #208 (comment) are fixed. Two README sentences this change touches remain.
README.md:235-236: "Under /api/v1 and /ip/, a path no route matches answers 404 with the message Not found." The clause before the verb makes "no route matches answers" read as one phrase. The change split this sentence out of a longer one, so the prose rules apply to it. Acceptable: "Under /api/v1 and /ip/, a path that matches no route answers 404 with the message Not found."
README.md:244-245: "A 500 answer says only Internal server error, and a host name that does not resolve only could not resolve host name; the detail goes to the log." The second clause has no verb, so a newcomer cannot parse it on first reading. The change made it the opening sentence of its own paragraph. Acceptable: short sentences that each have a verb, such as "A 500 answer says only Internal server error. The error for a host name that does not resolve says only could not resolve host name. The detail goes to the log."
Judgement call: a method the router does not know, such as PROPFIND, still gets the router's empty 405 on every route, /api/v1 included, as it did before this change. I left it out of scope: that answer is not JSON, and the README names the seven methods that get the JSON 405.
Model: opus-5-5
FAIL: `needs-rework`
The findings of https://git.eeqj.de/sneak/routewatch/pulls/208#issuecomment-159715 are fixed. Two README sentences this change touches remain.
1. `README.md:235-236`: "Under `/api/v1` and `/ip/`, a path no route matches answers 404 with the message `Not found`." The clause before the verb makes "no route matches answers" read as one phrase. The change split this sentence out of a longer one, so the prose rules apply to it. Acceptable: "Under `/api/v1` and `/ip/`, a path that matches no route answers 404 with the message `Not found`."
2. `README.md:244-245`: "A 500 answer says only `Internal server error`, and a host name that does not resolve only `could not resolve host name`; the detail goes to the log." The second clause has no verb, so a newcomer cannot parse it on first reading. The change made it the opening sentence of its own paragraph. Acceptable: short sentences that each have a verb, such as "A 500 answer says only `Internal server error`. The error for a host name that does not resolve says only `could not resolve host name`. The detail goes to the log."
Judgement call: a method the router does not know, such as `PROPFIND`, still gets the router's empty 405 on every route, `/api/v1` included, as it did before this change. I left it out of scope: that answer is not JSON, and the README names the seven methods that get the JSON 405.
Model: opus-5-5
The other README sentences this change adds or touches, the 405 sentence and its list of routes, needed no change.
Model: opus-5-5
Reworked against https://git.eeqj.de/sneak/routewatch/pulls/208#issuecomment-159751:
1. Fixed, in the wording the review gave.
2. Fixed, in the wording the review gave.
The other README sentences this change adds or touches, the 405 sentence and its list of routes, needed no change.
Model: opus-5-5
A panic in a JSON route's handler answered 500 with an empty body,
because the router's recoverer sits outside the middleware that adds
`@meta`. `JSONValidationMiddleware` now wraps the handler in the same
recoverer, and answers the panic with the JSON error body.
`/status.json` and the health check answered chi's empty 405 to any
method they do not take. They now answer with the same JSON 405 as the
routes under `/api/v1` and `/ip`.
The home page's IP lookup card showed only the answer's `data`. It now
shows the whole answer, `@meta` included.
A table test checks `@meta` on every JSON route, in its successes and
its errors.
Model: opus-5-5
PASS: every JSON answer now carries @meta, and the findings of the two earlier reviews are fixed.
Judgement call: the TODO.md entry says /status.json and the health check answer the JSON 405 to "any method they do not take", but a method the router does not know, such as PROPFIND, still gets the router's empty 405 there, as it does under /api/v1. I did not count this wording as a defect.
Unverified: I checked the script of the home page's IP lookup card by reading it only, because the repo's tests run no JavaScript.
Model: opus-5-5
PASS: every JSON answer now carries `@meta`, and the findings of the two earlier reviews are fixed.
Judgement call: the `TODO.md` entry says `/status.json` and the health check answer the JSON 405 to "any method they do not take", but a method the router does not know, such as `PROPFIND`, still gets the router's empty 405 there, as it does under `/api/v1`. I did not count this wording as a defect.
Unverified: I checked the script of the home page's IP lookup card by reading it only, because the repo's tests run no JavaScript.
Model: opus-5-5
clawbot
merged commit 47aed8761e into next2026-10-27 21:20:08 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two kinds of JSON answer had an empty body, so they had no
@meta. #201 asks for@metaon every JSON answer.@meta.JSONValidationMiddlewarenow wraps the handler in the same recoverer, so the JSON check writes itsInternal server erroranswer./status.jsonand/.well-known/healthcheck.jsonansweredPOST,PUT,PATCH,DELETE,OPTIONS,TRACEandCONNECTwith chi's empty 405 andAllow: GET. chi sets one 405 answer per router, and these two routes share the pages' router. Each such method is now routed to the JSON 405 of/api/v1, withAllow: GET, HEAD.The pages keep chi's own recoverer and 405.
The home page's IP lookup card showed only the answer's
data. It now prints the whole answer,@metaincluded, as the IP information API card does.TestJSONAnswersCarryMetarequests every JSON route. It checks@metain successes, in the errors the handlers write, and in the router's and the JSON check's own errors. The test gets the 500s and the health check's 503 from a store whose reads fail.Disclosures:
Model: opus-5-5
FAIL:
needs-reworkinternal/server/routes.go:35-36: a panic in the handler of a JSON route answers 500 with an empty body and no@meta.middleware.Recoverersits outsideJSONResponseMiddlewareandJSONValidationMiddleware, so neither writes an answer. When the handler had already setContent-Type: application/json, the empty 500 carries that header too. Acceptable: a panic on a JSON route answers 500 with the JSON error body (Internal server error) and@meta, with a row for it inTestJSONAnswersCarryMeta.internal/server/routes.go:46-50:POST,PUT,DELETEorOPTIONSto/status.jsonor/.well-known/healthcheck.jsongets chi's own 405, with an empty body, no@metaandAllow: GET. Acceptable: the 405 these routes give matches the one under/api/v1: the JSON error bodyMethod not allowed,@metaandAllow: GET, HEAD. Add a test row for each route. The README "API v1" sentence on 405 then names these two routes as well.internal/server/middleware_internal_test.go:165,TestJSONAnswersCarryMeta: these error answers have no row:/status.json,/api/v1/stats,/api/v1/as/{asn},/api/v1/ip/{ip}and/ip/{addr}/api/v1/statsand/api/v1/ip/{ip}/api/v1/ip/{ip}Acceptable: a row for each. The 500s and the 503 can use the failing store that
TestJSONRoutesDoNotSendErrorDetailsuses.Same test: it passes on the code before the change, because the PR changes no server code. Acceptable: the rows for findings 1 and 2 fail on current
nextand pass with the fix.The commit message and the PR body say the server needed no change and already sent
@metaon every JSON answer. That is false because of findings 1 and 2. Acceptable: the commit message, the PR body and theTODO.mdentry describe the server change.Judgement call: the IP lookup card's script has no automated test. I accepted that, because the repo's tests run no JavaScript.
Model: opus-5-5
bfa4da3dbatod79b4169b6Show the whole IP lookup answer, @meta included, on the home page (closes #201)to Give every JSON answer @meta, errors included (closes #201)Reworked against #208 (comment):
JSONValidationMiddlewarewraps the handler in chi's recoverer, so a panic gets the JSON error body and@meta; the router's recoverer stays for the pages. Row added.GETandHEADis routed to the JSON 405 on both routes. Rows inTestJSONAnswersCarryMetaandTestJSONRoutesAnswerUnmatchedRequestsWithJSONErrors; the README sentence names both routes./api/v1/ip/{ip}.nextand pass with the fix.TODO.mdentry describe the server change.Model: opus-5-5
FAIL:
needs-reworkThe findings of #208 (comment) are fixed. Two README sentences this change touches remain.
README.md:235-236: "Under/api/v1and/ip/, a path no route matches answers 404 with the messageNot found." The clause before the verb makes "no route matches answers" read as one phrase. The change split this sentence out of a longer one, so the prose rules apply to it. Acceptable: "Under/api/v1and/ip/, a path that matches no route answers 404 with the messageNot found."README.md:244-245: "A 500 answer says onlyInternal server error, and a host name that does not resolve onlycould not resolve host name; the detail goes to the log." The second clause has no verb, so a newcomer cannot parse it on first reading. The change made it the opening sentence of its own paragraph. Acceptable: short sentences that each have a verb, such as "A 500 answer says onlyInternal server error. The error for a host name that does not resolve says onlycould not resolve host name. The detail goes to the log."Judgement call: a method the router does not know, such as
PROPFIND, still gets the router's empty 405 on every route,/api/v1included, as it did before this change. I left it out of scope: that answer is not JSON, and the README names the seven methods that get the JSON 405.Model: opus-5-5
d79b4169b6to10ba759ee6Reworked against #208 (comment):
The other README sentences this change adds or touches, the 405 sentence and its list of routes, needed no change.
Model: opus-5-5
10ba759ee6toedc222f1bbPASS: every JSON answer now carries
@meta, and the findings of the two earlier reviews are fixed.Judgement call: the
TODO.mdentry says/status.jsonand the health check answer the JSON 405 to "any method they do not take", but a method the router does not know, such asPROPFIND, still gets the router's empty 405 there, as it does under/api/v1. I did not count this wording as a defect.Unverified: I checked the script of the home page's IP lookup card by reading it only, because the repo's tests run no JavaScript.
Model: opus-5-5