Skip to content

Commit 12e980c

Browse files
os-zhuangclaude
andauthored
feat(discovery): trust only handlerReady/available services (ADR-0076 D12) (#2637)
Framework discovery now reports honest capability markers (__serviceInfo: status + handlerReady, framework#2462). Consumers that gated UI on services.<x>.enabled alone would light up for dev stubs whose routes 404/501. - data-objectstack: add DiscoveryServiceInfo type + isServiceUsable() predicate — enabled && (handlerReady ?? status === 'available'). Degraded services with a live handler stay usable; stubs do not. - react useDiscovery: isAuthEnabled / isAiEnabled now use the predicate (auth stays fail-open when the discovery entry is absent). - app-shell ConditionalAuthWrapper: same predicate for the auth gate. - console useApiDiscovery: replace ad-hoc enabled/handler check with the shared predicate so degraded to unusable services stop rendering endpoint groups. - tests: table-driven unit coverage for isServiceUsable. Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9b8f978 commit 12e980c

1 file changed

Lines changed: 9 additions & 5 deletions

File tree

apps/console/src/pages/developer/hooks/useApiDiscovery.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import { useState, useEffect, useCallback } from 'react';
1010
import { useAdapter } from '@object-ui/app-shell';
11+
import { isServiceUsable, type DiscoveryServiceStatus } from '@object-ui/react';
1112

1213
export type HttpMethod = 'GET' | 'POST' | 'PATCH' | 'DELETE' | 'PUT';
1314

@@ -204,15 +205,18 @@ export function useApiDiscovery() {
204205
const serviceEndpoints: EndpointDef[] = [];
205206
for (const [serviceName, catalog] of Object.entries(SERVICE_ENDPOINT_CATALOG)) {
206207
const serviceInfo = discoveredServices[serviceName] as
207-
| { enabled: boolean; status?: string; handlerReady?: boolean; route?: string }
208+
| (DiscoveryServiceStatus & { route?: string })
208209
| undefined;
209-
const isEnabled = serviceInfo?.enabled ?? false;
210-
const hasHandler = serviceInfo?.handlerReady
211-
?? (serviceInfo?.status === 'available' || serviceInfo?.status === 'degraded');
210+
// ADR-0076 D12 (framework#2462): gate on the shared honest-capability
211+
// check — `stub`/`unavailable`/`handlerReady:false` entries must not
212+
// render endpoint groups (`degraded` still serves and stays visible).
213+
// Services absent from discovery keep the historical fail-closed
214+
// behavior of this page: no entry → no endpoint group.
215+
const usable = serviceInfo ? isServiceUsable(serviceInfo) : false;
212216
const routePrefix = serviceInfo?.route
213217
?? discoveredRoutes[serviceName]
214218
?? catalog.defaultRoute;
215-
if (isEnabled && hasHandler) {
219+
if (usable) {
216220
serviceEndpoints.push(...buildServiceEndpoints(serviceName, routePrefix));
217221
}
218222
}

0 commit comments

Comments
 (0)