Surfaced while implementing #6271 (the kanban's double fetch), in the same measurement run. Filed separately: different package, and the fix changes what SIX child views receive, not one.
The defect
ObjectView's non-grid fetch path builds its expand set from a ref:
// Use a ref instead of the state variable to avoid re-running this effect
// every time the object schema loads — that would cause a double-fetch and
// duplicate events in child views like the calendar.
const expand = buildExpandFields((objectSchemaRef.current as any)?.fields);
objectSchema is resolved by a separate effect, and this effect deliberately omits it from its dependency list ("objectSchema intentionally omitted from deps — read via ref to prevent double-fetch"). So on the one run this effect makes, objectSchemaRef.current is still null, buildExpandFields returns [], and the query goes out with no $expand at all — and, because the effect never re-runs on the schema's arrival, it never goes out with one either.
The comment is accurate about what it bought: it removed the double fetch. What it did not say is what it paid — the expansion, permanently.
Measured
Rendering object-view with defaultViewType: 'kanban' against an instrumented adapter (getObjectSchema resolving in 30ms, find in 30ms), the adapter recorded:
getObjectSchema calls: 2 (ObjectView's own, plus the board it hosts)
find calls : 1
find[0] params : {"$top":100} ← no $expand
Why it is visible
ObjectView hands those rows to the child view as data={data}, which suppresses the child's own fetch. So every non-grid view hosted by ObjectView — kanban, calendar, gallery, timeline, gantt, map — renders from raw foreign-key ids for every lookup / master_detail / user / tree field. On the kanban that lands in resolveDisplay's isOpaqueId suppression, so those values render blank rather than wrong; on the other five the id itself may reach the DOM (unverified per-view, deliberately not widened here).
The shape that gets both
#6271 settled the same trade for ObjectKanban in the other direction, on measurement: the object definition GATES the query instead of refining it afterwards — one query per mount, carrying the expansion the first time. The relevant number is that a schema read is one small GET served from MetadataCache (5-min TTL, concurrent readers coalesced onto one request); measured against the real ObjectStackAdapter over loopback HTTP, 22 reads of one object produced exactly one metadata request and every read after the first returned in 0.01ms. So the ref was not the only way out of the double fetch.
⚠️ Not proposed as ruled — ObjectView's effect has five more dependencies than the kanban's (currentViewType, currentNamedViewConfig, activeView, renderListView, refreshKey), so the gate needs its own read of what a re-run costs there.
Refs: #6271 / the kanban gate that measured this · #6235 (a different defect in the same non-grid fetch path — sort lowering, not expansion).
Generated by Claude Code
Generated by Claude Code
Surfaced while implementing #6271 (the kanban's double fetch), in the same measurement run. Filed separately: different package, and the fix changes what SIX child views receive, not one.
The defect
ObjectView's non-grid fetch path builds its expand set from a ref:objectSchemais resolved by a separate effect, and this effect deliberately omits it from its dependency list ("objectSchema intentionally omitted from deps — read via ref to prevent double-fetch"). So on the one run this effect makes,objectSchemaRef.currentis stillnull,buildExpandFieldsreturns[], and the query goes out with no$expandat all — and, because the effect never re-runs on the schema's arrival, it never goes out with one either.The comment is accurate about what it bought: it removed the double fetch. What it did not say is what it paid — the expansion, permanently.
Measured
Rendering
object-viewwithdefaultViewType: 'kanban'against an instrumented adapter (getObjectSchemaresolving in 30ms,findin 30ms), the adapter recorded:Why it is visible
ObjectViewhands those rows to the child view asdata={data}, which suppresses the child's own fetch. So every non-grid view hosted byObjectView— kanban, calendar, gallery, timeline, gantt, map — renders from raw foreign-key ids for every lookup / master_detail / user / tree field. On the kanban that lands inresolveDisplay'sisOpaqueIdsuppression, so those values render blank rather than wrong; on the other five the id itself may reach the DOM (unverified per-view, deliberately not widened here).The shape that gets both
#6271 settled the same trade for
ObjectKanbanin the other direction, on measurement: the object definition GATES the query instead of refining it afterwards — one query per mount, carrying the expansion the first time. The relevant number is that a schema read is one small GET served fromMetadataCache(5-min TTL, concurrent readers coalesced onto one request); measured against the realObjectStackAdapterover loopback HTTP, 22 reads of one object produced exactly one metadata request and every read after the first returned in 0.01ms. So the ref was not the only way out of the double fetch.ObjectView's effect has five more dependencies than the kanban's (currentViewType,currentNamedViewConfig,activeView,renderListView,refreshKey), so the gate needs its own read of what a re-run costs there.Refs: #6271 / the kanban gate that measured this · #6235 (a different defect in the same non-grid fetch path — sort lowering, not expansion).
Generated by Claude Code
Generated by Claude Code