Found by the #3587 tranche-2 audit; ledgered as mismatch in packages/rest/src/rest-route-ledger.ts (PR #3609).
The split
- REST mounts
GET /api/v1/ui/view/:object/:type — type as a path segment (rest-server.ts:3396; 501 when protocol.getUiView is absent).
- The SDK (
client.meta.getView, packages/client/src/index.ts:522-524) sends GET /ui/view/:object?type= — type as a query param.
- The dispatcher
/ui domain accepts both forms (domains/ui.ts:32-50; dispatcher ledger row GET /ui/view/:object/:type?).
So the SDK's request pattern (two path segments, not three) never matches REST's route; it falls through to the dispatcher, which answers. REST's route is dead weight for the SDK — and in project-scoped mode, where REST is the only surface registered under /api/v1/environments/:environmentId, a scoped query-dialect call would have no server at all (the scoped client currently exposes no getView, so this is latent, not live).
Fix options
- A (recommended): client switches to the path dialect —
meta.getView builds /ui/view/:object/:type. Both surfaces already accept it (dispatcher's :type? is optional-typed), no server change, non-breaking on the wire. One-line client change + tests.
- B: REST additionally registers the query form (
GET /ui/view/:object). Keeps two dialects alive forever.
- C: retire REST's ui route and let the dispatcher own
/ui. Blocked on scoped-mode coverage (the dispatcher does not strip /environments/:id, http-dispatcher.ts:1223).
Acceptance
meta.getView provably reaches both surfaces (unit test asserts the built URL; conformance row flips mismatch → sdk).
- Both route ledgers updated and green.
Refs: #3587, PR #3609.
Found by the #3587 tranche-2 audit; ledgered as
mismatchinpackages/rest/src/rest-route-ledger.ts(PR #3609).The split
GET /api/v1/ui/view/:object/:type— type as a path segment (rest-server.ts:3396; 501 whenprotocol.getUiViewis absent).client.meta.getView,packages/client/src/index.ts:522-524) sendsGET /ui/view/:object?type=— type as a query param./uidomain accepts both forms (domains/ui.ts:32-50; dispatcher ledger rowGET /ui/view/:object/:type?).So the SDK's request pattern (two path segments, not three) never matches REST's route; it falls through to the dispatcher, which answers. REST's route is dead weight for the SDK — and in project-scoped mode, where REST is the only surface registered under
/api/v1/environments/:environmentId, a scoped query-dialect call would have no server at all (the scoped client currently exposes nogetView, so this is latent, not live).Fix options
meta.getViewbuilds/ui/view/:object/:type. Both surfaces already accept it (dispatcher's:type?is optional-typed), no server change, non-breaking on the wire. One-line client change + tests.GET /ui/view/:object). Keeps two dialects alive forever./ui. Blocked on scoped-mode coverage (the dispatcher does not strip/environments/:id,http-dispatcher.ts:1223).Acceptance
meta.getViewprovably reaches both surfaces (unit test asserts the built URL; conformance row flipsmismatch→sdk).Refs: #3587, PR #3609.