Symptom
On a live showcase host, /discovery reports:
capabilities.search = { "enabled": false }
services.search = { "enabled": false, "status": "unavailable", ... }
while the endpoint those bits describe is fully live:
GET /api/v1/search?q=audit → 200, 5 real hits
Expected: the declared capability matches served behaviour (Prime Directive #10, declared === enforced) — either the bit is enabled: true, or the endpoint refuses.
Impact: a client that trusts the discovery document — which is exactly what the document is for — skips a working surface. This is the failure mode discovery exists to prevent, inverted: not an advertised endpoint that 404s, but a real endpoint no conforming client will ever call.
Root cause
The capability bit derives from a registered search service slot — search: registeredServices.has('search') in the well-known capability builder (packages/metadata-protocol/src/protocol.ts) — while the route (registerSearchEndpoints, packages/rest/src/rest-server.ts) gates on something else entirely: it only answers 501 NOT_IMPLEMENTED when protocol.searchAll is missing, and the protocol implements searchAllregardless of whether any search service slot is registered. The two producers answer the same question with two unrelated predicates.
Note the neighbouring keys in that same builder are already serveability-gated with a comment stating the rule ("the predicate is deliberately the SAME one that decides whether the route is advertised — what we advertise and what we claim cannot disagree"; chunkedUpload was moved onto it in #5672). search is one of the keys still on bare slot presence, and its route does not consult the slot at all — so the fix must pick ONE predicate for both ends: either derive the bit from typeof protocol.searchAll === 'function', or make the route honour the slot. Primary lane is the capability builder in packages/metadata-protocol; the seam reaches packages/rest.
Reproduction
- Boot showcase on a fresh isolated file DB (
SqlDriver / better-sqlite3); authenticate as admin@objectos.ai. GET /api/v1/discovery → capabilities.search.enabled === false, services.search.status === "unavailable".GET /api/v1/search?q=audit → 200 with 5 real hits.
Source
Extracted from the QA run #7463 (framework a86db17).
Symptom
On a live showcase host,
/discoveryreports:while the endpoint those bits describe is fully live:
Expected: the declared capability matches served behaviour (Prime Directive #10,
declared === enforced) — either the bit isenabled: true, or the endpoint refuses.Impact: a client that trusts the discovery document — which is exactly what the document is for — skips a working surface. This is the failure mode discovery exists to prevent, inverted: not an advertised endpoint that 404s, but a real endpoint no conforming client will ever call.
Root cause
The capability bit derives from a registered
searchservice slot —search: registeredServices.has('search')in the well-known capability builder (packages/metadata-protocol/src/protocol.ts) — while the route (registerSearchEndpoints,packages/rest/src/rest-server.ts) gates on something else entirely: it only answers501 NOT_IMPLEMENTEDwhenprotocol.searchAllis missing, and the protocol implementssearchAllregardless of whether anysearchservice slot is registered. The two producers answer the same question with two unrelated predicates.Note the neighbouring keys in that same builder are already serveability-gated with a comment stating the rule ("the predicate is deliberately the SAME one that decides whether the route is advertised — what we advertise and what we claim cannot disagree";
chunkedUploadwas moved onto it in #5672).searchis one of the keys still on bare slot presence, and its route does not consult the slot at all — so the fix must pick ONE predicate for both ends: either derive the bit fromtypeof protocol.searchAll === 'function', or make the route honour the slot. Primary lane is the capability builder inpackages/metadata-protocol; the seam reachespackages/rest.Reproduction
SqlDriver/ better-sqlite3); authenticate asadmin@objectos.ai.GET /api/v1/discovery→capabilities.search.enabled === false,services.search.status === "unavailable".GET /api/v1/search?q=audit→200with 5 real hits.Source
Extracted from the QA run #7463 (framework a86db17).