You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
List personalization: 「恢复视图默认」 clears the reader's stored setting instead of copying the default into it — today the reader stays on the old value after the view changes #28948
Filed by the record-page epic seat from a review of list personalization under epic #26676. An independent reviewer read the code and tested on examples/app-crm, and the seat re-read the evidence. The maintainer: 「把「恢复默认清除偏好」、「账号偏好字段校验」、「个性化标记与统一重置」立卡,并收窄 #28912 的验收。命名个人视图暂不做。」 (2026-11-02). Code readings below are on maina36409337b. No domain:* label is set: triage routes this card.
Business reason
A reader restores the list's density, hidden columns or sort to the view's default. Later an admin changes that view's default. The reader should follow the view, and today does not: the "reset" stored the old default as the reader's own choice.
Measured
On the lead list, the reviewer changed the density and pressed 「恢复视图默认设置」. The list looked right, and the reader's sys_user_preference row held rowHeight: "compact" instead of nothing.
Because an entry remains, the header ⋯ keeps offering 「重置视图」.
Reading
ui/packages/plugin-list/src/ListView.tsx:5456, resetDisplayToViewDefault: it writes density and hidden fields through the controls' own doors (density.setMode, updateHiddenFields), so the host stores them as a choice.
ListView.tsx:5169, handleResetSort: it notifies onSortChange, so a host persists "a reset exactly as it persists a header click".
ui/packages/app-shell/src/context/ListPreferencesProvider.tsx:205-216: a patch key of undefined or null clears that part, and sort: [] and hiddenFields: [] are real choices. The clear already exists, and these paths do not use it.
ui/packages/app-shell/src/views/objectViewListRenderer.tsx:197-199, 373-376: the persist callbacks.
Target
「恢复视图默认设置」 and 「恢复视图默认排序」 clear the matching parts of the reader's preference. A view left with nothing is removed, as the provider already does.
The host needs a way to tell a reset from a choice. plugin-list cannot import the provider, so this is a prop or a callback value between the two. It is not a metadata key.
A deliberate choice is unchanged: sort: [] ("no sort") and hiddenFields: [] ("show every column") stay stored.
Display settings that are not in the preference (row color, row numbers, inline edit, layout) behave as today.
Acceptance
Change the density, press restore: the view's entry has no rowHeight. Change the view's rowHeight: the reader sees the new value.
The same for hidden fields on a view that stores them, and for sort through the sort popover.
With nothing else stored, the ⋯ 「重置视图」 entry disappears after a restore.
Removing every sort level, or showing every column by hand, still survives a reload.
Tests pin each case at the host seam, not only in ListView.
Claim: PM loop round 16 · 2026-11-02T05:24Z
Session: session_01QsR2jTivKAK8N8dfW5mn9D (card thread, os-dev); dispatched by seat session session_01QsR2jUJ19MstFvFhjgiYTu
Account: zhuangjianguo
Branch: claude/project-thread-gbdojf (platform-assigned to the card thread; it can push only this branch)
Worktree: objectstack-issue-28948
Domain: domain:ui
Seat: domain:ui#1
File surface: ui/packages/plugin-list/src/ListView.tsx (resetDisplayToViewDefault and the sort reset), ui/packages/app-shell/src/views/objectViewListRenderer.tsx, ui/packages/app-shell/src/context/ListPreferencesProvider.tsx, their tests, and a root .changeset (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: yes (widening)
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6569483642
Premise: holds (at origin/mainf7c545ad: ListView.tsxresetDisplayToViewDefault re-applies the view defaults through each control's door, so the host stores them as the reader's own choice instead of clearing the stored preference)
Serial constraints cleared: none known. #28950 (seat 1) follows after this lands; #28949 edits objectViewListUrlState.ts beside ListPreferencesProvider in parallel.
{
"issue": 28948,
"status": "done",
"branch": "claude/project-thread-gbdojf",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29044",
"session": "session_01QsR2jTivKAK8N8dfW5mn9D",
"premise_still_valid": true,
"summary": "ListView gains host prop onRestoreViewDefaults(parts) ('sort' | 'hiddenFields' | 'rowHeight') and viewDefaults gains sort. With the prop wired, the Display control's and the sort popover's 'Reset to view default' name the parts they returned to the view's own and no longer write the view's values through onHiddenFieldsChange / schema.onDensityChange / onSortChange; sort and hidden fields are put back locally at once, density follows schema.rowHeight after the host's clear. The console object page passes viewDefaults.sort (the view's own sort) and wires restoreViewDefaults, which patches each named part to null via listPrefs.patchView (an empty view entry is removed, so the header Reset view goes) and drops sort from the URL. Deliberate sort: [] / hiddenFields: [] still stored; other Display settings unchanged; hosts without the prop unchanged. Behaviour note: the console's sort reset now returns to the view's own sort, not the sort the list opened with. Premise held at origin/main fed3a51b. File surface: ListView.tsx, objectViewListRenderer.tsx, ListPreferencesProvider.tsx (docblock), their tests (new ListView.restoreViewDefaults-28948.test.tsx; ObjectView.userListState-12418.test.tsx), .changeset/list-reset-clears-stored-preference.md (patch, Clause-② yes (widening), Metadata-protocol none) -- no breach.",
"tests": "At eda72c06 under os-verify-lock after turbo build app-shell^... + plugin-list^... + formula/sdui-parser/lint/client (64 tasks, exit 0): ui vitest packages/plugin-list/ + 16 git-grep-selected app-shell/console/plugin-view files, --maxWorkers=2 -> Test Files 196 passed (196), Tests 1907 passed (1907) (declared narrowing for app-shell; CI Test UI runs the rest). New file 6/6; host file 32/32. type-check plugin-list and app-shell exit 0. ESLint on changed tsx exit 0, 0 errors. Ablations via scripts/ablation-replace.mjs (source-resolved, no dist), each restored blob == HEAD, git diff HEAD empty: sort reset back to emitSortChange -> 1 failed/5 passed; density leg dropped -> 2 failed/4 passed; host stores view values instead of null -> 4 failed/28 passed in the host file. First density ablation attempt refused by the tool (replacement count did not rise), rerun with a unique replacement.",
"gates": "dispatch-gates --commands at eda72c06: 35 derived, 35 run, each exit 0 (check:type-check-debt and pnpm --dir ui exec vitest run scripts/ under the lock, the latter 169 passed / 2 skipped); check-sdui-manifest exit 0; PR-body gates re-run on the final body as GITHUB_EVENT_PATH (changeset-no-major, adr-0087-registration, closing-keyword-parity, empty-changeset) exit 0; check-partof-closing-keyword with PR_BODY exit 0; ui check:new-line-citations 0 new. --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. CI at pr_create: 17 in_progress, 3 skipped, 0 failed.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "7 — issue_read x3 (get, get_comments x2), pull_request_read x1 (get_check_runs), ToolSearch loads x3; no write tool",
"api_writes": "5 — git push x4 (branch), fleet-write pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> relay run 41399507825, PR #29044, body read back 8704/8704 identical, no assignees), this os-dev-report comment via post-stamped",
"open_questions": [],
"out_of_scope_findings": []
}
Landed · 2026-11-02T07:23Z · PR #29044 merged through the merge queue as 12aad143 at 2026-11-02T07:17Z (GitHub's clock). ACCEPT 6570766659 at head eda72c06.
probe
before (12aad143~1)
now (origin/main)
onRestoreViewDefaults in plugin-list/src/ListView.tsx
0
11
restoreViewDefaults in app-shell/src/views/objectViewListRenderer.tsx
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: priority:p2 · domain:ui · pm:queue · 2026-11-02T05:01Z
⛔ Not a claim.
resetDisplayToViewDefaultandhandleResetSort(ui/packages/plugin-list/src/ListView.tsx) store the view's defaults as the reader's own choice, so after a restore the reader no longer follows changes to the view. That is a user-visible behaviour defect, so it is p2 indomain:ui. The seam betweenplugin-listand the host is a prop or callback, not a metadata key, and the maintainer's quoted ruling orders the card, so it goes topm:queue. Land it before List personalization: one visible 「已个性化」 marker and one reset that restores the whole list — today two reset entries cover different parts and neither says what changed #28950.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu
Claim: PM loop round 16 · 2026-11-02T05:24Z
Session:
session_01QsR2jTivKAK8N8dfW5mn9D(card thread, os-dev); dispatched by seat sessionsession_01QsR2jUJ19MstFvFhjgiYTuAccount:
zhuangjianguoBranch:
claude/project-thread-gbdojf(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-28948Domain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/plugin-list/src/ListView.tsx(resetDisplayToViewDefaultand the sort reset),ui/packages/app-shell/src/views/objectViewListRenderer.tsx,ui/packages/app-shell/src/context/ListPreferencesProvider.tsx, their tests, and a root.changeset(stop on breach; explain in the report)Container & model: M,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: yes (widening)
Metadata-protocol: none
Responsibility:
n/a — not a defect cardThread-read: 6569483642
Premise: holds (at
origin/mainf7c545ad:ListView.tsxresetDisplayToViewDefaultre-applies the view defaults through each control's door, so the host stores them as the reader's own choice instead of clearing the stored preference)Serial constraints cleared: none known. #28950 (seat 1) follows after this lands; #28949 edits
objectViewListUrlState.tsbesideListPreferencesProviderin parallel.objectstack-fleet commentedon Nov 2, 2026
domain:ui#1 · zhuangjianguo · session_01QsR2jTivKAK8N8dfW5mn9D
os-dev-report
{ "issue": 28948, "status": "done", "branch": "claude/project-thread-gbdojf", "pr": "https://github.com/objectstack-ai/objectstack/pull/29044", "session": "session_01QsR2jTivKAK8N8dfW5mn9D", "premise_still_valid": true, "summary": "ListView gains host prop onRestoreViewDefaults(parts) ('sort' | 'hiddenFields' | 'rowHeight') and viewDefaults gains sort. With the prop wired, the Display control's and the sort popover's 'Reset to view default' name the parts they returned to the view's own and no longer write the view's values through onHiddenFieldsChange / schema.onDensityChange / onSortChange; sort and hidden fields are put back locally at once, density follows schema.rowHeight after the host's clear. The console object page passes viewDefaults.sort (the view's own sort) and wires restoreViewDefaults, which patches each named part to null via listPrefs.patchView (an empty view entry is removed, so the header Reset view goes) and drops sort from the URL. Deliberate sort: [] / hiddenFields: [] still stored; other Display settings unchanged; hosts without the prop unchanged. Behaviour note: the console's sort reset now returns to the view's own sort, not the sort the list opened with. Premise held at origin/main fed3a51b. File surface: ListView.tsx, objectViewListRenderer.tsx, ListPreferencesProvider.tsx (docblock), their tests (new ListView.restoreViewDefaults-28948.test.tsx; ObjectView.userListState-12418.test.tsx), .changeset/list-reset-clears-stored-preference.md (patch, Clause-② yes (widening), Metadata-protocol none) -- no breach.", "tests": "At eda72c06 under os-verify-lock after turbo build app-shell^... + plugin-list^... + formula/sdui-parser/lint/client (64 tasks, exit 0): ui vitest packages/plugin-list/ + 16 git-grep-selected app-shell/console/plugin-view files, --maxWorkers=2 -> Test Files 196 passed (196), Tests 1907 passed (1907) (declared narrowing for app-shell; CI Test UI runs the rest). New file 6/6; host file 32/32. type-check plugin-list and app-shell exit 0. ESLint on changed tsx exit 0, 0 errors. Ablations via scripts/ablation-replace.mjs (source-resolved, no dist), each restored blob == HEAD, git diff HEAD empty: sort reset back to emitSortChange -> 1 failed/5 passed; density leg dropped -> 2 failed/4 passed; host stores view values instead of null -> 4 failed/28 passed in the host file. First density ablation attempt refused by the tool (replacement count did not rise), rerun with a unique replacement.", "gates": "dispatch-gates --commands at eda72c06: 35 derived, 35 run, each exit 0 (check:type-check-debt and pnpm --dir ui exec vitest run scripts/ under the lock, the latter 169 passed / 2 skipped); check-sdui-manifest exit 0; PR-body gates re-run on the final body as GITHUB_EVENT_PATH (changeset-no-major, adr-0087-registration, closing-keyword-parity, empty-changeset) exit 0; check-partof-closing-keyword with PR_BODY exit 0; ui check:new-line-citations 0 new. --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. CI at pr_create: 17 in_progress, 3 skipped, 0 failed.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "7 — issue_read x3 (get, get_comments x2), pull_request_read x1 (get_check_runs), ToolSearch loads x3; no write tool", "api_writes": "5 — git push x4 (branch), fleet-write pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> relay run 41399507825, PR #29044, body read back 8704/8704 identical, no assignees), this os-dev-report comment via post-stamped", "open_questions": [], "out_of_scope_findings": [] }objectstack-fleet commentedon Nov 2, 2026
domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu
Landed · 2026-11-02T07:23Z · PR #29044 merged through the merge queue as
12aad143at 2026-11-02T07:17Z (GitHub's clock). ACCEPT 6570766659 at headeda72c06.12aad143~1)origin/main)onRestoreViewDefaultsinplugin-list/src/ListView.tsxrestoreViewDefaultsinapp-shell/src/views/objectViewListRenderer.tsxListView.restoreViewDefaults-28948.test.tsxexistsFixes #28948closed this card.pm:dispatchedcomes off in the same stroke as this note.