Skip to content

data-objectstack: view-overrides:{object} is only invalidated by updateViewConfig — createView / updateView / deleteView leave the batch map stale for the 5-minute TTL #4363

Description

@yinlianghui

Adjacent finding, surfaced while removing the dead views:{object} invalidations for #3778 (sweep #4328). Not fixed there — that PR is a pure dead-code removal, and this is a behavioural gap that predates it. Filed under PD #10.

Measured on origin/main @ 7e4f0e530.

What

ObjectStackAdapter caches exactly two view-shaped reads:

reader cache key line
getView view:{object}:{viewId} packages/data-objectstack/src/index.ts:2969
listViewOverrides view-overrides:{object} packages/data-objectstack/src/index.ts:2931

Four write paths touch view rows. Only one of them invalidates the batch map:

write path invalidates view-overrides:{object}?
updateViewConfig view:{object}:{viewId}, view-overrides:{object} yes
createView (nothing) no
updateView (draft and published halves) view:{object}:{viewName} no
deleteView view:{object}:{viewName} no

MetadataCache's default TTL is 5 minutes (packages/data-objectstack/src/cache/MetadataCache.ts:90), and the adapter is long-lived, so the stale window is up to 5 minutes of real use rather than one navigation.

Why the stale map is not self-correcting

loadViewOverrides (packages/app-shell/src/views/ObjectView.tsx:283) treats a resolved batch answer as authoritative and deliberately does not re-probe per view — that is #3774's fix, and it is correct:

RESOLVES (including to an empty map) → authoritative. […] do not "helpfully" re-probe per view on an empty map, that reinstates the 404 flurry it removes.

So when the cached map is stale, the per-view getView fallback is by design unreachable. listViews is uncached and answers fresh, which means the switcher can show a view whose override body came from a map written up to five minutes earlier — the two reads disagree, and the fresher one is not the one that supplies the override.

The sharpest shape is updateView: it is the rename/patch path (#4139), it invalidates the per-view key it just wrote, and it leaves the batch map holding the pre-edit body. A user who edits a view and returns to the object can be served the old override until the TTL expires.

Not claimed

No browser repro was run — this is a read of the invalidation table against the two cache keys plus the TTL, not a reproduction. What is measured is the asymmetry (one of four write paths invalidates the map) and the fact that the fallback which would mask it is intentionally disabled.

Direction (left to triage)

  1. Have createView / updateView / deleteView invalidate view-overrides:{object} as updateViewConfig already does — smallest change, keeps the batch read authoritative.
  2. Give the four paths one shared "view rows for this object changed" invalidation helper, so the next write path cannot forget a key by omission.

Option 2 is the shape that stops this recurring, since the defect here is precisely that the key list is restated per call site.

Related

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions