Found while implementing #10537 (out of scope there: that card scoped the REST route's work to the URL's datasource; this is the residual cost inside one datasource).
What is true at head
packages/services/service-datasource/src/external-datasource-service.ts — validateObject(objectName) (:345) reads the live remote schema for the object's datasource on every call:
constschema=awaitthis.config.introspect(datasource);
There is no memoisation, so the sweep (validateAll, and since PR #10960 the scoped validateDatasource) performs one introspect(datasource) per object, all in flight at once via Promise.all. A datasource with 20 federated objects is introspected 20 times per validation, concurrently, against the same remote.
In production introspect resolves to IDataEngine.introspectDatasource(datasource) (wired in plugin.ts), i.e. a real driver round-trip, not a cached read.
The contract's own wording reads the other way
packages/spec/src/contracts/external-datasource-service.ts:157 documents validateAll as:
Validate every federated object, parallelised per datasource.
The parallelism is per object; nothing is shared per datasource. Whichever way this is resolved, the doc line and the implementation should stop disagreeing — a reader sizing the cost of a validation sweep from that sentence gets the wrong number by a factor of the object count.
Not fixed in #10537
That card's fix narrows which datasources are dialled (one, not N); this is how many times the one is dialled. Folding a memo into the sweep changes when a remote is read within a single validation — an observable-timing change with its own test surface — so it is filed rather than ridden in.
If taken, the shape to consider is a per-call (not per-instance) introspection memo threaded through the sweep, so a long-lived service never serves a stale schema to a later validation, plus the doc-line correction above.
Unassigned — filed for triage to level and route.
Generated by Claude Code
Found while implementing #10537 (out of scope there: that card scoped the REST route's work to the URL's datasource; this is the residual cost inside one datasource).
What is true at head
packages/services/service-datasource/src/external-datasource-service.ts—validateObject(objectName)(:345) reads the live remote schema for the object's datasource on every call:There is no memoisation, so the sweep (
validateAll, and since PR #10960 the scopedvalidateDatasource) performs oneintrospect(datasource)per object, all in flight at once viaPromise.all. A datasource with 20 federated objects is introspected 20 times per validation, concurrently, against the same remote.In production
introspectresolves toIDataEngine.introspectDatasource(datasource)(wired inplugin.ts), i.e. a real driver round-trip, not a cached read.The contract's own wording reads the other way
packages/spec/src/contracts/external-datasource-service.ts:157documentsvalidateAllas:The parallelism is per object; nothing is shared per datasource. Whichever way this is resolved, the doc line and the implementation should stop disagreeing — a reader sizing the cost of a validation sweep from that sentence gets the wrong number by a factor of the object count.
Not fixed in #10537
That card's fix narrows which datasources are dialled (one, not N); this is how many times the one is dialled. Folding a memo into the sweep changes when a remote is read within a single validation — an observable-timing change with its own test surface — so it is filed rather than ridden in.
If taken, the shape to consider is a per-call (not per-instance) introspection memo threaded through the sweep, so a long-lived service never serves a stale schema to a later validation, plus the doc-line correction above.
Unassigned — filed for triage to level and route.
Generated by Claude Code