From 9d538951b641a034c6d3ee8abb09367d03fbfc77 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 21 Jul 2026 02:15:34 +0200 Subject: [PATCH] fix(hwpod): keep native readiness local --- internal/hwpod/http.ts | 10 +++++++--- internal/hwpod/spec-registry.test.ts | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/hwpod/http.ts b/internal/hwpod/http.ts index 2ba29d76..0e3c3ef9 100644 --- a/internal/hwpod/http.ts +++ b/internal/hwpod/http.ts @@ -56,9 +56,13 @@ export function createHwpodHttpApp(options: { runtimeApiUrl: string; runtimeApiA }; } -async function readiness(options: { runtimeApiUrl: string; runtimeApiAuthorization: string; temporal: any }) { - try { const response = await fetch(`${options.runtimeApiUrl}/v1/hwpod/topology?resource=node&limit=1`, { headers: { authorization: options.runtimeApiAuthorization }, signal: AbortSignal.timeout(5000) }); return json(response.ok ? 200 : 503, { ok: response.ok, serviceId: "hwlab-hwpod-api", temporal: "configured", runtimeApi: response.ok ? "reachable" : "unreachable", valuesPrinted: false }); } - catch { return json(503, { ok: false, serviceId: "hwlab-hwpod-api", temporal: "configured", runtimeApi: "unreachable", valuesPrinted: false }); } +async function readiness(options: { runtimeApiUrl: string; runtimeApiAuthorization: string; temporal: any; specRegistry: any }) { + try { + const specs = await options.specRegistry.list(); + return json(200, { ok: true, serviceId: "hwlab-hwpod-api", temporal: "configured", specRegistry: "ready", specCount: specs.count, runtimeApi: "configured", valuesPrinted: false }); + } catch (error: any) { + return json(503, { ok: false, serviceId: "hwlab-hwpod-api", temporal: "configured", specRegistry: "blocked", runtimeApi: "configured", error: { code: error?.code ?? "hwpod_spec_registry_unavailable", message: error?.message ?? String(error) }, valuesPrinted: false }); + } } async function proxyGet(base: string, route: string, authorization: string) { const response = await fetch(`${base}${route}`, { headers: { authorization }, signal: AbortSignal.timeout(10_000) }); return new Response(await response.text(), { status: response.status, headers: { "content-type": response.headers.get("content-type") ?? "application/json", "cache-control": "no-store" } }); } function specDocument(body: any) { return body && typeof body === "object" && !Array.isArray(body) && body.document !== undefined ? body.document : body; } diff --git a/internal/hwpod/spec-registry.test.ts b/internal/hwpod/spec-registry.test.ts index 6cf949d1..a3cd754f 100644 --- a/internal/hwpod/spec-registry.test.ts +++ b/internal/hwpod/spec-registry.test.ts @@ -46,6 +46,8 @@ test("L1 HWPOD HTTP exposes runtime CRUD and typed frozen errors", async () => { const temporal = { close: async () => {}, start: async () => ({}), describe: async () => ({}), result: async () => ({}) }; const app = createHwpodHttpApp({ runtimeApiUrl: "http://runtime.invalid", runtimeApiAuthorization: "Bearer test", temporal, specRegistry: registry }); + expect(await request(app, "GET", "/health/ready")).toMatchObject({ status: 200, body: { ok: true, specRegistry: "ready", specCount: 1, runtimeApi: "configured" } }); + const created = await request(app, "POST", "/v1/hwpod/specs", { document: spec("runtime-http", "/http-v1") }); expect(created).toMatchObject({ status: 201, body: { ok: true, status: "created", hwpodId: "runtime-http" } }); expect(await request(app, "GET", "/v1/hwpod/specs/runtime-http")).toMatchObject({ status: 200, body: { document: { spec: { workspace: { path: "/http-v1" } } } } });