From a6e5adb6cf06e640ba8cbb078377f49898a31a91 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Sat, 30 May 2026 10:43:52 +0530 Subject: [PATCH] fix(api): /healthz service=instanode-api + correct /livez vs /readyz comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG-API-146/148/309: /healthz.service emitted the legacy brand string "instant.dev" — predates the rename to instanode.dev. Now emits "instanode-api" so canaries that key on `service` to disambiguate api / worker / provisioner /healthz stamps align with the runtime brand and log-line correlation fields. BUG-API-202: the /livez comment block claimed "the readiness signal lives at /healthz" — actually wrong. /healthz is the shallow probe (commit_id + migration stamp); /readyz is the deep readiness matrix wired to the k8s readinessProbe (see handlers/readyz.go). Comment updated so future readers don't get a wrong mental model. Coverage block: Symptom: /healthz.service = "instant.dev" (legacy brand) Enumeration: rg -F '"instant.dev"' --type go Sites found: 4 (router.go emit + healthz_test.go fixture + healthz_test.go assert + e2e_test.go assert) Sites touched: 4 (all 4 — the remaining matches are inline comments and unrelated DeployDomain default in config_test.go) Coverage test: TestHealthzShape pins service="instanode-api" + asserts legacy "instant.dev" must not regress (require.NotEqual). Live verified: pending merge + auto-deploy + curl /healthz | jq .service Co-Authored-By: Claude Opus 4.7 (1M context) --- e2e/e2e_test.go | 6 ++++-- internal/router/healthz_test.go | 9 +++++++-- internal/router/router.go | 18 +++++++++++++++--- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index c3c43b99..fcaa70bc 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -28,8 +28,10 @@ func TestE2E_Healthz_ReturnsOK(t *testing.T) { if body["ok"] != true { t.Errorf("GET /healthz: want ok=true, got %v", body) } - if body["service"] != "instant.dev" { - t.Errorf("GET /healthz: want service=instant.dev, got %v", body["service"]) + // BUG-API-146/148/309: `service` is "instanode-api" — the legacy + // "instant.dev" value is the brand drift this assertion catches. + if body["service"] != "instanode-api" { + t.Errorf("GET /healthz: want service=instanode-api, got %v", body["service"]) } } diff --git a/internal/router/healthz_test.go b/internal/router/healthz_test.go index 36914039..9d933551 100644 --- a/internal/router/healthz_test.go +++ b/internal/router/healthz_test.go @@ -47,7 +47,7 @@ func TestHealthzShape(t *testing.T) { m := reader.Get(c.UserContext()) return c.JSON(fiber.Map{ "ok": true, - "service": "instant.dev", + "service": "instanode-api", "commit_id": buildinfo.GitSHA, "build_time": buildinfo.BuildTime, "version": buildinfo.Version, @@ -75,7 +75,12 @@ func TestHealthzShape(t *testing.T) { // Buildinfo contract — every field is non-empty; commit_id specifically // falls back to "dev" when -ldflags is omitted (go run, go test). require.Equal(t, true, got["ok"]) - require.Equal(t, "instant.dev", got["service"]) + // BUG-API-146/148/309: `service` must align with the runtime brand + // ("instanode-api"), not the legacy "instant.dev" string. Canaries + // + log-line correlation key on the new value. + require.Equal(t, "instanode-api", got["service"]) + require.NotEqual(t, "instant.dev", got["service"], + "BUG-API-146: legacy brand string must not regress into /healthz.service") require.NotEmpty(t, got["commit_id"], "commit_id MUST be present on /healthz") require.NotEmpty(t, got["build_time"]) require.NotEmpty(t, got["version"]) diff --git a/internal/router/router.go b/internal/router/router.go index 44cbe55e..f8306f5b 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -136,8 +136,12 @@ func NewWithHooks(cfg *config.Config, db *sql.DB, rdb *redis.Client, geoDbs *mid // GET /livez — "the process is alive." NO database check, NO migration // check, NO auth, NO rate-limit, NO logging context. Pure process-up // signal so a k8s liveness probe can distinguish "process alive" from - // "process ready" (the readiness signal lives at /healthz, which checks - // DB + migration state). + // "process ready" (the deep readiness matrix lives at /readyz — see + // handlers/readyz.go; /healthz is the shallow build-SHA + migration + // stamp surface that canaries hit post-deploy). BUG-API-202: an + // earlier copy of this block said "readiness signal lives at /healthz" + // which was wrong — /healthz is the shallow probe, /readyz is the + // per-component readiness matrix wired to the k8s readinessProbe. // // Wired here BEFORE the app.Use(...) chain so the kubelet's probe // traffic (~6/min/pod from livenessProbe + readinessProbe split, per @@ -367,9 +371,17 @@ func NewWithHooks(cfg *config.Config, db *sql.DB, rdb *redis.Client, geoDbs *mid // of the pod's local TZ. build_time is the immutable image stamp; // `now` is the live read — keeping both lets a probe compute the // pod's uptime as a sanity check too. + // BUG-API-146/148/309 (QA 2026-05-29): the `service` field used to + // emit "instant.dev" — the legacy brand name. Now emits "instanode-api" + // so /healthz aligns with the runtime brand (instanode.dev) and the + // log-line serviceName ("api" / "instant-api"). Canaries that key on + // `service` to disambiguate api vs worker vs provisioner /healthz + // stamps benefit from the new value too — see handlers/readyz.go + // where worker/provisioner probes report "instanode-worker" and + // "instanode-provisioner" in sibling repos. return c.JSON(fiber.Map{ "ok": true, - "service": "instant.dev", + "service": "instanode-api", "commit_id": buildinfo.GitSHA, "build_time": buildinfo.BuildTime, "version": buildinfo.Version,