Repository navigation
Description
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff
Blocked-by: #28949
Blocked-by: #28948
Blocked-by: #28950
Blocked-by: #28912
Ruled C (see the ruling comment below). This card records the ruling. The first version gets its own execution card once all four blockers are closed.
Filed by the record-page epic seat on the maintainer's word: 「个人视图 立决策卡,并帮我综合评估」 (2026-11-02). Shortly before, the maintainer said 「命名个人视图暂不做」, so nothing is scheduled while this is open. An independent reviewer wrote the analysis and the seat checked its citations. Readings are on main ab085a0482. Analysis revised on the maintainer's correction, quoted below.
The question
A salesperson wants to keep "the leads I follow up this week" as a list with their own name on it. Today they can adjust a list and the system remembers it, but it keeps one unnamed copy per view, so a new filter overwrites the last one. Keeping a second set means a browser bookmark.
Background
- Each user has one unnamed setting per view, in
sys_user_preference(keyui.list.plus the object name;ui/packages/app-shell/src/context/ListPreferencesProvider.tsx). - Creating a view and 「保存为视图」 are admin-only:
objectViewTitleSwitcher.tsx:449,ObjectDataPage.tsx:579. Saved views are environment metadata, visible to everyone who can read the object (ADR-0131 D6). - A sidebar favorite stores the view, not its current filter (
ui/packages/app-shell/src/layout/listViewFavorites.ts). - Two declarations promise more than exists:
ViewScopeSchemastill listspersonal(packages/spec/src/ui/view.zod.ts:5789), and nothing restricts such a view to one user.sharing.type: 'personal'only changes a read-only toolbar badge (ui/packages/plugin-list/src/ListView.tsx:6364).
content/docs/ui/audience-based-interfaces.mdx:51promises "personal views".
Prior rulings. #7494 (2026-08-12): 「今天的合同就是 org 级;per-user scope 留在 #7611(v18),不提前造。」 #7611 parked per-user overlay scope and closed not planned on 2026-08-24; its per-user half later shipped through sys_user_preference (objectui#12418). It never ruled on named personal views.
Governing text
- ADR-0131 D13: "a per-user 'personal view' scope stays the parked v18 direction … if pulled, it returns as a user-owned D3 object, not as this table." Re-check:
git show origin/main:docs/adr/0131-total-organization-ownership-no-null-organization-id.md | grep -n "user-owned D3 object" - ADR-0017 §2: "
personal— authored at runtime, visible only to itsowner". Re-check:git show origin/main:docs/adr/0017-object-has-many-view.md | grep -n "visible only to its" view.zod.ts,VIEW_ITEM_OWNER_RETIRED: "per-user view scoping is a parked direction". Re-check:git show origin/main:packages/spec/src/ui/view.zod.ts | grep -n "parked direction"
Protocol. A and B change no protocol. C adds a user-owned platform object and a merged read in the console, on its own execution card; its first version adds no view-item key. D changes the protocol and ADR-0131.
Premises to re-check
| Premise | Re-check |
|---|---|
| View creation is admin-only | git show origin/main:ui/packages/app-shell/src/views/ObjectDataPage.tsx | grep -n "saveAsViewButton = isAdmin" |
| The metadata write gate has no user dimension | git show origin/main:packages/rest/src/meta-item-write-routes.ts | grep -n "metaSaveVerdict" |
| Favorites carry no filter state | git show origin/main:ui/packages/app-shell/src/layout/listViewFavorites.ts | grep -n "href:" |
| A query on an unreadable field is refused by the server, so a personal view's filter can't reveal it | git show origin/main:packages/plugins/plugin-security/src/predicate-guard.ts | grep -n "not readable by the caller" |
| The engine resolves relative dates in a filter; whether the list filter panel offers them is still to be measured | git show origin/main:packages/spec/src/data/date-range-presets.ts | grep -n "this_week" |
Options
| Option | What it does | Where the data lives, and who sees it | What the customer notices | Effort |
|---|---|---|---|---|
| A. Don't build | Keep the one unnamed setting, URL bookmarks, and author-written "My …" views | Unchanged | A second set of conditions lives only in a browser bookmark | Zero |
| B. Named favorites with state | Save the view plus its current filter and sort as a named sidebar favorite | The favorites preference row, self only | A named bookmark. It is not in the view switcher, has no columns of its own, and breaks quietly when the view changes | ui lane, 1–2 PRs. No direct precedent; #27943 (+2206/−560, the whole switcher) is the upper bound |
| C. True personal views | A user-owned object per ADR-0131 D13. The switcher merges package, environment and "my" views, and any reader can save as "my view" | User data, row scope self, not exported with packages | Same model as the major CRMs. Works in walled environments, because it is data and not metadata | Two lanes, at least 2 PRs. Nearest precedents: objectui#12471 (+2609/−480), #27943 (+2206/−560) |
| D. Let readers create shared views | Give readers the metadata write, or a new permission | Environment metadata, visible to everyone | One person's list appears for the whole company, and the switcher grows with headcount. Walled environments can't write it (#23330) | Spec, ui, and an ADR-0131 change. No precedent |
业务含义
- A:列表是公司的,个人只能临时调;要固定一套条件,就找管理员加视图。
- B:把一次筛选结果存成带名字的书签挂在侧栏,底层视图一改就可能失效。
- C:每人有自己的视图抽屉,和公司视图并列,别人看不见。Salesforce、Dynamics 365、HubSpot、Airtable 都是这种模型(经验判断,未查官方文档)。
- D:人人都是视图管理员,很快没人知道哪个视图是谁的。
按场景评估(维护者口径)
维护者更正:「我们是创业项目,要评估需求的合理性,而不是现在没有拉动」。所以 issue 零命中只记作「无反馈数据」,不作为推迟理由。以下角色和频率是经验判断,不是本项目实测。
| 角色 | 工作 | 现有能力覆盖 | 覆盖不了 | 判断 |
|---|---|---|---|---|
| 销售 | 每天按复合条件过线索,同时维持 2–4 份工作集 | "My …" 视图覆盖「我负责」,无名设置留最近一份 | 同一视图上多份工作集互相覆盖;条件因人因时变化,作者写不全 | 真实、中频、代价中等 |
| 主管 | 团队切片,随月、随人变化 | 预写的团队视图覆盖骨架 | 组合写不全 | 需求更强,但要的是团队共享,C 第一版只是前置层 |
| 客服 / 运营 | 按队列工作 | 组织定义的队列视图 | 基本没有 | 基本不需要 |
| 财务 / 后台 | 周期清单 | 预写视图、报表、导出 | 临时核对 | 不需要 |
AI 生成应用的影响。 岗位级的静态条件应该由 AI 写进包,这压掉了一半需求。因人因时的条件作者无法预知,把 9 个视图写成 20 个只会让切换器更挤。另外(推断):用户让助手「给我一个本周跟进列表」时,今天只能落到全组织可见的定制包,个人层是这种操作的合理落点。
最强反方: 无名设置加多个基础视图,已经相当于多份工作集,小团队今天基本够用。它不成立的地方是:管理员改基础视图时个人那份会乱,同一视图也放不下两份。这条决定了时序,C 排在卫生卡之后。
四轴分析
① 项目长远合理性。 项目已三次写下终态:ADR-0017 的三层作用域、#7611 的 "architecturally right end-state"、ADR-0131 D13 的用户所有对象。C 是这条线的落点,并给个人列表一个不污染组织视图的归宿。B 形成第二套视图定义方言,以后做 C 要迁移。D 和 ADR-0131、ADR-0146 的来源模型相反。A 不增生,但终态空缺。读数:C > A > B > D。
② 实际业务拉动(按场景)。 见上表。销售每天发生、单次代价小;主管更强但要共享;其他角色不需要。无反馈数据,如实记录,不作权重。
③ 防 AI 犯错。 今天 AI 写 sharing.type: 'personal' 或 scope: 'personal',保存成功,所有人照样看得见,徽标却写「个人」,这是静默的可见性谎言。C 用 spec 的 ListView 形状校验,坏值保存时响亮拒绝;筛选不可读字段由服务端拒绝。B 的偏好 JSON 结构自由,坏了只表现为列表空着或被拒。D 会让个人口味随定制包静默部署到下一个环境。
④ 创业阶段不扩散。 C 的场景合理,义务是一张用户数据表,不进包,也不是作者可写的协议键;第一版压到最小。D 代价最大。四个选项都不需要新门禁,荐「不加」。
推荐:C,第一版排在个性化卫生卡之后
时序: #28949 → #28948 → #28950 → #28912 → C 第一版。第一版把当前个性化状态快照成视图,这四张卡没落地时快照源是脏的:可能含已删字段,可能把旧默认当成个人选择。#28915 与 C 没有耦合,不参与排序。
第一版包含: 另存为我的视图、切换器里的「我的视图」分组、改名、删除、设为我的默认(复用已有的置顶)。
第一版不包含: 分享和团队视图、管理员代管和离职转移、字段选择器、进包和导入导出。个人视图之上也不再叠无名偏好层。
工作量: 两个车道,至少 2 个 PR。先例:objectui#12471(+2609/−480,用户所有列表状态)、#27943(+2206/−560,切换器,C 只加一个分组)、objectui#11582(+674/−18,保存被拒的提示)。平台对象照 sys_user_preference 的模板,没有独立 PR 先例。
终态: 两年后切换器里有三层:包作者的视图、环境管理员发布的视图、用户自己命名的「我的视图」。「我的视图」是一行属于该用户的数据,行级仅本人,不随包导出,配置就是 spec 的 ListView。
自检:只看①选 C;②③④ 是否翻转:否。②把时序从「不排期」改成「卫生卡之后」,④把第一版压到最小,都不翻字母;不新增门禁。
其余选项不取的理由: A 的代价是销售每天重设、主管找管理员,可以承受,但留下终态空缺,是回退项。B 只解决命名,不解决覆盖和漂移,还多一套方言。D 对主管最对症,但墙内不成立,且要改 ADR-0131。
置信缺口:
- 角色和频率是经验判断,没有使用数据;第一版落地后以「多少用户建了至少一个」作为要不要做分享的依据。
- 助手代建列表的落点是按 ADR-0146 推断的,未看控制台助手的实际写路径。
- 列表筛选面板能否选「本周」这类相对日期未实测。引擎解析日期宏(
{week_start}),spec 有this_week预设,但如果面板不提供,「我的本周跟进」存下的就是会过期的绝对日期。
裁后执行
裁 C:
- 席位在 ADR-0131 D13 旁记日期注和本卡编号:命名个人视图是用户所有对象,不走 view item,不复用
scope: 'personal'。 - 同笔子裁决,不另立决策卡:
- 退役
ViewScopeSchema.personal和sharing.type: 'personal',开一张收口卡。 audience-based-interfaces.mdx:51先改成 per-user list preferences,C 落地后再改回。- 个人视图的 id 不用视图的 object.key 语法,避免撞包视图名。
- 个人视图之上不叠无名偏好层。
- 退役
- 开工前先核实相对日期在列表筛选里能否选择和保存。
- 四张卫生卡合入后,席位重跑上面的 re-check,再立第一版执行卡,卡上写明「不包含」清单。
- 分享留到第一版落地之后,以使用情况为依据,并先裁非管理员能否产出环境元数据。
裁 A: 同样执行第 2 步的退役和文档修改,并把 ADR-0131 D13 和 view.zod.ts 里的 "parked direction" 改成 not planned。
裁 B 或 D: 维护者在卡上另裁。B 要同时定筛选状态的存法和底层视图被删时的表现。D 要先改 ADR-0131。
os-decision-facets
- ① 项目长远合理性:C 落实 ADR-0017 和 ADR-0131 D13 的终态,用一个用户数据对象和一套 spec 形状,并给个人列表一个不污染组织视图的归宿,缩小特例;B 造第二套方言,D 下放环境元数据权属且墙内不成立;A 让终态空缺。
- ② 实际业务拉动(按场景):销售每天维持多份工作集,无名设置只留一份,绕行单次代价小但每日发生;主管更强但要共享,C 第一版只是前置层;客服、财务、后台不需要;无反馈数据,不作权重。
- ③ 防 AI 犯错:今天写
personal保存成功而所有人可见,是静默谎言;C 保存时响亮拒绝坏值,不可读字段由服务端拒绝;B 静默失效;D 让个人口味随包静默部署。 - ④ 创业阶段不扩散:C 场景合理,第一版只做另存、切换、改名、删除、设默认,不做分享和代管;两处悬空声明现在退役;四个选项都不加新门禁。
Prior rulings read: personal view / 个人视图 / per-user scope / sys_view_definition / view.owner → 19 + 282 + 7 + 6 + 5 hits (first 15 read, the rest by title); ADR-0017 §2, ADR-0131 D6 and D13, ADR-0146 D2, ADR-0049; thread: #7494, #7611, #20085, #20230, objectui#12418, objectui#12474, #27594.
Activity
objectstack-fleet commentedon Nov 2, 2026
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff
Ruling: C · 2026-11-02T06:21Z
The seat asked: 「选 C 还是 A?我推荐 C。」 C was stated as: 做个人视图,第一版排在四张卫生卡之后,范围按卡上写的. The maintainer: 「同意」.
Ruled, with the sub-questions in the same stroke:
scope: 'personal'.Executed now:
personaldeclarations and corrects the docs line.needs-user-decision→pm:blocked.When all four blockers are closed, the seat re-runs the re-checks above, measures whether the list filter panel can select a relative date such as 本周, and files the first-version execution card with the 「不包含」 list. An early unlock from any single blocker does not start it.
Sharing stays out until the first version has landed. It then needs usage evidence, and a ruling on whether non-admins may produce environment metadata.
objectstack-fleet commentedon Nov 2, 2026
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff
Premise measured · 2026-11-02T06:43Z. The maintainer asked the seat to finish what was unverified: 「没验证的 继续验证」. Preview:
bdb19ca6d9,examples/app-crm, signed in as the dev admin.Relative dates: the engine works, and a reader has no way to choose one.
close_date < {today}/>= {today}close_date < {week_end}/< {current_month_end}{not_a_macro}uf__filtervalue{current_month_end}(operatorbefore)2026-11-02, an absolute date, and it comes back from the stored preference on the next open{today}into the date inputSo the HotCRM comment at
src/sales/views/event.view.ts:17-23("date macros ship to the server as literal strings") doesn't hold on this build, while the one attask.view.ts:298does.What this means here. A personal view saved today could only hold absolute dates, so 「我的本周跟进」 would go stale. The same is true of today's unnamed setting. Spec already has the presets (
DATE_RANGE_PRESETS, includingthis_week) and the dashboard filter bar offers them. The list filter panel doesn't. The seat will bring this to the maintainer before the first-version card is filed.Blocked-bywith four targets.h19BlockOutlivedBlockerinscripts/pm/check-half-states.mjsreports a row when any body target has closed. An open target "withholds a full discharge".references/state-machine.mdsays a closed upstream means re-deriving the block, never a reflex release. The "all targets closed" rule there applies only to the scheduled full-run card refresh. So one closure can raise a patrol row, and the remaining open targets keep this card blocked. The ruling comment's line, that an early unlock doesn't start the work, stands.The seat's test filter was removed with 「重置视图」.
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage:
domain:server· p2 · 2026-11-02T07:36Z⛔ Not a claim.
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff
Relative dates ruled · 2026-11-02T08:00Z. The maintainer: 「三点都按 A:相对日期立独立卡,在 #28971 第一版立卡前合入,包含早于/晚于的相对点;仪表盘拼法另立低优先级卡;两只钟另立 finding。」
Blocked-by, so the seat checks List filter panel: offer relative dates on date rows — 本周 and 今天 today store a fixed date, so a saved filter silently goes wrong #29115 at filing time, along with the four blockers above.This answers the open point in the previous comment, that the seat would bring the relative-date gap to the maintainer.
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: unblocked ·
pm:queue(p2 kept) · 2026-11-02T13:06Z⛔ Not a claim.
Blocked-by(List personalization: a stored sort or filter on a deleted or unreadable field is dropped when the list opens, as the URL route already does #28949, 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, 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, List views: readers can hide and show columns by default — flip the userActions.hideFields default, so a generated app has the control without having to declare it #28912) is closed.pm:blocked→pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-steve · session_01ADHkmQjPiXgNoSaEpqeGvY
Seat correction · 2026-11-02T15:00Z
At 2026-11-02T14:41Z this seat moved this card from
pm:queuetoneeds-user-decision. That was the seat's mistake: it read the[Decision]title and did not read the comments. The card was already ruled C (6570568131), the relative-date sub-question was ruled A (6572083158), and triage unblocked it topm:queue(6577893396) once #28949, #28948, #28950 and #28912 had closed. #29115 has closed too. No maintainer ruling is owed.needs-user-decision→pm:queue. Seat 1 claims the card's execution step in the next comment.objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-steve · session_01ADHkmQjPiXgNoSaEpqeGvY
Execution step 4 · 2026-11-02T15:04Z
The four hygiene cards and #29115 are all closed, and every re-check in the body still holds on
origin/maina6441636. The first-version execution card is filed as #29443, with the 「不包含」 list. It runs in two steps: the server step, a user-owned platform object, comes first, and the ui-lane step after it. Seat 1 claims the server step on #29443. This card's work continues there. #29037 and #29038 remain the ruling's side cards.objectstack-fleet commentedon Nov 3, 2026
domain:server#1 · os-warren · session_01JQwxbXsK9j25sd7eVwW96G
Closed: ruling C executed in both halves · 2026-11-03T03:39Z
⛔ Not a claim. This decision card came back into the
domain:serverqueue, but no work is left on it. The coordinator assigned it to seat 1 by mod-5, and the seat read the thread before claiming.sys_personal_view)4008e6290f; #29443 closed completed0b2b309cb4; #29635 closed completedThe execution card filed under step 4 (6580498444) has carried this card's work since then, and both of its halves have landed. Closed as completed. If the maintainer wants a step from the 「不包含」 list (sharing, team views, admin management, a field picker, packaging), it is a new card, not a reopening of this one.