diff --git a/admin/src/app/dashboard/health/HealthCoverage.test.tsx b/admin/src/app/dashboard/health/HealthCoverage.test.tsx
new file mode 100644
index 000000000..56b619028
--- /dev/null
+++ b/admin/src/app/dashboard/health/HealthCoverage.test.tsx
@@ -0,0 +1,80 @@
+import { renderToStaticMarkup } from "react-dom/server";
+import { MemoryRouter } from "react-router-dom";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import type { InstanceHealthResult } from "@/lib/api/client/admin/instance";
+import type { SystemStatusResult } from "@/lib/api/client/admin/system";
+import { FindingsTab } from "./FindingsTab";
+import { ServicesTab } from "./ServicesTab";
+
+const state = vi.hoisted(() => ({
+ health: { data: undefined as InstanceHealthResult | undefined, isError: false, isLoading: false, isFetching: false, dataUpdatedAt: 0, error: new Error("secret-provider-detail"), refetch: vi.fn() },
+ services: { data: undefined as SystemStatusResult | undefined, isError: false, isLoading: false, isFetching: false, error: new Error("secret-provider-detail"), refetch: vi.fn() },
+ canConfigure: true,
+}));
+vi.mock("@/hooks/useInstanceHealth", () => ({ useInstanceHealth: () => state.health, findingCount: () => 0 }));
+vi.mock("@/hooks/useUpdateState", () => ({ useUpdateState: () => ({ data: undefined }) }));
+vi.mock("@/components/layout/UpdateDialog", () => ({ UpdateDialog: () => null }));
+vi.mock("../InstanceHealthPanel", () => ({ InstanceFindings: () =>
Retained findings
}));
+vi.mock("@tanstack/react-query", () => ({ useQuery: () => state.services }));
+vi.mock("@/hooks/useAdminPerm", () => ({ useAdminPerm: () => state.canConfigure }));
+vi.mock("../MailStatusCard", () => ({ MailStatusCard: () =>
Protected mail probe }));
+
+function render(page: "findings" | "services") {
+ const html = renderToStaticMarkup(
{page === "findings" ? : });
+ return new DOMParser().parseFromString(html, "text/html").body.textContent;
+}
+
+beforeEach(() => {
+ state.canConfigure = true;
+ Object.assign(state.health, { data: { checks: [], summary: { error: 0, warning: 0, info: 0 }, execution_coverage: "unreported" }, isError: false, dataUpdatedAt: Date.now() });
+ Object.assign(state.services, { data: { data: [], checked_at: new Date().toISOString() }, isError: false });
+});
+
+describe("configuration and service coverage", () => {
+ it("does not mount the protected platform mail probe without manage-settings access", () => {
+ state.canConfigure = false;
+ expect(render("services")).toContain("Platform mail permission required");
+ expect(render("services")).not.toContain("Protected mail probe");
+ });
+ it("does not equate absent findings or an older coverage-free response to healthy", () => {
+ for (const coverage of [undefined, "unreported"]) {
+ state.health.data!.execution_coverage = coverage;
+ expect(render("findings")).toContain("Check execution coverage is not established");
+ expect(render("findings")).not.toContain("No problems found");
+ expect(render("findings")).toContain("Response received");
+ }
+ });
+
+ it("keeps failed refresh explicit and redacts raw query errors", () => {
+ state.health.isError = true;
+ state.services.isError = true;
+ for (const page of ["findings", "services"] as const) {
+ expect(render(page)).toContain("refresh");
+ expect(render(page)).not.toContain("secret-provider-detail");
+ expect(render(page)).not.toContain("All systems operational");
+ }
+ });
+
+ it("does not call an empty service list operational", () => {
+ expect(render("services")).toContain("Current service coverage unknown");
+ expect(render("services")).toContain("No components were returned");
+ });
+
+ it("scopes passed probes to reachability and hides connection errors", () => {
+ state.services.data!.data = [{ name: "postgres", ok: true, latency_ms: 5 }, { name: "redis", ok: false, latency_ms: 20, error: "password=private secret-provider-detail" }];
+ expect(render("services")).toContain("1 service probe failed");
+ expect(render("services")).toContain("Probe passed");
+ expect(render("services")).not.toContain("secret-provider-detail");
+ state.services.data!.data = [{ name: "postgres", ok: true, latency_ms: 5 }];
+ expect(render("services")).toContain("Reported service probes passed");
+ expect(render("services")).toContain("does not prove send throughput");
+ });
+
+ it("does not turn stale probes or cached successful probes into a fresh verdict", () => {
+ state.services.data!.data = [{ name: "postgres", ok: true, latency_ms: 5 }];
+ state.services.data!.checked_at = new Date(Date.now() - 300_000).toISOString();
+ expect(render("services")).toContain("Current service coverage unknown");
+ expect(render("services")).toContain("Cached probe");
+ expect(render("services")).not.toContain("Probe passed");
+ });
+});
diff --git a/admin/src/app/dashboard/health/ServicesTab.tsx b/admin/src/app/dashboard/health/ServicesTab.tsx
index 2cda5a7df..3d8315255 100644
--- a/admin/src/app/dashboard/health/ServicesTab.tsx
+++ b/admin/src/app/dashboard/health/ServicesTab.tsx
@@ -11,6 +11,9 @@ import { Callout, StatusBadge, StatusDot } from "@/components/ui/kit";
import { cn } from "@/lib/utils";
import { MailStatusCard } from "../MailStatusCard";
import { getSystemStatus, type SystemComponentStatus } from "@/lib/api/client/admin/system";
+import { observationIsOld } from "@/lib/monitoring";
+import { useAdminPerm } from "@/hooks/useAdminPerm";
+import { AdminPerm } from "@/lib/auth/permissions";
export const SYSTEM_STATUS_KEY = ["admin", "system", "status"] as const;
@@ -36,17 +39,20 @@ function titleCase(name: string): string {
}
export function ServicesTab() {
+ const canConfigure = useAdminPerm(AdminPerm.ManageSettings);
// Probes have no realtime event, so this is a deliberate poll; the query
// only lives while the tab is mounted.
const statusQ = useQuery({
queryKey: SYSTEM_STATUS_KEY,
queryFn: getSystemStatus,
refetchInterval: 15_000,
+ refetchIntervalInBackground: false,
retry: false,
});
const components = statusQ.data?.data ?? [];
const failing = components.filter((c) => !c.ok);
+ const cached = statusQ.isError || observationIsOld(statusQ.data?.checked_at, Date.now());
return (
@@ -85,7 +91,7 @@ export function ServicesTab() {
{statusQ.isError && (
statusQ.refetch()}
/>
@@ -93,8 +99,10 @@ export function ServicesTab() {
{statusQ.data && (
<>
- {failing.length === 0 ? (
-
+ {cached || components.length === 0 ? (
+ {components.length === 0 ? "No components were returned. Reachability has not been established." : "Cached probes cannot establish current reachability."}
+ ) : failing.length === 0 ? (
+ Reachability at the probe time only. This does not prove send throughput, mailbox sync or recovery.
) : (
{failing.map((c) => titleCase(c.name)).join(", ")}
@@ -123,13 +131,13 @@ export function ServicesTab() {
) : (
{components.map((c) => (
-
+
))}
)}
-
+ {canConfigure ? : Manage settings access is required to inspect or test platform mail.}
>
@@ -138,12 +146,12 @@ export function ServicesTab() {
);
}
-function ComponentRow({ component: c }: { component: SystemComponentStatus }) {
+function ComponentRow({ component: c, cached }: { component: SystemComponentStatus; cached: boolean }) {
return (