Skip to content

[finding] discovery contradicts itself under a non-default crud.dataPrefix: routes.data follows the key, services.data.route stays hard-coded at /api/v1/data #16674

Description

@claude

Found while implementing #14879 (the client SDK half of this same key). Not that PR's change and not addressed there; filed so it is not buried.

Measured, on a live server

Booting createRestApiPlugin with crud: { dataPrefix: '/objects' } and reading GET /api/v1/discovery, the one document reports the data routes in two places and they disagree:

Producer

packages/metadata-protocol/src/protocol.ts:5740 writes route: '/api/v1/data' as a literal into the services.data slot. The REST discovery handler's substitution pass only rewrites discovery.routes.* -- routes.data, routes.metadata, routes.ui, routes.mcp -- so the services block is never brought in line with the mounted paths and keeps the conventional literal whatever the deployment configured.

(Locate by symbol, not by line -- rest-server.ts line numbers have been moving.)

Why this is a defect and not an observation

The liveness ledger classifies crud_endpoints' dataPrefix live because it "has five independent consumers and moves the mounted paths and the advertised discovery document together", and #14691 retired patterns and objectParamStyle on the reasoning that "the mounted CRUD paths are the contract the client SDK, the discovery document and /openapi.json all describe -- a per-operation pattern knob could only make them lie." Here the discovery document lies to itself: a reader that trusts services.data.route is pointed at an unmounted path by the very document whose job is to say where the routes are.

Nearest neighbour is #4318 (discovery slots declaring routes that contradict their own handlerReady), same block, different subject -- that one is about routes that do not exist at all, this one is about a route that exists somewhere else.

Why it was not fixed in the #14879 PR

Scope: #14879's face is the client SDK, and this producer is in packages/metadata-protocol. The in-place exemption also fails on its own terms -- packages/rest/src/rest-server.ts, which owns the substitution pass this would extend, is held by open PR #16628.

What a fix would decide (not decided here)

Either the substitution pass is extended to the services block so both halves of the document follow the mounted paths, or services.*.route is declared as a conventional hint rather than an address and its consumers are checked against that reading. The first keeps one answer in the document; the second needs the consumers audited. Contract decision -- triage routes.


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions