From 1a360e9133f37dfd22e3fb31eb86fa1ec9ba1ba0 Mon Sep 17 00:00:00 2001 From: Edwin Lim Date: Tue, 8 Sep 2026 15:01:13 -0700 Subject: [PATCH] chore: remove old gw readiness check --- README.md | 8 +- .../__tests__/health-checks.test.ts | 130 +++++++----------- src/lib/health-checks/endpoints.ts | 10 +- src/lib/health-checks/index.ts | 6 +- src/lib/health-checks/readiness.ts | 36 ++--- src/lib/health-checks/testme.md | 8 -- src/lib/health-checks/types.ts | 1 - .../tui/playground/demos/HealthCheckDemo.tsx | 5 - src/ui/tui/store.ts | 2 +- 9 files changed, 71 insertions(+), 135 deletions(-) diff --git a/README.md b/README.md index 32de4c180..19d249184 100644 --- a/README.md +++ b/README.md @@ -614,7 +614,7 @@ point is `evaluateWizardReadiness()`, which returns one of three values: | --- | --- | | `types.ts` | Enums, interfaces (`ServiceHealthStatus`, `AllServicesHealth`, etc.) | | `statuspage.ts` | Statuspage.io v2 API helpers + checks for Anthropic, PostHog, GitHub, npm, Cloudflare | -| `endpoints.ts` | Direct endpoint checks for LLM Gateway (`/_liveness`), MCP (`/`), and the skills origins (`skill-menu.json` on GitHub Releases + the AWS mirror) | +| `endpoints.ts` | Direct endpoint checks for MCP (`/`) and the skills origins (`skill-menu.json` on GitHub Releases + the AWS mirror) | | `readiness.ts` | `checkAllExternalServices`, `evaluateWizardReadiness`, readiness config | | `index.ts` | Barrel re-export | | `testme.md` | Test running instructions and endpoint reference | @@ -632,10 +632,14 @@ two arrays: ### Current defaults ```ts -downBlocksRun: ['anthropic', 'npmOverall', 'llmGateway', 'mcp', 'skillsOrigin'], +downBlocksRun: ['anthropic', 'npmOverall', 'mcp', 'skillsOrigin'], degradedBlocksRun: ['anthropic'], ``` +The AI gateway is deliberately absent: its URL is only known from the run's +token mint at bootstrap, so there is nothing static to probe — and a failed +mint already stops the run with the server's reason. + `skillsOrigin` is one entry covering two origins: skills are published to GitHub Releases and an AWS mirror under the same filenames, and downloads fail over between them (`src/lib/fetch-retry.ts`). Both are probed in parallel, so diff --git a/src/lib/health-checks/__tests__/health-checks.test.ts b/src/lib/health-checks/__tests__/health-checks.test.ts index 66ebca378..cbafb2074 100644 --- a/src/lib/health-checks/__tests__/health-checks.test.ts +++ b/src/lib/health-checks/__tests__/health-checks.test.ts @@ -8,9 +8,7 @@ * summary.json – same rollup plus component list; component statuses: * operational | degraded_performance | partial_outage | major_outage | under_maintenance * https://support.atlassian.com/statuspage/docs/show-service-status-with-components - * - * LLM Gateway – FastAPI service, GET /_liveness returns {"status":"alive"} (200) - * Source: posthog/services/llm-gateway/src/llm_gateway/api/health.py + * * MCP – Cloudflare Worker, GET / returns an HTML landing page (200) * Source: posthog/services/mcp/src/index.ts @@ -23,7 +21,6 @@ import { checkCloudflareOverallHealth, checkGithubHealth, checkSkillsOriginHealth, - checkLlmGatewayHealth, checkMcpHealth, checkNpmComponentHealth, checkNpmOverallHealth, @@ -35,6 +32,7 @@ import { ServiceHealthStatus, WizardReadiness, } from '@lib/health-checks/index'; +import { fetchEndpointHealth } from '@lib/health-checks/endpoints'; // --------------------------------------------------------------------------- // Real-world Statuspage.io v2 response factories @@ -191,9 +189,6 @@ const POSTHOG_INCIDENTIO_HEALTHY = { scheduled_maintenances: [], }; -// LLM Gateway /_liveness response (from posthog/services/llm-gateway/src/llm_gateway/api/health.py) -const LLM_GATEWAY_LIVENESS_BODY = JSON.stringify({ status: 'alive' }); - // MCP / landing page (from posthog/services/mcp/src/index.ts + src/static/landing.html) const MCP_LANDING_HTML = 'PostHog MCP Server'; @@ -210,7 +205,6 @@ const URLS = { npmSummary: 'https://status.npmjs.org/api/v2/summary.json', cloudflareStatus: 'https://www.cloudflarestatus.com/api/v2/status.json', cloudflareSummary: 'https://www.cloudflarestatus.com/api/v2/summary.json', - llmGatewayLiveness: 'https://gateway.us.posthog.com/_liveness', mcpLanding: 'https://mcp.posthog.com/', githubSkillMenu: 'https://github.com/PostHog/context-mill/releases/latest/download/skill-menu.json', @@ -251,10 +245,6 @@ const HEALTHY_RESPONSES: Record = body: JSON.stringify(CLOUDFLARE_SUMMARY_HEALTHY), contentType: 'application/json', }, - [URLS.llmGatewayLiveness]: { - body: LLM_GATEWAY_LIVENESS_BODY, - contentType: 'application/json', - }, [URLS.mcpLanding]: { body: MCP_LANDING_HTML, contentType: 'text/html; charset=utf-8', @@ -722,54 +712,64 @@ describe('health-checks', () => { }); // ----------------------------------------------------------------------- - // LLM Gateway (fetchEndpointHealth – /_liveness) + // fetchEndpointHealth (retry + status-taxonomy machinery, probed directly + // against a synthetic URL — no production probe uses the strict defaults + // any more, but every endpoint check shares this loop) // ----------------------------------------------------------------------- - describe('checkLlmGatewayHealth', () => { - it('returns healthy when gateway responds 200 with {"status":"alive"}', async () => { - const result = await checkLlmGatewayHealth(); + describe('fetchEndpointHealth', () => { + const PROBE_URL = 'https://probe.posthog.test/_liveness'; + + it('returns healthy on a 200', async () => { + (global.fetch as Mock).mockImplementation( + overrideFetch({ + [PROBE_URL]: () => + Promise.resolve(new Response('ok', { status: 200 })), + }), + ); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.Healthy); expect(result.rawIndicator).toBe('HTTP 200'); expect(global.fetch).toHaveBeenCalledWith( - URLS.llmGatewayLiveness, + PROBE_URL, expect.objectContaining({ signal: expect.any(AbortSignal) }), ); }); - it('returns down on 302 — the gateway probe stays strict, redirects are not OK here', async () => { + it('returns down on 302 — the default predicate stays strict, redirects are not OK', async () => { (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => + [PROBE_URL]: () => Promise.resolve(new Response(null, { status: 302 })), }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.Down); expect(result.error).toContain('HTTP 302'); }); - it('returns down when gateway responds 503 (e.g. deploying)', async () => { + it('returns down when the endpoint responds 503 (e.g. deploying)', async () => { (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => + [PROBE_URL]: () => Promise.resolve( new Response('Service Unavailable', { status: 503 }), ), }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.Down); expect(result.error).toContain('HTTP 503'); }); - it('returns down when gateway responds 502 (bad gateway)', async () => { + it('returns down when the endpoint responds 502 (bad gateway)', async () => { (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => + [PROBE_URL]: () => Promise.resolve(new Response('Bad Gateway', { status: 502 })), }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.Down); expect(result.error).toContain('HTTP 502'); }); @@ -777,15 +777,15 @@ describe('health-checks', () => { it('returns no-connection on DNS resolution failure (no status-page corroboration)', async () => { (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => + [PROBE_URL]: () => Promise.reject( - new Error('getaddrinfo ENOTFOUND gateway.us.posthog.com'), + new Error('getaddrinfo ENOTFOUND probe.posthog.test'), ), }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.NoConnection); - expect(result.error).toBe('getaddrinfo ENOTFOUND gateway.us.posthog.com'); + expect(result.error).toBe('getaddrinfo ENOTFOUND probe.posthog.test'); }); it('returns no-connection on timeout (AbortError)', async () => { @@ -793,10 +793,10 @@ describe('health-checks', () => { abortError.name = 'AbortError'; (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => Promise.reject(abortError), + [PROBE_URL]: () => Promise.reject(abortError), }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.NoConnection); expect(result.error).toBe('Request timed out after 5000ms'); }); @@ -805,18 +805,16 @@ describe('health-checks', () => { let calls = 0; (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => { + [PROBE_URL]: () => { calls++; if (calls < 3) { return Promise.reject(new Error('ECONNRESET')); } - return Promise.resolve( - new Response(LLM_GATEWAY_LIVENESS_BODY, { status: 200 }), - ); + return Promise.resolve(new Response('ok', { status: 200 })); }, }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.Healthy); expect(result.rawIndicator).toContain('attempts=3'); expect(calls).toBe(3); @@ -826,7 +824,7 @@ describe('health-checks', () => { let calls = 0; (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => { + [PROBE_URL]: () => { calls++; return Promise.resolve( new Response('Service Unavailable', { status: 503 }), @@ -834,7 +832,7 @@ describe('health-checks', () => { }, }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.Down); expect(calls).toBe(3); expect(result.error).toContain('HTTP 503'); @@ -845,20 +843,18 @@ describe('health-checks', () => { let calls = 0; (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => { + [PROBE_URL]: () => { calls++; if (calls < 3) { return Promise.resolve( new Response('Bad Gateway', { status: 502 }), ); } - return Promise.resolve( - new Response(LLM_GATEWAY_LIVENESS_BODY, { status: 200 }), - ); + return Promise.resolve(new Response('ok', { status: 200 })); }, }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.Healthy); expect(result.rawIndicator).toContain('attempts=3'); expect(calls).toBe(3); @@ -868,7 +864,7 @@ describe('health-checks', () => { let calls = 0; (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => { + [PROBE_URL]: () => { calls++; if (calls < 3) return Promise.reject(new Error('ECONNRESET')); return Promise.resolve( @@ -877,7 +873,7 @@ describe('health-checks', () => { }, }), ); - const result = await checkLlmGatewayHealth(); + const result = await fetchEndpointHealth(PROBE_URL); expect(result.status).toBe(ServiceHealthStatus.Down); expect(result.error).toContain('HTTP 502'); }); @@ -1082,7 +1078,7 @@ describe('health-checks', () => { // ----------------------------------------------------------------------- describe('checkAllExternalServices', () => { - it('returns all 11 service keys when everything is healthy', async () => { + it('returns all 10 service keys when everything is healthy', async () => { const health = await checkAllExternalServices(); const keys = Object.keys(health); expect(keys).toEqual( @@ -1095,18 +1091,17 @@ describe('health-checks', () => { 'npmComponents', 'cloudflareOverall', 'cloudflareComponents', - 'llmGateway', 'mcp', 'skillsOrigin', ]), ); - expect(keys).toHaveLength(11); + expect(keys).toHaveLength(10); for (const val of Object.values(health)) { expect(val.status).toBe(ServiceHealthStatus.Healthy); } }); - it('upgrades NoConnection llmGateway/mcp to Down when status page reports an outage', async () => { + it('upgrades NoConnection mcp to Down when status page reports an outage', async () => { const incidentBody = { ...POSTHOG_INCIDENTIO_HEALTHY, ongoing_incidents: [ @@ -1128,20 +1123,17 @@ describe('health-checks', () => { Promise.resolve( new Response(JSON.stringify(incidentBody), { status: 200 }), ), - [URLS.llmGatewayLiveness]: () => - Promise.reject(new Error('ECONNRESET')), [URLS.mcpLanding]: () => Promise.reject(new Error('ECONNRESET')), }), ); const health = await checkAllExternalServices(); expect(health.posthogOverall.status).toBe(ServiceHealthStatus.Down); - expect(health.llmGateway.status).toBe(ServiceHealthStatus.Down); - expect(health.llmGateway.error).toContain('corroborated by status page'); expect(health.mcp.status).toBe(ServiceHealthStatus.Down); + expect(health.mcp.error).toContain('corroborated by status page'); }); - it('keeps llmGateway/mcp as NoConnection when posthogstatus.com itself is unreachable (the bug-fix scenario)', async () => { + it('keeps mcp as NoConnection when posthogstatus.com itself is unreachable (the bug-fix scenario)', async () => { // User on flaky wifi: every PostHog-owned URL fetch fails at the // network layer, including posthogstatus.com. Previously // incidentio.ts returned Degraded for fetch failures, which @@ -1152,8 +1144,6 @@ describe('health-checks', () => { overrideFetch({ [URLS.posthogIncidentIo]: () => Promise.reject(new Error('ECONNRESET')), - [URLS.llmGatewayLiveness]: () => - Promise.reject(new Error('ECONNRESET')), [URLS.mcpLanding]: () => Promise.reject(new Error('ECONNRESET')), }), ); @@ -1162,22 +1152,18 @@ describe('health-checks', () => { expect(health.posthogOverall.status).toBe( ServiceHealthStatus.NoConnection, ); - expect(health.llmGateway.status).toBe(ServiceHealthStatus.NoConnection); expect(health.mcp.status).toBe(ServiceHealthStatus.NoConnection); }); - it('keeps llmGateway/mcp as NoConnection when status page reports no incident', async () => { + it('keeps mcp as NoConnection when status page reports no incident', async () => { (global.fetch as Mock).mockImplementation( overrideFetch({ - [URLS.llmGatewayLiveness]: () => - Promise.reject(new Error('ETIMEDOUT')), [URLS.mcpLanding]: () => Promise.reject(new Error('ETIMEDOUT')), }), ); const health = await checkAllExternalServices(); expect(health.posthogOverall.status).toBe(ServiceHealthStatus.Healthy); - expect(health.llmGateway.status).toBe(ServiceHealthStatus.NoConnection); expect(health.mcp.status).toBe(ServiceHealthStatus.NoConnection); }); @@ -1187,9 +1173,8 @@ describe('health-checks', () => { typeof c[0] === 'string' ? c[0] : (c[0] as URL).toString(), ); // PostHog uses a single incident.io endpoint for both overall + components - expect(calledUrls).toHaveLength(11); + expect(calledUrls).toHaveLength(10); expect(calledUrls).toContain(URLS.posthogIncidentIo); - expect(calledUrls).toContain(URLS.llmGatewayLiveness); expect(calledUrls).toContain(URLS.mcpLanding); expect(calledUrls).toContain(URLS.githubSkillMenu); expect(calledUrls).toContain(URLS.awsSkillMenu); @@ -1231,22 +1216,6 @@ describe('health-checks', () => { expect(result.health.anthropic.status).toBe(ServiceHealthStatus.Degraded); }); - it('returns No when LLM Gateway is down (downBlocksRun)', async () => { - (global.fetch as Mock).mockImplementation( - overrideFetch({ - [URLS.llmGatewayLiveness]: () => - Promise.resolve( - new Response('Service Unavailable', { status: 503 }), - ), - }), - ); - const result = await evaluateWizardReadiness( - DEFAULT_WIZARD_READINESS_CONFIG, - ); - expect(result.decision).toBe(WizardReadiness.No); - expect(result.health.llmGateway.status).toBe(ServiceHealthStatus.Down); - }); - it('returns No when MCP is down (downBlocksRun)', async () => { (global.fetch as Mock).mockImplementation( overrideFetch({ @@ -1316,7 +1285,6 @@ describe('health-checks', () => { expect(result.reasons.some((r) => r.includes('GitHub'))).toBe(true); expect(result.reasons.some((r) => r.includes('npm'))).toBe(true); expect(result.reasons.some((r) => r.includes('Cloudflare'))).toBe(true); - expect(result.reasons.some((r) => r.includes('LLM Gateway'))).toBe(true); expect(result.reasons.some((r) => r.includes('MCP'))).toBe(true); }); }); diff --git a/src/lib/health-checks/endpoints.ts b/src/lib/health-checks/endpoints.ts index ccb2fa168..2be4c5df9 100644 --- a/src/lib/health-checks/endpoints.ts +++ b/src/lib/health-checks/endpoints.ts @@ -13,10 +13,6 @@ import { ServiceHealthStatus, type BaseHealthResult } from './types'; // NoConnection means we don't know whose fault it is; readiness reconciles // against the status page before deciding how to surface it to the user. // -// LLM Gateway – FastAPI service -// Source: posthog/services/llm-gateway/src/llm_gateway/api/health.py -// GET /_liveness → 200 {"status":"alive"} -// // MCP – Cloudflare Worker // Source: posthog/services/mcp/src/index.ts // GET / → 302 to posthog.com docs. The redirect proves the worker is up. @@ -65,7 +61,8 @@ async function attemptFetch( } } -async function fetchEndpointHealth( +// Exported so tests can pin the retry/taxonomy machinery directly. +export async function fetchEndpointHealth( url: string, timeoutMs = 5000, isExpectedStatus: (status: number) => boolean = (s) => s === 200, @@ -137,9 +134,6 @@ async function fetchEndpointHealth( return result; } -export const checkLlmGatewayHealth = (): Promise => - fetchEndpointHealth('https://gateway.us.posthog.com/_liveness'); - export const checkMcpHealth = (): Promise => fetchEndpointHealth( 'https://mcp.posthog.com/', diff --git a/src/lib/health-checks/index.ts b/src/lib/health-checks/index.ts index be2d40e81..b4c3f6041 100644 --- a/src/lib/health-checks/index.ts +++ b/src/lib/health-checks/index.ts @@ -22,11 +22,7 @@ export { resetPosthogHealthCache, } from './incidentio'; -export { - checkLlmGatewayHealth, - checkMcpHealth, - checkSkillsOriginHealth, -} from './endpoints'; +export { checkMcpHealth, checkSkillsOriginHealth } from './endpoints'; export { type WizardReadinessConfig, diff --git a/src/lib/health-checks/readiness.ts b/src/lib/health-checks/readiness.ts index 018cf84dd..6cd883678 100644 --- a/src/lib/health-checks/readiness.ts +++ b/src/lib/health-checks/readiness.ts @@ -17,11 +17,7 @@ import { checkPosthogOverallHealth, checkPosthogComponentHealth, } from './incidentio'; -import { - checkLlmGatewayHealth, - checkMcpHealth, - checkSkillsOriginHealth, -} from './endpoints'; +import { checkMcpHealth, checkSkillsOriginHealth } from './endpoints'; import { logToFile } from '@utils/debug'; // --------------------------------------------------------------------------- @@ -37,7 +33,6 @@ export const SERVICE_LABELS: Record = { npmComponents: 'npm (components)', cloudflareOverall: 'Cloudflare', cloudflareComponents: 'Cloudflare (components)', - llmGateway: 'LLM Gateway', mcp: 'MCP', skillsOrigin: 'Skills download', }; @@ -56,26 +51,24 @@ export interface WizardReadinessConfig { /** * See README section "Health checks" for the full rationale. * Adjust these arrays to change what blocks a wizard run. + * + * The AI gateway is not probed: its URL is only known from the run's token + * mint, and a failed mint already stops the run at bootstrap with the + * server's reason. */ export const DEFAULT_WIZARD_READINESS_CONFIG: WizardReadinessConfig = { - downBlocksRun: [ - 'anthropic', - 'npmOverall', - 'llmGateway', - 'mcp', - 'skillsOrigin', - ], + downBlocksRun: ['anthropic', 'npmOverall', 'mcp', 'skillsOrigin'], degradedBlocksRun: ['anthropic'], }; /** * Reduced readiness config for --signup provisioning flows. * - * Provisioning only needs PostHog and the LLM Gateway - it doesn't - * use Anthropic directly, npm, the skills origins, or MCP. + * Provisioning only needs PostHog - it doesn't use Anthropic directly, npm, + * the skills origins, or MCP. */ export const SIGNUP_WIZARD_READINESS_CONFIG: WizardReadinessConfig = { - downBlocksRun: ['posthogOverall', 'llmGateway'], + downBlocksRun: ['posthogOverall'], }; // --------------------------------------------------------------------------- @@ -92,7 +85,6 @@ export async function checkAllExternalServices(): Promise { npmComponents, cloudflareOverall, cloudflareComponents, - llmGateway, mcp, skillsOrigin, ] = await Promise.all([ @@ -104,7 +96,6 @@ export async function checkAllExternalServices(): Promise { checkNpmComponentHealth(), checkCloudflareOverallHealth(), checkCloudflareComponentHealth(), - checkLlmGatewayHealth(), checkMcpHealth(), checkSkillsOriginHealth(), ]); @@ -118,7 +109,6 @@ export async function checkAllExternalServices(): Promise { npmComponents, cloudflareOverall, cloudflareComponents, - llmGateway, mcp, skillsOrigin, }; @@ -131,7 +121,7 @@ export async function checkAllExternalServices(): Promise { * official status page (`posthogstatus.com`): * * - Status page says PostHog is `Down` / `Degraded` → upgrade - * llmGateway / mcp to `Down`. The status page corroborates. + * mcp to `Down`. The status page corroborates. * - Status page is `Healthy` → keep `NoConnection`. The status page * contradicts; this is probably the user's network. * - Status page is also `NoConnection` → keep `NoConnection`. User @@ -145,11 +135,11 @@ export async function checkAllExternalServices(): Promise { * when incident.io's API parsed successfully and reported a real * `partial_outage` or `degraded_performance` for some component. That's * PostHog acknowledging an issue, even if narrower than a full outage. - * If our gateway probe is also failing, those two signals together + * If our MCP probe is also failing, those two signals together * justify pointing at PostHog rather than the user. * * A narrower variant — only corroborate when the affected component is - * gateway-related (LLM, US/EU Cloud, app) — would be more precise. We + * MCP-related (US/EU Cloud, app) — would be more precise. We * have the data in `posthogComponents` but don't use it here. If the * analytics show false positives concentrated in this case, it's a * cheap follow-up. @@ -179,7 +169,6 @@ export function reconcilePosthogReachability( return { ...health, - llmGateway: upgrade(health.llmGateway), mcp: upgrade(health.mcp), }; } @@ -346,7 +335,6 @@ function allUnknown(error: string): AllServicesHealth { npmComponents: { ...base }, cloudflareOverall: base, cloudflareComponents: { ...base }, - llmGateway: base, mcp: base, skillsOrigin: base, }; diff --git a/src/lib/health-checks/testme.md b/src/lib/health-checks/testme.md index 7eb5c32a2..9cf6a7202 100644 --- a/src/lib/health-checks/testme.md +++ b/src/lib/health-checks/testme.md @@ -40,7 +40,6 @@ responses captured from production endpoints on 2026-03-05. | npm (components) | `https://status.npmjs.org/api/v2/summary.json` | Adds `components[]` array | | Cloudflare | `https://www.cloudflarestatus.com/api/v2/status.json` | Same shape | | Cloudflare (components) | `https://www.cloudflarestatus.com/api/v2/summary.json` | Adds `components[]` array | -| LLM Gateway | `https://gateway.us.posthog.com/_liveness` | `{"status":"alive"}` (HTTP 200) | | MCP | `https://mcp.posthog.com/` | HTML landing page (HTTP 200) | ### Statuspage.io API v2 reference @@ -54,13 +53,6 @@ responses captured from production endpoints on 2026-03-05. - Component docs: -### LLM Gateway - -- Source: `posthog/services/llm-gateway/src/llm_gateway/api/health.py` -- `GET /` → `{"service":"llm-gateway","status":"running"}` -- `GET /_liveness` → `{"status":"alive"}` (no DB dependency) -- `GET /_readiness` → `{"status":"ready"}` (checks Postgres with `SELECT 1`) - ### MCP - Source: `posthog/services/mcp/src/index.ts` diff --git a/src/lib/health-checks/types.ts b/src/lib/health-checks/types.ts index 02aeed48a..f838bbf96 100644 --- a/src/lib/health-checks/types.ts +++ b/src/lib/health-checks/types.ts @@ -37,7 +37,6 @@ export interface AllServicesHealth { npmComponents: ComponentHealthResult; cloudflareOverall: BaseHealthResult; cloudflareComponents: ComponentHealthResult; - llmGateway: BaseHealthResult; mcp: BaseHealthResult; skillsOrigin: BaseHealthResult; } diff --git a/src/ui/tui/playground/demos/HealthCheckDemo.tsx b/src/ui/tui/playground/demos/HealthCheckDemo.tsx index 03c7064db..501f6972c 100644 --- a/src/ui/tui/playground/demos/HealthCheckDemo.tsx +++ b/src/ui/tui/playground/demos/HealthCheckDemo.tsx @@ -44,7 +44,6 @@ const MOCK_CONFIRMED_OUTAGE: AllServicesHealth = { }, cloudflareOverall: HEALTHY, cloudflareComponents: { status: ServiceHealthStatus.Healthy }, - llmGateway: HEALTHY, mcp: HEALTHY, skillsOrigin: HEALTHY, }; @@ -58,10 +57,6 @@ const MOCK_NO_CONNECTION: AllServicesHealth = { npmComponents: { status: ServiceHealthStatus.Healthy }, cloudflareOverall: HEALTHY, cloudflareComponents: { status: ServiceHealthStatus.Healthy }, - llmGateway: { - status: ServiceHealthStatus.NoConnection, - error: 'getaddrinfo ENOTFOUND gateway.us.posthog.com', - }, mcp: { status: ServiceHealthStatus.NoConnection, error: 'fetch failed', diff --git a/src/ui/tui/store.ts b/src/ui/tui/store.ts index 1f2f8a16f..12cf174ab 100644 --- a/src/ui/tui/store.ts +++ b/src/ui/tui/store.ts @@ -156,7 +156,7 @@ function captureHealthCheckBlocked(result: WizardReadinessResult): void { const posthogStatus = health.posthogOverall?.status; const retriesUsed = Math.max( 0, - ...(['llmGateway', 'mcp', 'skillsOrigin'] as const).map((k) => { + ...(['mcp', 'skillsOrigin'] as const).map((k) => { const ind = health[k]?.rawIndicator ?? ''; const m = ind.match(/attempts=(\d+)/); return m ? Number(m[1]) - 1 : 0;