# Health — current state: MxAccessGateway Repo: `~/Desktop/MxAccessGateway`. Stack: .NET 10 gateway (x64) + .NET 4.8 worker (x86), gRPC; solution `src/MxGateway.sln`. Health code lives in `src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs`. All paths relative to repo root. Verified 2026-06-01. **Summary: bare liveness only.** MxAccessGateway has a single `/health/live` endpoint that returns a hardcoded `GatewayHealthReply` JSON object. `AddHealthChecks()` is called at startup but is entirely unused — no `IHealthCheck` implementations are registered, `MapHealthChecks` is never called, and there is no readiness or active-node tier. The net48 x86 worker process has no HTTP server and therefore no health endpoint of any kind. ## 1. Endpoint wiring `src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs`: - `:61` — `builder.Services.AddHealthChecks()` is called in the DI registration block. **This call is dead**: no `.AddCheck()` call follows it, no `MapHealthChecks` is ever called. The framework registers the health-check infrastructure but nothing is wired through it. - `:139–145` — `MapGatewayEndpoints` maps a raw `endpoints.MapGet("/health/live", ...)` (not `MapHealthChecks`). The handler is an inline lambda that returns `Results.Ok(new GatewayHealthReply(...))` with a hardcoded `Status: "Healthy"`: ```csharp endpoints.MapGet( "/health/live", () => Results.Ok(new GatewayHealthReply( Status: "Healthy", DefaultBackend: GatewayContractInfo.DefaultBackendName, WorkerProtocolVersion: GatewayContractInfo.WorkerProtocolVersion))) .WithName("LiveHealth"); ``` This endpoint always returns HTTP 200 `{"Status":"Healthy",...}` as long as the process is alive. It carries no authentication requirement (no `[Authorize]` or `.RequireAuthorization()`). ## 2. Response shape `GatewayHealthReply` is a record with three fields: - `Status` — always `"Healthy"` (hardcoded string, not the ASP.NET Core `HealthStatus` enum) - `DefaultBackend` — value of `GatewayContractInfo.DefaultBackendName` (the configured backend name, useful for confirming which gateway instance a probe hit) - `WorkerProtocolVersion` — value of `GatewayContractInfo.WorkerProtocolVersion` (the gRPC protocol version the gateway expects from the worker, useful for version-skew detection) The response is not `HealthChecks.UI.Client` JSON and is not the standard ASP.NET Core health response shape. It is a bespoke JSON record. ## 3. Probes None. There is no `IHealthCheck` registered. The `/health/live` response does not reflect: - Whether the SQLite auth-store is reachable - Whether any active MXAccess session is functional - Whether the x86 worker named-pipe IPC is connected or the worker process is alive - Whether the gRPC service is actually accepting calls The endpoint is purely a process liveness indicator. ## 4. Tier coverage | Tier | Endpoint | Status | |---|---|---| | Process liveness | `/health/live` (raw `MapGet`) | ✅ present (but non-standard) | | Readiness | `/health/ready` | ⛔ absent | | Active node | `/health/active` | ⛔ absent (not Akka-based; not applicable as-is) | | `healthz` convention | `/healthz` | ⛔ absent | MxAccessGateway is not an Akka.NET application — it has no cluster, no leader election, and no active-node concept. The "active" tier in the shared spec translates here to "is the worker process connected and the gRPC service ready to accept calls?" rather than cluster leadership. ## 5. x86 worker `ZB.MOM.WW.MxGateway.Worker` is a .NET 4.8 console application communicating with the gateway over Windows named-pipe IPC. It has no HTTP server, no health endpoint, and no exposure to any probe mechanism. Its liveness must be inferred indirectly — either via the gateway process monitoring it (not currently implemented) or via the `GrpcDependencyHealthCheck` the gateway could use to probe the IPC channel. ## 6. Notable gaps - `AddHealthChecks()` at `:61` is dead code. No `IHealthCheck` is ever registered via this call. - `/health/live` uses `MapGet` (a raw minimal-API handler) rather than `MapHealthChecks`. It bypasses the ASP.NET Core health-check middleware entirely, which means it does not participate in the standard health-check pipeline (no `IHealthCheckPublisher`, no `HealthReport`, no UI integration). - The hardcoded `"Healthy"` status means the endpoint cannot reflect real probe results even if probes were added later — the handler must be replaced, not just supplemented. - No readiness gating: orchestrators (Kubernetes, Traefik) that rely on `/health/ready` returning 503 until the process is actually ready will receive 200 (or 404) from MxAccessGateway today. --- ## Adoption plan → `ZB.MOM.WW.Health` **Replace `/health/live` + wire the shared tiers:** The `AddHealthChecks()` call at `GatewayApplication.cs:61` is already present — it just needs probes registered against it. The raw `MapGet("/health/live", ...)` handler at `:139–145` must be removed and replaced with `app.MapZbHealth()` from `ZB.MOM.WW.Health`. Steps: 1. **Remove** the inline `MapGet("/health/live", ...)` lambda (`:139–145`). The `GatewayHealthReply` record and `DefaultBackend`/`WorkerProtocolVersion` metadata can be surfaced differently (e.g., a `/info` endpoint or as custom data on the health response). 2. **Register a `GrpcDependencyHealthCheck`** (from `ZB.MOM.WW.Health`) that probes the named-pipe IPC channel to the x86 worker. Tag `["ready"]`. This replaces the hardcoded liveness-only response with a real probe that reflects whether the worker is reachable. 3. **Optionally add a `GrpcDependencyHealthCheck`** for any downstream gRPC dependency (e.g., the Galaxy Repository connection) if the gateway is expected to be healthy only when its upstreams are reachable. Tag `["ready"]`. 4. **Call `app.MapZbHealth()`** — this maps `/health/ready` (tag `ready`), `/health/active` (tag `active`; initially empty — no active-node concept in MxGateway), and `/healthz` (bare liveness). The `/healthz` endpoint replaces the semantic role that `/health/live` served today. 5. **Do not add `ZB.MOM.WW.Health.Akka`** — MxAccessGateway has no Akka dependency. The consumer matrix in the design specifies MxGateway uses the core package only. **Keep bespoke:** - The `WorkerProtocolVersion` / `DefaultBackend` metadata from `GatewayHealthReply` is MxAccessGateway-specific; keep it as a separate `/info` endpoint or embed it as `Data` on a custom probe rather than normalizing it into the shared contract. - The x86 worker itself (net48 console, named-pipe IPC, no HTTP) remains outside the shared health scheme. The `GrpcDependencyHealthCheck` observes the worker indirectly from the gateway side. - Per-gateway auth and TLS concerns on who may call health endpoints remain per-project. **Adoption is a follow-on task** (tracked in `GAPS.md`), not part of the `ZB.MOM.WW.Health` library build. MxGateway is the **highest-priority adopter** (P1 gap — no probes/tiers today) and should be the first app wired up once the nupkg is available.