Skip to content
Skip to main content
Novel Systems home
Decision log
D-082August 5, 2026

The API says which commit it is running

Affects: backend/src/lib/build-info.ts, backend/src/routes/index.ts, backend/src/schemas/common.schema.ts, public/openapi.json

What was wrong

The Stripe adapter fix of D-080 was written, tested, committed and pushed, and the live billing sandbox went on writing CA$0.00 invoices. Two explanations fit the evidence equally well: the fix was deployed and does not work against the live Stripe account, or the fix was never deployed. Those call for opposite responses — reopen the diagnosis, or press redeploy — and nothing the deployment served could tell them apart. /api/health reported a database round trip. /api/routes reported a route table. Both had been byte-identical for weeks either side of the change, because neither is a function of the code that changed.

The question was settled in the end by inference from a third endpoint's behaviour — GET /api/v1/quotes/:id/invoice only answers for a SUCCEEDED sync, the fixed adapter records FAILED on a total mismatch, therefore an answered request proves the old adapter — which is correct, and is a slow and fragile way to learn something the process already knows about itself.

What was decided

/api/health carries a build object on both arms: commit, ref, environment, read once at module load from Vercel's system environment.

On the 503 arm as well as the 200 arm, deliberately. "The database is unreachable" and "which build is failing to reach it" are the two halves of the same page, and the second would otherwise be unavailable exactly when the first is being read.

Every field is nullable and null is the honest answer rather than a fallback. Run anywhere that is not Vercel there is no commit to report, and a literal like "unknown" or "dev" would be a value every consumer has to learn to distinguish from a real one. The test asserts the keys and the nulls, not a SHA: under test there is no deployment, and asserting a SHA would only assert that the test runner is not one.

The alternative, and why not

A separate /api/version endpoint. Rejected because the moment the question gets asked is the moment somebody is already looking at health — during an incident, or after a deploy that did not visibly land — and a second endpoint is a second thing to know about. It also would have to be added to the route manifest, the OpenAPI document and the contract check for a payload that is three fields.

Publishing a build time was considered and dropped. Vercel exposes no build timestamp to the runtime; process start time is a different fact and would be read as this one.

Is publishing a commit SHA a disclosure?

The repository is private, so the SHA names a commit the reader cannot fetch. What it gives them is the ability to say "the deployment changed" or "it did not" — which is the point, and which any observer can already establish by watching behaviour change. Same class as /api/routes, which publishes the route table on the argument that a deployment ought to be able to describe itself.

What would have to change for this to be wrong

Moving off Vercel. The variable names are Vercel's; on another host all three fields go null and the endpoint quietly stops answering the question it was added for. The fix then is to populate them at build time from git rev-parse rather than to delete the field.