Repository navigation
Description
Ruled: 6289508074 · letter E′ · 2026-10-20T11:09Z
Problem
On the organization record page (Setup → sys_organization → Members tab), an org with 1,002 members shows a 25-row related list with no way to search. A maintainer asked a plain question — "is this person a member of this org?" — and the only answer today is paging through 40 pages, or going the other way round (open the user's record → Organizations tab).
This is not specific to members: every record:related_list (contacts on an account, lines on an order, team members, …) has the same gap.
Why it can't be fixed by "just turning the magnifier on"
Verified against main (objectstack 0904d85, objectui 2d8a8b7):
- objectui — the existing box is client-side and matches raw ids.
RelatedList.tsxhas an opt-infilterableinput, butrecord-related-list.tsxnever passes it, so no page can show it. Even if shown, it sweepsrow[key]— foruser_idthat isusr_…, not the name the cell draws — and while a term is typed it drops out of windowed mode and downloads the whole child collection. - objectstack —
$searchnever traverses a lookup.search-filter.tsexpands over the object's own textual/enum fields.sys_memberis a junction (two lookups, formula title), so its resolved search set is empty and, since metadata-protocol / objectql: asearchterm on an object with no searchable field is dropped silently, so the read answers every row (an empty auto-default search set is not refused) #24284, a non-blanksearchon it is refused400 INVALID_FIELD. A related list that forwarded the term to the server would get a 400.
Proposal
Part 1 — objectstack: lookup-aware $search (the core)
- A single-valued lookup in an object's search set matches when its referenced record matches the term on the referenced object's own resolved search fields (e.g.
sys_member.user_id→sys_username / email; pinyin via the__searchcompanion where enabled). - Expansion: run the term against the referenced object under the caller's execution context (RLS + FLS apply — otherwise search becomes an existence oracle for records the caller cannot read), then OR
{ <lookup>: { $in: … } }into the term's clause. One hop only, never recursive. - Scale: prefer a semi-join (subquery) when both objects share a datasource; cross-datasource falls back to an id list capped at N (e.g. 500) and the response says the result may be incomplete — never a silent short answer.
- Resolution: explicit
searchableFieldsmay name a lookup; the auto-default adds single-valued lookups whose target has a non-empty search set.sys_memberthen searches with no metadata change and the metadata-protocol / objectql: asearchterm on an object with no searchable field is dropped silently, so the read answers every row (an empty auto-default search set is not refused) #24284 refusal no longer fires for it. - Record the rule as an addendum to ADR-0061.
- Free side-benefit: main list views ("search accounts by owner name"), lookup pickers, REST and MCP/AI reads get the same behaviour.
Part 2 — spec: record:related_list.searchable
- New
searchable?: booleanonRecordRelatedListProps, defaulttrue;falsehides the box. Enforced in the renderer per ADR-0049 (pin test), not declared-only.
Part 3 — objectui: the search box on the related list
Where the user types — in the related-list card header, the same magnifier control the main list toolbar uses:
default
┌──────────────────────────────────────────────────────────────┐
│ 👥 Members 1002 🔍 [Invite user] [Add member] │
after clicking 🔍 — expands in place inside the header
┌──────────────────────────────────────────────────────────────┐
│ 👥 Members 1 / 1002 [🔍 Zhang Yang ×] [Invite user] [Add member] │
├──────────────────────────────────────────────────────────────┤
│ Zhang Yang Member 2026/10/15 4:30 PM ··· │
│ View all results for "Zhang Yang" → │
no match
│ No members match "Zhang San" [Invite user] │
| Aspect | Behaviour |
|---|---|
| Placeholder | derived from the searchable columns, e.g. "Search user, role…" |
| Trigger | 300 ms debounce; Enter searches immediately |
| Count badge | "matched / total" while a term is active |
| Paging | stays windowed — term sent as $search, server pages; never a full download |
| Clear | × or Esc clears and collapses |
| Tabs | each related list keeps its own term |
| View all | link carries the term (?search=…); the list page already reads an initial term |
| Mobile | expands to a full-width row under the header |
| Hidden when | the object resolves no search field (reuse ListView's "searchless object" handling on INVALID_FIELD) or searchable: false |
- Retire the client-side
filterableprop (inert today, and wrong if switched on) under enforce-or-remove, after confirming it has no consumers. - i18n for placeholder / no-match / incomplete-result strings (en, zh, ja, es).
Acceptance
- Org page → Members → 🔍 → type a member's name: only that member is listed, badge shows
1 / 1002, the request is a windowed$search(no full-collection fetch). - A non-member's name: "No members match …" with the card's existing Invite action.
- With pinyin search enabled,
zyfinds 张杨. - A user the caller cannot read is not found by name (RLS/FLS honoured in the lookup hop).
- Invitations tab searches by email, Teams tab by name.
- "View all" opens the full list with the same term applied.
- A business object's related list (e.g. Account → Contacts) is searchable with no metadata change.
Delivery
- objectstack PR — lookup-aware
$search+ ADR-0061 addendum + tests (permissions, cap, pinyin) + specsearchable. - objectui PR — header search box,
filterableretirement, renderer wiring, i18n, browser-verified on the org Members tab.
Workaround until then: open the user's record → Organizations tab.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 20, 2026
[Decision] 关联列表加服务端搜索框、
$search按查找字段所指记录的名字匹配:做不做,做多大?Director analysis, batch #377 item 3 — director seat, summon #46,
session_013414Vtz3Z8PrXFetUziHoh, 2026-10-20T10:30Z. Triage (triage seat post #6015) routed this card to the box as a feature proposal with no analysis on it ("appetite, yes or no; lean yes, after 18.0"). This seat therefore writes the analysis. Read on objectstackorigin/main41646a5788f5and objectuiorigin/main58798eca8e02, both fetched in this act. Thread: no comments.一句话问题: 一个有 1,002 名成员的组织,在组织详情页的「成员」列表里没法搜人;想知道「某人是不是这个组织的成员」,只能翻 40 页。所有关联列表(客户下的联系人、订单行……)都一样。
背景(本席实测)
packages/spec/src/data/search-fields.ts:查找字段(lookup/master_detail)不进自动搜索集(SEARCH_AUTO_EXCLUDED_TYPES)。显式声明进searchableFields的话,匹配的是存储的外键 id,不是名字。sys_member的user_id、organization_id都是查找字段,标题是公式字段(无存储列,sys-member.object.ts:299)。所以按名字搜成员,今天在服务端做不到。卡上说它的搜索集为空、会 400(metadata-protocol / objectql: asearchterm on an object with no searchable field is dropped silently, so the read answers every row (an empty auto-default search set is not refused) #24284);本席读到role是 select,可能仍在自动集里。这点未实测,不影响结论:名字搜不到。packages/plugin-detail/src/RelatedList.tsx:239/532/660/2280:有个默认关闭的filterable,在客户端按原始值过滤(查找列上是usr_…这样的 id,不是名字),输入时还会退出分页、下载整个子集合。卡上说没有页面传它,本席没另测。Governing text
docs/adr/0061-record-search-architecture.md:50):「Forlookup/referencefields, searching the related display name needs a join → Tier 2 (or a denormalized display column).」决定(:13)是 Tier 1 先上、Tier 2 延后。本卡就是 ADR-0061 自己点名延后的那一项,不是新方向。record:related_list.searchable键)是唯一的协议增量,见下。前提(复核命令)
git grep -n "'lookup', 'master_detail'" origin/main -- packages/spec/src/data/search-fields.ts(→SEARCH_AUTO_EXCLUDED_TYPES)。git grep -n "needs a join" origin/main -- docs/adr/0061-record-search-architecture.md。filterable是本地过滤:objectuigit grep -n "filterActive = filterable" origin/main -- packages/plugin-detail/src/RelatedList.tsx。选项
searchable键;objectui 加搜索框searchable键,搜索框在子对象有搜索集时就显示;退役filterable业务含义直译: A/B = 通讯录里输入「张杨」就能找到他所在的那一行;C = 在每张表上再抄一份名字,名字改了还要挨个去改;D = 继续一页一页翻。
四轴(业务立场)
searchable: false没有任何人提过要关掉搜索框 —— 零拉动。跨数据源的查找搜索也没有具名需求。filterable正是客户端猜错字段的样本)。跨数据源在入口响亮拒绝,优于静默封顶再附一个客户端可能忽略的「不完整」标记。权限:查找这一跳必须走目标对象自己的读取(行级与字段级权限都生效),否则搜索就成了「这个名字存不存在」的探测器 —— 出错时是静默泄露,所以这是硬性执行参数。推荐:B(18.0 之后,p3)
$search对查找字段按被指记录的名字匹配,这是主流平台的常态(Dynamics 365 的 Quick Find 可以加查找列、按被指记录的主名称匹配;ServiceNow 列表搜索在引用字段上匹配显示值);服务端一条规则,所有界面共享;关联列表的搜索框只是这条规则的又一个入口。searchable键和「可能不完整」响应字段,都是永久契约。sys_member搜索集今天的确切内容未测。os-decision-facets
searchable: false与跨数据源查找零拉动。searchable键、不加「不完整」响应字段;退役坏掉的filterable。Prior rulings read: lookup,search,related_list,searchablefields → 24 hits; ADR-0061 D2/D3/D7 and :50 (lookup display name → Tier 2, deferred); thread: none; repo: objectstack-ai/objectstack
裁后执行
pm:queue,domain:enginep3,不进 18.0。服务端 PR 先行:单值查找字段一跳、只限同数据源、按调用者上下文经目标对象自己的查询执行(行级与字段级权限都编进子查询;调用者读不到的字段不参与匹配);自动集加入目标有搜索集的单值查找;跨数据源的查找不自动加入,显式声明在入口按名拒绝;四条钉子(按名字命中、读不到的用户搜不到、拼音命中、跨数据源声明被拒)并消融。ADR-0061 加一条带日期的注记,单独开 PR(Tier H,等您批)。随后立 objectui 执行卡(domain:ui,Blocked-by:本卡):卡片头部搜索框、窗口分页、退役filterable、四语种文案;再走 console pin bump。searchable键,按 ADR-0049 强制)与跨数据源封顶 + 响应字段。Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Director clarification, batch #377 item 3 — director seat, summon #46,
session_013414Vtz3Z8PrXFetUziHoh, 2026-10-20T10:57Z. The maintainer asked in this session's chat: 「24815 没看懂,是关联字表中输入文字搜索当前子表吗?不是单表查询吗?为什么不支持」. The answer as given, for the record; the letter is still owed.是的,搜的就是当前子表;但「按名字搜成员」不是单表查询。 成员子表的每一行只存一个指向用户的编号,不存名字;名字在另一张表(用户表)里。页面上看到「张杨」,是显示时顺着编号去用户表取来的。
user_id属于这些人、且属于本组织的行。这是两张表的查询。$search只搜本表自己存的文本列(ADR-0061 第一层);查找字段按所指记录的名字匹配,ADR-0061 :50 写明「needs a join」,列为第二层并延后。所以不支持。关联列表分两种,结论不同:
对选项的影响: 「只加搜索框」能解决第一种,解决不了本卡的起因;推荐 B 不变(搜索框 + 按所指记录的名字匹配,只限同数据源,不加新 spec 键)。
Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Director re-analysis, batch #377 item 3 — director seat, summon #46,
session_013414Vtz3Z8PrXFetUziHoh, 2026-10-20T11:03Z. The maintainer proposed in this session's chat: 「成员表 如果配置一个筛选字段,可以弹出搜索用户名不也是可以吗」. This seat measured it; the letter is still owed.可以,而且两步都是现成的单表能力。 读数(objectstack
origin/main、objectuiorigin/main58798eca8e02,本次取):UserFiltersSchema(packages/spec/src/ui/view.zod.ts:1755,fields[].field)。objectuipackages/plugin-list/src/UserFilters.tsx:141把lookup/master_detail/user字段渲染成LookupValuePicker,即可按名字搜目标表的选择器。选择器搜用户表是单表$search;选中后按user_id等值筛成员,也是单表。服务端零改动,权限照常(选择器按调用者权限搜用户)。packages/app-shell/src/views/ObjectView.tsx:2738-2745(?filter[<field>]=<value>),目标列表页支持用户筛选参数(uf_*)。sys_member今天只声明了一个列表视图mine(packages/platform-objects/src/identity/sys-member.object.ts:272),没有用户筛选。record:related_list)本身没有用户筛选键。新增两个选项
sys_member的列表视图配置user_id(可加role)用户筛选domain:engine1 个小 PR(platform-objects 元数据);先例:列表视图userFilters现成userFilters形状,在卡片头部就地筛选record:related_list复用现有 schema)+ objectui 1 PR + 元数据 + pin bump;无先例推荐改为 E′。 只看①:Salesforce 的关联列表也不就地筛选,「View All」进入完整列表视图再用筛选与搜索;E′ 正是这个建模,且只用已声明的能力,不扩契约。B(按查找名字的自由文本搜索)仍是 ADR-0061 延后的第二层,留待有自由文本拉动时再议,不因本卡实现。②③④ 是否翻转:否(② 「某人是不是本组织成员」由 E′ 精确回答;③ 选择器只能选已有记录,等值匹配,不新增联表读取路径;④ 零新契约)。置信缺口:「查看全部」落到哪个列表视图、该视图上配置的用户筛选是否出现,未在浏览器实测。
Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Ruling: batch #377 item 3 · letter E′ · maintainer 「OK」 2026-10-20T11:09Z
Director seat, summon #46,
session_013414Vtz3Z8PrXFetUziHoh. Presented in this session's chat as batch #377 item 3: the director analysis 6288891225 recommended B. The maintainer asked 「24815 没看懂…为什么不支持」 (answer 6289320277), then proposed 「成员表 如果配置一个筛选字段,可以弹出搜索用户名不也是可以吗」. This seat measured that proposal as letter E′ and recommended it (re-analysis 6289408661). The maintainer's 「OK」 accepts E′. Thread read through 6289408661 at this write.Governing text:ADR-0061 (docs/adr/0061-record-search-architecture.md:50: matching a lookup by the related record's display name "needs a join → Tier 2", deferred). This ruling keeps that deferral. The capability used is the declared list-viewuserFilters(packages/spec/src/ui/view.zod.ts,UserFiltersSchema).What the ruling binds
sys_member's list view (packages/platform-objects/src/identity/sys-member.object.ts,listViews) declares a dropdown user filter onuser_id, plusrole. objectui renders a lookup filter field asLookupValuePicker(packages/plugin-list/src/UserFilters.tsx:141, objectui58798eca8e02), which searchessys_userby name under the caller's permissions. The member list then filters by equality on the stored id. No server, spec or objectui change.?filter[organization_id]=…(objectuiObjectView.tsx:2738-2745). Whichsys_memberlist view it lands on is unverified. The dev first measures that landing view, then declares the user filter on it. If no declared view is reachable that way, the dev declares one (anallview) rather than editingmine. Then the dev verifies in a browser: org record → Members → View all → User filter → type a member's name → one row; a non-member's name → empty.user_iduser filter, and the browser reading above in the PR. If the landing view cannot be made to show the filter without a renderer or spec change, that premise is falsified: report a fork and do not widen. ⛔ Do not fall back to B or E silently.$search(B stays ADR-0061's deferred Tier 2). Nosearchablekey. No in-place related-list filter (E). The inert client-sidefilterableprop on objectui'sRelatedListis not touched here.Workload of the letter:
domain:engine· 1 PR (S, platform-objects metadata) · no measured precedent PR; the list-viewuserFilterscapability itself is existing.Execution. This card:
needs-user-decision→pm:queue, keepingdomain:engine,priority:p3andarea:records. The title is rewritten to the ruled scope in the same act. Not an 18.0 gate.Generated by Claude Code
[-]feat(search,ui): related lists get a server-side search box, and `$search` matches a lookup by its referenced record's name — an org's 1000+ Members tab cannot answer "is this person a member?"[/-][+]sys_member list view: a User filter (the searchable user picker), so an organization's members can be found by name from the Members tab's View all[/+]objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 22 (p3 only, by the maintainer's order 「你后续只处理 p3」) · 2026-10-21T05:46Z · p3,
domain:engine(triage's grade); ruled letter E′ at 6289508074 (maintainer 「OK」 2026-10-20T11:09Z, on the director's re-analysis 6289408661). An organization with 1,002 members cannot find one of them by name from its Members tab. The ruling answers it with metadata only:sys_member's list view declares a user filter onuser_id(androle), so "View all" → User filter → a typed name narrows the list to that member.Session:
session_01JtSQQ3EWsbNPzyYMug1tXy(the dispatching seat; the dev runs as its own cloud session, named in the dispatch comment)Account:
os-project-manager(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24815-member-user-filterWorktree:
objectstack-issue-24815Domain:
domain:engineSeat:
domain:engine#1(seat post #6367)File surface:
sys_memberlist view the organization record's Members tab "View all" lands on. It carries?filter[organization_id]=…(objectuiObjectView.tsx, read only).sys_memberdeclares onlyminetoday, andmineis filtered to the current user;userFiltersis declared and rendered: the spec'sUserFiltersSchema(packages/spec/src/ui/view.zod.ts), objectui'sUserFilters.tsx(LookupValuePickerfor a lookup field, read only), and the showcase precedents (examples/app-showcase/src/ui/views/project.view.ts,task.view.ts);packages/platform-objects/src/identity/sys-member.object.ts,listViewsonly:user_id, plusrole;allview) rather than editingmine, as the ruling directs.user_iduser filter. Browser reading in the PR, per the ruling: org record → Members → View all → User filter → type a member's name → one row; a non-member's name → empty.patchfor@objectstack/platform-objects.⛔ Not in scope (the ruling's item 4):
$search: option B stays ADR-0061's deferred Tier 2;searchablespec key;filterableprop onRelatedList;Container & model:
M,mode:cloud(one metadata declaration, then a dev boot and a browser reading),model: TIER_DEFAULT(this run'sdispatch-gates.mjs --tier: "no path-derived mandate")Clause-②: no (platform metadata only: a list-view user filter, and a list view where none is reachable; no spec key, accept set, response, outcome or export moves)
Responsibility: an administrator asked "is this person a member of this organization?" must page through 40 pages |
sys_memberdeclares no list view that "View all" can filter by user | every administrator of an organization with more members than a page showsThread-read: 6289508074
Serial constraints cleared: the 11 open PRs' file lists and the
pm:dispatchedclaims were read at this claim, onorigin/main72518d20f5. No open PR touchessys-member.object.tsorpackages/platform-objects/src/identity/. No held claim names that file.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Dispatch ·
domain:engineseat 1 ·session_01JtSQQ3EWsbNPzyYMug1tXy· 2026-10-21T05:48Z:mode:cloud. The dev session issession_01FyP8DzyLetcGkWW1Lj2ji8. It builds at the default tier on branchclaude/issue-24815-member-user-filter, under claim 6309042170 and the ruling 6289508074 (letter E′).sys_memberlist view the organization record's Members tab "View all" opens;userFiltersrenders for a lookup field;allview if none is reachable (nevermine), declares a user filter onuser_idandrole;patchchangeset for@objectstack/platform-objects;needs_decisionand builds nothing wider.searchablekey, an in-place related-list filter (E), objectui changes.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{
"issue": 24815,
"status": "needs_decision",
"branch": "claude/issue-24815-member-user-filter",
"pr": null,
"session": "session_01FyP8DzyLetcGkWW1Lj2ji8",
"premise_still_valid": false,
"summary": "Measured first, as ruling 6289508074 item 2 orders, and the measurement trips item 3's fork. Metadata alone cannot put a User filter where 'View all' lands, so per the ruling there is no PR, nothing was widened, and nothing fell back to B or E. LANDING VIEW (dev boot, objectstack 72518d2 + console at the .objectui-sha pin cf153eb, showcase
pnpm dev -- --fresh -p 38415, admin): org record /_console/apps/setup/sys_organization/record/org_mvhqbbd8hr4cx573 -> Members -> View all lands on /_console/apps/setup/sys_member/data?filter[organization_id]=org_mvhqbbd8hr4cx573. That is the ADR-0055 bare data surface (ObjectDataPage), captioned 'URL-defined data slice - not bound to any saved view'. It is no list view at all: since objectui#12741, RelatedRecordActionsBridge builds View all with recordListPath(), deliberately unanchored so that a default view's own filter cannot over-narrow the list. sys_member's only (hence default) view ismine, which is exactly that case. The director's re-analysis cited ObjectView.tsx's filter[...] reader, but that is the /view route; View all does not go there. The same code is on objectui main 0093b2c. WHAT THE LANDING RENDERS: ObjectDataPage auto-derives its filter bar from the object's fields of type select/multiselect/radio/enum/boolean only (USER_FILTER_TYPES, capped at 4) and reads no declared userFilters. The bar shows 'Role' and no 'User'. PROBE (throwaway; reverted, blob equal to HEAD c3487c97): I declared anallview with userFilters {element:'dropdown', fields:[user_id, role]}, rebuilt, and confirmed the server returned listViews [all, mine]. The View all landing was unchanged: still /data, still 'Role' only. Opened by hand, /console/apps/setup/sys_member/view/all?filter[organization_id]=... renders 'User | Role'. Typing 'Zhang' in the picker offered 'Zhang Yang'; selecting it gave URL ...&uf_user_id=HBxz..., 1 record. Typing 'Olivia' offered 'Olivia Outsider' (a non-member); selecting it gave 'No matching records'. The E-prime mechanism works, but only on a route that View all never opens, and Setup's nav has no Members entry that reaches /view/all. Declaring the view anyway would declare a capability that no user path reaches (PD#10). Making View all reach it needs an objectui change, which the ruling and the claim exclude. Hence needs_decision.","tests": "No code change, so no unit tests. Real runs: (1)
pnpm exec turbo run build --concurrency=2under os-verify-lock: VERDICT command-exit 0, 77/77 tasks; (2)bash scripts/build-console.shat pin cf153eb: the first try raced my concurrent build (@objectstack/lint DTS TS7016 on a half-built formula dist); the re-run was green ('dist ready ... from objectui@cf153eb2e535'); (3) dev boot,check:console-shagreen; (4) Playwright walks, quoted in summary; screenshots kept in the session scratchpad. Probe edit: committed nothing; restored withgit checkout HEAD -- sys-member.object.ts;git hash-object=git rev-parse HEAD:path= c3487c977c29d76686580f38008b119fce5109bd (BLOB-EQUAL);git diff HEADempty. The worktree was removed afterwards. No pin and no ablation: there is no declaration to pin.","gates": "NOT MEASURED, because there is no diff.
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackexit 2: 'this branch changes nothing against origin/main (merge base 72518d2) - nothing to derive'. No --ran reconciliation, no platform-objects typecheck or test, no test:repo, no merge re-run: nothing changed to run them on. No PR, so no CI check-runs to cite.","dogfood_battery": "n/a - no PR, no
!title, Clause-2 arm none","mcp_calls": "0",
"api_writes": "1 - POST /repos//issues/24815/comments (this os-dev-report, via the fleet-write relay op
comment). Not REST: onegit push -u origin claude/issue-24815-member-user-filter, the empty branch at 72518d2, which is the claim's landing marker. No pr_create was spent. All reads were unauthenticated public REST GETs plus a read-only blobless clone of objectui in the scratchpad (now deleted).","line_budget": "none set; diff is empty (0/0, no files)",
"files_changed": [],
"deviations": [
"No PR, no changeset and no pin: the ruling's item 3 fork fired (the dispatch's 'Fork, not fallback'). The draft-PR delivery and the PR-body browser reading are therefore not produced; the browser reading lives in this report's summary.",
"Dev boot ran in single-org mode. OS_TENANCY_POSTURE=group refuses to boot without @objectstack/organizations, which is not in this repo. So 'an organization with two members plus a non-member' is the Default Organization: two created members (Zhang Yang, Maria Lopez), plus admin and two showcase demo members, and a third created user (Olivia Outsider) removed via /auth/organization/remove-member. Users were created with /auth/admin/create-user, because self sign-up is invite_only.",
"Throwaway edit to sys-member.object.ts in my own worktree, as a measurement probe; reverted and proven blob-equal; never committed.",
"Nothing under content/docs/** or docs/qa/** touched."
],
"open_questions": [
{
"question": "View all opens the unanchored /data surface, which never reads a list view's userFilters, so E-prime (metadata only) cannot show a User filter there. Which way should the member-by-name need be met?",
"options": [
"F1 (objectui, renderer only): ObjectDataPage's auto-derived filter bar also offers single-valued relationship fields (lookup / master_detail / user), rendered by the LookupValuePicker that UserFilters already uses for those types. Zero metadata, spec or server change. Every related list's View all over a junction (members, team members, ...) gains a by-name picker. Cost: 1 objectui PR (domain:ui) + console pin bump + manifest regen. Open detail: the 4-filter cap and field order decide which chips show. On sys_member that is organization_id, user_id, role; the organization chip is redundant beside the URL scope, though harmless.",
"F2 (objectui + metadata): View all lands on a declared list view carrying filter[...], and this card then declares the
allview with the user_id/role user filter (the probe above shows that works). Cost: objectui PR + this metadata PR + pin bump. It reverses objectui#12741's deliberate unanchoring, and it needs a rule for WHICH view (default view =minehere would over-narrow), i.e. a new selection convention or spec key.","F3 (metadata only, E-prime as written): declare the
allview anyway. A user can reach it only by typing /view/all; View all and Setup nav never open it. Declares a capability no path delivers (PD#10); not recommended.","D: no change. Workaround: user record -> Organizations tab."
],
"recommendation": "F1. Real need: the measured gap is exactly that the View all landing has no relationship filter; the picker mechanism is already proven (1 row for a member, empty for a non-member). Long-term: it keeps ADR-0055's 'the URL is the view' and objectui#12741's unanchoring intact, and ADR-0061 Tier 2 stays deferred, as the ruling wanted; one renderer rule serves every junction. AI-error axis: nothing to author, so an AI cannot declare a filter the landing silently ignores, which F3 invites and F2 makes depend on an unwritten view-selection rule. Startup axis: no spec key, no server path, no new contract, one renderer rule. Confidence gap: F1 on ObjectDataPage itself is unmeasured. It passes derived userFilters to the same ListView/UserFilters that measured green on /view/all, so the uf* equality path should hold, but not yet browser-read there. Ownership moves to domain:ui (objectui), so this card would be re-ruled, not re-dispatched to engine."
}
],
"out_of_scope_findings": [
"class: none (drift) - examples/app-showcase/src/ui/views/task.view.ts (the comment above
grid) says the console suppresses userFilters on object list views by design. At objectui cf153eb, ObjectView.tsx renders dropdown userFilters there (ADR-0047 amended, objectui #2338) and suppresses only element:'tabs'; the probe saw 'User | Role' render. The stale comment could steer an author away from a working capability. Read-only drift with no producer harmed, so not filed. carrier: none (承接者:无); for Acceptance notes."]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
[回箱] 裁决 E′ 的前提被实测证伪:组织「成员」页的「查看全部」不经过任何列表视图,按名字找成员要怎么做?
domain:engineseat 1(seat post #6367)·os-project-manager·session_01JtSQQ3EWsbNPzyYMug1tXy· 2026-10-21T07:01Z。裁决 6289508074(字母 E′)第 3 条写明「前提被证伪就报 fork,⛔ 不硬做,也不悄悄退回 B 或 E」。dev 按此报了needs_decision(报告 6309736149),没有开 PR,也没有改任何文件。本席复核了它的实测,按 SKILL〈升级与决策〉「仅前提被证伪才回箱」把卡交回决策箱。认领 6309042170 同笔释放。一句话问题: 管理员在组织详情页点「成员 → 查看全部」,打开的页面只能按「角色」筛选,不能按「用户」筛选。裁决让我们在成员表的列表视图上加「用户」筛选,但「查看全部」根本不打开任何列表视图,所以加了也没人看得到。
背景(实测)
dev 在真实启动的 showcase 上,以管理员身份走了一遍。objectstack 用的是
72518d20f5,控制台按.objectui-sha钉在 objectuicf153eb2e535。/_console/apps/setup/sys_member/data?filter[organization_id]=…。ObjectDataPage)。页面自己写着「URL-defined data slice - not bound to any saved view」。RelatedRecordActionsBridge.tsx里「查看全部」用recordListPath()生成链接,注释写明不锚定任何保存视图,以免默认视图自带的过滤把列表缩小。本席在 objectui 本地副本里读到了同一段代码。sys_member唯一的视图mine(只显示「我的成员身份」)正好就是这种会把列表缩小的默认视图。ObjectDataPage只从字段类型自动生成筛选条,类型只限select / multiselect / radio / enum / boolean(USER_FILTER_TYPES,最多 4 个)。userFilters。所以页面上有「角色」,没有「用户」。HEAD逐字节相同):userFilters(user_id、role)的all视图后,「查看全部」打开的页面完全没变。/view/all?filter[organization_id]=…,页面显示「用户 | 角色」两个筛选。/view/all的入口。Governing text
docs/adr/0055-parameterized-bare-data-surface.md:33:「The URL is the view.filter[<field>]=<value>params (equality) apply…」。「查看全部」的落点就是这个 ADR 定义的无视图数据页。docs/adr/0061-record-search-architecture.md:50:按查找字段所指记录的名字搜索「needs a join → Tier 2」,延后。原裁决保留这个延后,本次回箱不动它。前提(复核命令)
git grep -n "recordListPath(appName, objectName" origin/main -- packages/app-shell/src/views/RelatedRecordActionsBridge.tsxgit grep -n "USER_FILTER_TYPES = new Set" origin/main -- packages/app-shell/src/views/ObjectDataPage.tsxsys_member只有mine一个视图:git grep -n -A3 "listViews: {" origin/main -- packages/platform-objects/src/identity/sys-member.object.ts选项
ObjectDataPage自动生成的筛选条也包含单值关系字段(lookup/master_detail/user),用列表视图已有的LookupValuePicker(按名字搜、按调用者权限)domain:ui· objectui 1 PR + 控制台 pin bump · 无实测先例sys_member声明带用户筛选的all视图mine会把列表缩小)all视图和用户筛选/view/all的人看得到;「查看全部」与导航都到不了。问题对用户依旧存在domain:engine1 小 PR · 违反 PD#10,不建议业务含义直译:
四轴(业务立场)
只看①选 F1;②③④ 是否翻转:否(②有拉动,③④ 都指向 F1)。
推荐:F1
ObjectDataPage上的行为尚未在浏览器实测。它把自动生成的筛选交给/view/all上已经实测通过的同一个ListView/UserFilters组件,uf_*等值筛选这条路理应成立,但还没读到。sys_member上出现哪几个筛选(organization_id、user_id、role)。其中组织筛选与 URL 里的组织条件重复,无害,但可在 F1 里一并约定隐藏已被 URL 固定的字段。裁后执行
domain:ui(objectui 渲染器),由该 lane 认领。本席不派 objectstack 的 PR。pm:blocked等它,之后本席派元数据 PR。相关: objectui#12741(「查看全部」不锚定视图的由来),ADR-0061(Tier 2 延后),dev 报告 6309736149。另有一处只读漂移:
examples/app-showcase/src/ui/views/task.view.ts的注释说控制台按设计会在对象列表视图上隐藏userFilters,但在 objectuicf153eb2e535上,dropdown 形式实际会渲染。没有生产方受影响,不立卡,只记于此。Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Maintainer ruling: F1 (the triage seat's chat, 「F1」, on the re-boxed decision
6310115089). Triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-21T08:42Zdomain:ui).ObjectDataPage's generated filter bar offers single-value relation fields throughLookupValuePicker. Its PR carries the browser measurement (a member gives 1 row, a non-member gives 0 rows).completed, with the work carried by objectui#13310. The objectui seats sweep their own repo, so the card lives there.Generated by Claude Code
feat(app-shell): the /data filter bar offers single-value relation fi…