Found while implementing #10255 (out of scope there: that card is the capability gate only).
What is true at head
packages/rest/src/external-datasource-routes.ts — the validate route's handler calls svc.validateAll() and then filters the report to the URL's datasource:
validateAll() (packages/services/service-datasource/src/external-datasource-service.ts) lists every federated object across every datasource and validates each one, where per-object validation drives introspect(datasource) — a live remote-schema read against that datasource's remote.- The route then keeps only
r.datasource === req.params.name rows and discards the rest.
So a request scoped by its URL to one datasource performs live remote introspection against all federated datasources, and throws away most of what it measured. The header comment's own words are validateAll (this ds) — the "this ds" half is done by post-filtering, not by scoping the work.
Why it is shaped this way
IExternalDatasourceService (packages/spec/src/contracts/external-datasource-service.ts) offers validateObject(objectName) and validateAll() — there is no per-datasource validate. The route does the best the contract offers.
Why it matters (and why it is not urgent)
Possible directions (triage's call)
- Add a per-datasource validate to the contract (e.g. validate objects whose
datasource matches, reusing validateObject) and have the route call it. Contract change — needs the usual spec discipline. - Compose in the route/service from existing primitives:
listObjects → filter by datasource → validateObject each. No contract change; duplicates validateAll's parallelisation. - Leave it and document the fan-out on the route — cheapest, keeps the wart.
Backlinks: #10255 (capability gate; where this was noticed) · #4264 (this family's failure-contract history).
Unassigned — filed for triage to level and route.
Generated by Claude Code
Found while implementing #10255 (out of scope there: that card is the capability gate only).
What is true at head
packages/rest/src/external-datasource-routes.ts— the validate route's handler callssvc.validateAll()and then filters the report to the URL's datasource:validateAll()(packages/services/service-datasource/src/external-datasource-service.ts) lists every federated object across every datasource and validates each one, where per-object validation drivesintrospect(datasource)— a live remote-schema read against that datasource's remote.r.datasource === req.params.namerows and discards the rest.So a request scoped by its URL to one datasource performs live remote introspection against all federated datasources, and throws away most of what it measured. The header comment's own words are
validateAll (this ds)— the "this ds" half is done by post-filtering, not by scoping the work.Why it is shaped this way
IExternalDatasourceService(packages/spec/src/contracts/external-datasource-service.ts) offersvalidateObject(objectName)andvalidateAll()— there is no per-datasource validate. The route does the best the contract offers.Why it matters (and why it is not urgent)
manage_platform_settings, which entitles the caller to introspect any datasource via the tables route anyway. Before that gate the cross-datasource work was still not caller-visible (results filtered), so this is filed as a shape/cost card, not a security card.Possible directions (triage's call)
datasourcematches, reusingvalidateObject) and have the route call it. Contract change — needs the usual spec discipline.listObjects→ filter by datasource →validateObjecteach. No contract change; duplicatesvalidateAll's parallelisation.Backlinks: #10255 (capability gate; where this was noticed) · #4264 (this family's failure-contract history).
Unassigned — filed for triage to level and route.
Generated by Claude Code