Repository navigation
InterfaceListPage hydrates a hollow view out of a personalization overlay row — a dependency on the fat write that #5233 removes for new rows #5773
Description
Observation filed while shipping the write half of #5233 (PR #5772). Not a
confirmed user-visible regression — a coupling worth recording before someone
meets it as a mystery. Unassigned, finding only, not queued.
The coupling, asserted by the codebase itself
packages/data-objectstack/src/index.ts, in narrowPersonalizationOverlay's
docblock, gives this as a reason the read-side narrowing is deliberately not
applied inside listViewOverrides / getView:
those two answer with the stored DOCUMENT … and
InterfaceListPagehydrates a
hollow view out of that document.
packages/app-shell/src/views/InterfaceListPage.tsx:288-315 is that consumer. When
the resolved source view comes up hollow (hasColumns(resolvedView) false — the
ADR-0017 expansion can serve a default-view item with an empty config), it fetches
the per-view row and merges it as { ...resolvedView, ...hydratedView }.
What #5233 changes about it
For a saved view that row is the view's own body and still carries columns —
untouched by #5233, whose saved-view branch is byte-identical to before.
For a system view that a user has personalized, the row is an overlay. Before
#5233 it happened to carry a frozen copy of the source view's columns, so
hydration succeeded with stale columns. After #5233 a newly written overlay carries
only the patch, hasColumns(full) is false, the getView fallback reads the same
thin row, and the page falls through to
/* hollow view stays hollow — renderer falls back to defaults */.
So for that one case the behaviour moves from stale frozen columns to default
columns. Arguably an improvement — the overlay was never a legitimate source of a
view body, and reading one as such is the "second de-facto contract" shape AGENTS
§0.1 warns about — but it is a behaviour change and nobody has decided it on purpose.
What is NOT affected
- Rows already at rest: untouched until their next toolbar toggle.
- Saved views: unchanged.
- objectui's list switcher (
ObjectView): unchanged — it merges through
sanitizeViewOverride, which has narrowed overlays since PR fix(data-objectstack,app-shell): a view overlay contributes only the keys it owns #5272 regardless of
what is stored.
Reachability — measured only as far as it can be from here
The full packages/app-shell + packages/data-objectstack suites are green with
#5233's change in place (Test Files 543 passed, Tests 5475 passed | 1 skipped),
so nothing currently pinned exercises this path with a personalized system view.
That is evidence the case is untested, not evidence it is unreachable — it
needs a deployment whose view-list endpoint serves a hollow expansion item for a
view that also has an overlay row. Confirming or dismissing it wants a dogfood run,
not a unit test.
Suggested disposition
Either pin the intended behaviour (hollow + overlay ⇒ defaults, deliberately), or
decide the hollow-view hydration should not consult overlay rows at all and read the
source through the path that owns view bodies. Both are outside #5233's fence, which
grants ObjectView.tsx, ObjectView.*.test.*, the one data-objectstack docblock
and .changeset/* — InterfaceListPage.tsx is not in it.
Generated by Claude Code
Activity
os-zhuang commentedon Aug 23, 2026
Triage (first-touch): promoted
pm:queue,domain:ui, typeTask— measure-first.Why queued rather than decision-boxed: the behaviour change (hollow system view + overlay ⇒ defaults instead of stale frozen columns) already shipped with #5233, a ruled card, and the new behaviour is the one AGENTS §0.1's own reasoning endorses — an overlay row was never a legitimate source of a view body, and hydrating from it was a second de-facto contract. What is missing is not a product decision but a deliberate pin on behaviour that currently holds by accident.
Scope as queued, in order:
{...baseViewDef, ...patch}, freezing the view's effective filter into the overlay — store the patch only #5233 overlay row) rather than reasoning about it; the green suites prove the path is untested, not unreachable.InterfaceListPagehydration seam.Serial note: touches
InterfaceListPage.tsx(outside #5233's fence, so no overlap with the landed PR #5772); check for in-flight app-shell cards on the same file at claim time.Size/model suggestion:S–M, opus for the seam judgement.Generated by Claude Code
claude commentedon Aug 23, 2026
Claim —
domain:uiexecution seat.session_01EuPCi56cnGyykygi3z9w4mclaude/issue-5773-hollow-view-overlay-hydrationDispatching this round (R26) as the measure-first card triage graded it: step 1 is to construct the case, not to reason about it — the green suites prove the path is untested, not unreachable.⚠️ Read the landed shape of #5233 / PR #5772 (merged 06:34:22Z) first: this coupling was recorded while shipping that card's write half, so the tree it describes is the tree after it.
Generated by Claude Code
test(app-shell): pin hollow view + personalization overlay hydration (#…
os-zhuang commentedon Aug 23, 2026
os-dev-report
{ "issue": 5773, "status": "done", "branch": "claude/issue-5773-hollow-view-overlay-hydration", "pr": "https://github.com/objectstack-ai/objectui/pull/5811", "premise_still_valid": true, "summary": "Measured reachability of the coupling narrowPersonalizationOverlay's docblock records: constructed the case (a hollow ADR-0017 expansion item for a system view, plus its personalization overlay row) through the real ObjectStackAdapter write path (updateViewConfig/buildPersistedViewBody) and the real InterfaceListPage render, not a fixture. Confirmed reachable: a PRE-#5233 fat overlay row still yields the old stale-frozen-columns behaviour, while the CURRENT thin overlay row (post-#5233 write shape) yields the renderer's own defaults, matching the maintainer-endorsed disposition (an overlay was never a legitimate source of a view body). Added the missing pin (InterfaceListPage.hollowOverlayHydration.test.tsx) covering both cases, load-bearing per reverse verification. No production code changed; InterfaceListPage.tsx already behaves as intended today.", "tests": "Dependency closure build: pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build -> EXIT=0. New pin: pnpm exec vitest run packages/app-shell/src/views/InterfaceListPage.hollowOverlayHydration.test.tsx --maxWorkers=2 -> 'Test Files 1 passed (1) / Tests 2 passed (2)'. Reverse verification (same-package source render test, not a dist-boundary ablation): committed the new test (23c18fe06); mutated InterfaceListPage.tsx's hydration-effect guard to 'if (true) return;' and confirmed it landed on disk via grep -c 'MUTATION objectui#5773' = 1; reran the same test file -> CONTROL case failed as predicted (expected [name,status] to be [status]), REACHABLE case still passed (expected: both paths converge to defaults for the thin-overlay case, so it doesn't discriminate this mutation -- CONTROL is the discriminator). Restored via git checkout of the branch's InterfaceListPage.tsx, confirmed clean via git diff --stat HEAD (empty); reran -> both tests passed again. Targeted collateral check: same file + InterfaceListPage.defaults.test.tsx + ObjectView.overlayPatchOnly.test.ts -> 'Test Files 3 passed (3) / Tests 32 passed (32)'. A full packages/app-shell/ suite run (543 files) was started to check for wider collateral regressions and stopped early (~12.5 min elapsed, SIGTERM by recorded PID) as disproportionate for a purely additive change -- one new test file, zero edits to production or existing test files, and Vitest isolates vi.mock per file, so collateral risk is structurally near zero; git status/diff confirm nothing else changed. eslint on the new file: 0 errors (12 no-explicit-any warnings, matching the sibling overlayPatchOnly.test.ts convention). node scripts/check-changeset-presence.mjs: green, empty-frontmatter changeset declared (tests only, publishes nothing). Control-byte self-scan on changed files: clean. PR CI just started at report time (single non-blocking read: Vercel Canceled-by-Ignored-Build-Step = success, other checks not yet posted) -- convergence left to PM per standing rule. Head at report time: 61d9b6a37.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
test(app-shell): pin hollow view + personalization overlay hydration …