Skip to content
Skip to main content
Novel Systems home
Decision log
D-034August 4, 2026

The uptime monitor matches on two fields, because one of them is the thing that can silently go missing

Decided

the Better Stack monitor for the site health endpoint asserts the keyword … and not the shorter, more obvious "status":"ok".

"status":"ok","checks":"reachability"

and not the shorter, more obvious "status":"ok".

Why. The endpoint has two arms. GET /api/health reports whether four environment variables are set; GET /api/health?probe=deep sends a real request to each of the four dependencies. D-032 gave both arms a checks discriminator — "configuration" or "reachability" — specifically so that a consumer cannot read one arm's answer as the other's. A monitor is a consumer, and it is the one consumer whose misreading is invisible, because a wrong green light produces no symptom at all.

The failure this guards against is not the endpoint breaking. It is the *query string* going missing — someone edits the monitor URL, a redirect drops it, a migration to a new monitor copies the base URL from the wrong place. Under a bare "status":"ok" keyword every one of those degrades the monitor from measuring reachability to measuring configuration, silently, with the light staying green and the monitor's own name still promising the stronger claim. That is the exact class of defect the health rewrite was written to end; leaving it live in the monitor would have moved the lie one layer out rather than fixing it.

The compound keyword is a *single* substring rather than two separate assertions because NextResponse.json serializes in object-literal order and app/api/health/route.ts declares status immediately before checks in both arms. The two fields are therefore adjacent in the body with exactly one comma between them. This is a real coupling: reordering those two fields in the route, or interposing a third, breaks the monitor without breaking a test. Anyone editing the HealthResponse literal has to know that.

The alternative was Better Stack's expected-status-code check plus a bare keyword. Rejected because the status code is 200 in both arms whenever the dependencies are fine, so the code carries no information about which arm ran. The whole point of the discriminator is that the arm has to be named in the body, and the only place to assert on it is the body.

This would be wrong if the endpoint ever gained a third arm whose response also carried "checks":"reachability" under different semantics, or if the monitor were moved to a provider whose keyword matching is not a literal substring. Either would require re-deriving the assertion rather than copying the string.