@@ -59,6 +59,25 @@ export class HttpDispatcher {
5959 } ;
6060 }
6161
62+ /**
63+ * 404 Route Not Found — no route is registered for this path.
64+ */
65+ private routeNotFound ( route : string ) {
66+ return {
67+ status : 404 ,
68+ body : {
69+ success : false ,
70+ error : {
71+ code : 404 ,
72+ message : `Route Not Found: ${ route } ` ,
73+ type : 'ROUTE_NOT_FOUND' as const ,
74+ route,
75+ hint : 'No route is registered for this path. Check the API discovery endpoint for available routes.' ,
76+ } ,
77+ } ,
78+ } ;
79+ }
80+
6281 private ensureBroker ( ) {
6382 if ( ! this . kernel . broker ) {
6483 throw { statusCode : 500 , message : 'Kernel Broker not available' } ;
@@ -133,11 +152,14 @@ export class HttpDispatcher {
133152 } ;
134153
135154 // Build per-service status map
155+ // handlerReady: true means the dispatcher has a real, bound handler for this route.
156+ // handlerReady: false means the route is present in the discovery table but may not
157+ // yet have a concrete implementation or may be served by a stub.
136158 const svcAvailable = ( route ?: string , provider ?: string ) => ( {
137- enabled : true , status : 'available' as const , route, provider,
159+ enabled : true , status : 'available' as const , handlerReady : true , route, provider,
138160 } ) ;
139161 const svcUnavailable = ( name : string ) => ( {
140- enabled : false , status : 'unavailable' as const ,
162+ enabled : false , status : 'unavailable' as const , handlerReady : false ,
141163 message : `Install a ${ name } plugin to enable` ,
142164 } ) ;
143165
@@ -174,7 +196,7 @@ export class HttpDispatcher {
174196 } ,
175197 services : {
176198 // Kernel-provided (always available via protocol implementation)
177- metadata : { enabled : true , status : 'degraded' as const , route : routes . metadata , provider : 'kernel' , message : 'In-memory registry; DB persistence pending' } ,
199+ metadata : { enabled : true , status : 'degraded' as const , handlerReady : true , route : routes . metadata , provider : 'kernel' , message : 'In-memory registry; DB persistence pending' } ,
178200 data : svcAvailable ( routes . data , 'kernel' ) ,
179201 // Plugin-provided — only available when a plugin registers the service
180202 auth : hasAuth ? svcAvailable ( routes . auth ) : svcUnavailable ( 'auth' ) ,
@@ -1207,6 +1229,19 @@ export class HttpDispatcher {
12071229 } ;
12081230 }
12091231
1232+ // 0b. Health Endpoint (GET /health)
1233+ if ( cleanPath === '/health' && method === 'GET' ) {
1234+ return {
1235+ handled : true ,
1236+ response : this . success ( {
1237+ status : 'ok' ,
1238+ timestamp : new Date ( ) . toISOString ( ) ,
1239+ version : '1.0.0' ,
1240+ uptime : typeof process !== 'undefined' ? process . uptime ( ) : undefined ,
1241+ } ) ,
1242+ } ;
1243+ }
1244+
12101245 // 1. System Protocols (Prefix-based)
12111246 if ( cleanPath . startsWith ( '/auth' ) ) {
12121247 return this . handleAuth ( cleanPath . substring ( 5 ) , method , body , context ) ;
@@ -1265,8 +1300,11 @@ export class HttpDispatcher {
12651300 const result = await this . handleApiEndpoint ( cleanPath , method , body , query , context ) ;
12661301 if ( result . handled ) return result ;
12671302
1268- // 3. Fallback (404)
1269- return { handled : false } ;
1303+ // 3. Fallback — return semantic 404 with diagnostic info
1304+ return {
1305+ handled : true ,
1306+ response : this . routeNotFound ( cleanPath ) ,
1307+ } ;
12701308 }
12711309
12721310 /**
0 commit comments