背景
对 examples/app-showcase 权限模型(ADR-0090)做第三轮全量复测:全新 DB 起服务 → REST 49 断言 → Playwright 25 条 UI 用例。只测试、不修改代码 。修复测试环境(补岗位绑定、造 announcement 数据、物化共享)后 REST 49/49、Playwright 25/25 全部通过;下列问题均为复测过程中暴露的记录,且同日已用一手证据逐条二次核验(在线 REST 重放、SQLite 物理表直查、fresh DB 副本引导、源码/规格对照)。
完整测试报告/清单/复跑脚本可经已关闭 PR #2921 的 refs/pull/2921/head 追溯(按 #2923 政策不入库)。关联:#2920 (authz 跟踪)。
📌 重评说明(2026-07-15)
原清单基于 2026-07-14 复测时的 main。当日晚间起 main 合入了大量授权改动(#2930 写护栏、#2934 A4 三态统一、B1/B2/B4 内核链、audience-binding suggestion 机制等),本次已逐项对照最新 main(framework c5e68b2 / objectui a637ab6)源码复核 ,结论重写如下。最重要的变化:
分级速览(重评后)
#
问题
原级别
重评结论(2026-07-15)
①
锚点岗位(everyone)可被数据 API 物理删除
🔴 重大
🔴 仍成立,升级为回归 :#2930 护栏词表停在 system/config,A4 后落库值是 platform/package,护栏对 sys_position 完全不触发
②
fresh 部署绑定 0 行静默降级
🔴 重大
🟠 部分修复 :everyone 基线已 boot 自动绑;7 个 showcase 岗位仍空壳;规格 "never auto-bound" 与实现矛盾仍在
③
启动期种子不物化共享规则
🟡 未修
🟡 仍成立 ,根因=物化 hook 对 isSystem 短路(rule-hooks.ts:54)
④
无 cookie 时 console FLS fail-open
🟡 未修
🟡 仍成立 (objectui 无相关修复)
⑤
announcement 无 name/无种子/创建权窄
🟡 未修
🟢 建议降级 :displayName 回退已健全;无种子+创建权窄属设计,余下仅示例数据完善
⑥
dev 服务器被外部 SIGKILL
🔵 环境
🔵 维持原判,无代码可评
⑦
拒绝语义分层不一致(400 vs 403)
🟡 未修
🟡 仍成立 :抛出点已带 status=403/code=FORBIDDEN,但 REST 层 mapDataError 丢弃,净结果未修
⑧
lookup 列显示 name 而非 displayNameField
🔵 既知
🔵 仍成立
⑨
复跑脚本 perm-setup.sh 不自足
🟡 未修
🟡 部分缓解 :everyone 基线绑定一步已免;其余两步半仍需手工;跟随②③⑤
⑩
REST list 静默忽略 $filter
🟡 未修
🟠 部分修复 :$filter 已归一到 where;unknown-param 校验仍缺(#2873 治本项未落)
🔴 ① 锚点岗位可删 —— 已修复但被回归打穿(当前唯一 🔴)
原始现象 (07-14 实测,全链路重放):managed_by: system 的 everyone 锚点无删除保护;带绑定删除得到的 409 只是 FK 引用完整性假象——先删 everyone→showcase_member_default 绑定行(200),再 DELETE everyone 岗位 → HTTP 200,锚点真删 ;重启后 bootstrapDeclaredPositions 只补锚点行(新 id),绑定不补,基线授权丢失。
重评(对照 main c5e68b2)——缺陷仍成立,原因已变 :
PR feat(plugin-security): 内置行写护栏 — sys_position / sys_capability 平台/应用托管行不可删改 #2930 (closes feat(plugin-security): 内置行写护栏 — sys_position / sys_capability 平台/应用托管行可被删改 #2918 ,07-14 16:15 合入)新增 assertSystemRowWriteGate(packages/plugins/plugin-security/src/security-plugin.ts:598 接线,实现 ~L1958-2033),本应对托管行 delete/update fail-closed 拒绝,连 modifyAllRecords 超管也拦。
但护栏的 provenance 词表停在旧值——security-plugin.ts:133:
sys_position: { ..., managed : { system : 'the platform' , config : 'an application package' } }
而同日稍晚合入的 A4(feat(plugin-security): A4 — managed_by 三态统一 + listView 露出 (#2920) #2934 )把 sys_position 词表统一为 platform/package/admin:新锚点行落库即 managed_by: 'platform'(bootstrap-builtin-positions.ts:84),且 normalize-managed-by.ts 的 boot reconciler 会把存量 system/config 行主动改写 为 platform/package。
结果:spec.managed['platform'] 查无 → 护栏不抛错 → DELETE 直达驱动。先删绑定绕过 FK 后,everyone 锚点今天依然可被物理删除。 sys_capability 侧词表一致(platform/package),保护有效——只有 sys_position 裸奔。
回归零告警的原因 :护栏单测(security-plugin.test.ts:1282 起)仍喂 system/config 旧值,与过期的门自洽,CI 全绿。另 normalize-managed-by.ts 注释自称 "NO runtime path branches on the legacy values"——SYSTEM_ROW_PROVENANCE.sys_position 恰恰 branch 在 legacy 值上,该安全声明不成立。
"重启不自愈"半句修正 :重启时 security-plugin.ts:1301-1318 会幂等重建 everyone→fallback 集这一条 基线绑定(见②),但管理员手工加到 everyone 的其余绑定不恢复,锚点 id 漂移仍在。
修复(极小改动) :security-plugin.ts:133 词表对齐 A4({ platform: 'the platform', package: 'an application package' },与 sys_capability 行一致),同步把 security-plugin.test.ts:1282-1435 仍用 system/config/user 的用例改为新词表;并修正 normalize-managed-by.ts 的错误安全注释。建议单独开回归 bug 引用 #2918 / #2930 / #2934 。
🟠 ② fresh 部署 0 绑定 —— 部分修复,三点分述
已修 :everyone 基线不再空壳。fallbackPermissionSet 现在几乎恒有值——取 app 的 isDefault 集,无则兜底内置 member_default(security-plugin.ts:294-304);kernel:ready 时以 isSystem 上下文幂等绑到 everyone(L1285-1322),并新增高权位集拒绑护栏(loud warn)。fresh boot 下 sys_position_permission_set 不再为 0 行。新增 sys_audience_binding_suggestion 建议表 + listAudienceBindingSuggestions 服务(ADR-0090 D5/D9,suggested-audience-bindings.ts),"待绑定"首次有了可查询诊断面。
未修 :7 个 showcase 岗位(contributor/manager/exec/auditor/ops/field_ops_delegate/client_portal_user)fresh 部署仍全部空壳。建议机制只收带 packageId 的包级声明集(suggested-audience-bindings.ts collectDeclaredSuggestions L129-136 拒绝无 packageId 的应用级集),岗位↔权限集的声明式绑定仍不存在;persona 静默降级依旧,只是 everyone 基线不再一起坏。
规格矛盾仍在,且形态更清晰 :packages/spec/src/security/permission.zod.ts:187 仍逐字写 "[ADR-0090 D5] Install-time suggestion to bind this set to the everyone position (admin confirms; never auto-bound )" ,而 isDefault 集恰恰经 CLI appDefaultPermissionSetName(packages/cli/src/commands/serve.ts:1455-1462)解析为 fallback,在 boot 时被自动写入绑定(security-plugin.ts:1310,无管理员确认)。现在实际是双轨 :应用级 isDefault → 自动绑(违背规格文案);包级 isDefault → 建议表+管理员确认(符合规格)。规格文案需改写区分两轨。绑定失败仍是 catch→warn 非致命。
🟡 ③ 种子不物化共享规则 —— 仍成立,根因已定位
种子并未绕过 hook 层:SeedLoaderService 走 engine.insert/update(packages/metadata-protocol/src/seed-loader.ts:255-257 等)。真正原因是共享物化 hook 首行短路:
packages/plugins/plugin-sharing/src/rule-hooks.ts:54 — if ((ctx?.session as any)?.isSystem) return;
而种子固定用 { isSystem: true, skipTriggers: true }(seed-loader.ts:699)。
全表 reconcile 入口只有手动 REST 端点(packages/rest/src/rest-server.ts:5237 evaluateRule);启动路径仅 bindRuleHooks + bootstrapDeclaredSharingRules(播种规则行,不评估既有记录),无自动 backfill 。这与"admin 空触碰一次即物化"的实测现象完全吻合。
修复方向 :种子通道对命中共享规则的对象放行物化,或 boot 后对 declared rules 跑一次 backfill(复用 SharingRuleService.evaluateRule)。
🟡 ④ 无 cookie 时 console FLS fail-open —— 仍成立(objectui)
权限拉取只依赖 cookie:packages/permissions/src/MePermissionsProvider.tsx:80-96 用裸 fetch + credentials:'include',不注入 localStorage auth-session-token Bearer(console 其余数据层走 createAuthenticatedFetch()),Provider 也没有自定义 fetch 的口子。
未知即放行:MePermissionsProvider.tsx:118 if (!objPerm) return true;表单侧 packages/plugin-form/src/ObjectForm.tsx:304-322 在 !perms?.isLoaded 时原样返回可编辑字段。
唯一 fail-closed 分支是端点返回非 2xx(data 保持 null → loadingFallback 挡住 children)。前端缺省方向仍是 fail-open;数据面 PATCH 仍会剥离受限字段,不构成越权写入,但方向应改为权限未知即只读。
🟢 ⑤ showcase_announcement —— 建议降级为示例完善项
无 name 字段属实(examples/app-showcase/src/data/objects/announcement.object.ts:36-40,仅 title/body/owner_id),但原清单担心的"显示名回退异常"已不成立 :packages/spec/src/data/display-name.ts 的 deriveDisplayField(L163-187)会命中 Tier-1 候选 title,空值 floor 到 Record #<id>,回退健全。
无种子行属实(src/data/seed/index.ts 无 announcement 条目);创建权仅 showcase_ops(permission-sets.ts:186 唯一 allowCreate)——原清单已承认"mia 403 是设计使然"。
余下实质仅"演示数据缺一块",建议作为 app-showcase 示例完善处理,不是框架缺陷。
🟡 ⑦ 400 vs 403 分层不一致 —— 仍成立,只差最后一公里
抛出点已修了一半 :packages/plugins/plugin-sharing/src/sharing-plugin.ts:403-409 现在抛错时已带 err.status = 403; err.code = 'FORBIDDEN'。
REST 层未接 :数据 CRUD 路由 catch 走 mapDataError(POST rest-server.ts:3318 / PATCH :3404 / DELETE :3447),它从不读取 error.status;其 403 短路(L111-124)只认 code === 'PERMISSION_DENIED' / PermissionDeniedError / '[Security] Access denied' 前缀,均不匹配本错误 → 落默认分支 rest-server.ts:325 → 仍 400 + 裸 error 无 code 。(只有 sendError L338-349 会采纳 error.status,但 CRUD 路径不走它。)
修复 :让 mapDataError 尊重已标注的 error.status/error.code(或把 FORBIDDEN code 加入 403 短路),客户端即可统一分支。
🟡 ⑨ 复跑脚本不自足 —— 部分缓解,跟随②③⑤
脚本本体按 #2923 政策不入库。三个手工步骤重评:
everyone→member_default 基线绑定 —— 已免 (②的 boot 自动绑定覆盖);7 条 showcase 岗位绑定仍需 REST 循环补建;
announcement 测试数据仍需以 admin/oskar 造(不能带 name 字段)——跟随⑤;
共享物化触碰仍需——跟随③。
注:zsh 下补绑定不能用 declare -A(bad substitution),用 ${pair%%:*} 字符串切分。
🟠 ⑩ REST $filter —— 部分修复
已修 :packages/metadata-protocol/src/protocol.ts:2352-2368 现在显式识别 $filter 并归一到 where(options.filter ?? options.filters ?? options.$filter ?? options.where;字符串先试 JSON.parse / FilterAST)。原清单里"整个 $filter 被丢弃、按名取 id 实得第一条记录"的具体危险场景已消除(OData 表达式字符串结构上进入 where,语义未必被驱动接受,但不再静默返回全量——配合 #2873 已修的驱动层 fail-loud,大概率报错而非放行)。
未修 :广义的 unknown-param 校验仍缺。protocol.ts:2411-2432 的 knownParams 白名单在 !options.where 时把未知键静默转成隐式字段等值过滤 ;where 已存在时未知键静默残留。无任何 4xx 或回显生效过滤条件的机制——#2873 建议的"上游统一校验"仍是缺口。
🔵 环境 / 既知观察(维持原判)
⑥ dev 服务器反复被外部 SIGKILL
受控后台监控中尾标 echo 未执行、shell 一并消失 → 外部 SIGKILL,非进程内部崩溃;与权限模型代码无关,属测试机环境问题,记录备查。
⑧ lookup 列显示 API name 而非 displayNameField
重评确认仍成立(objectui):网格只读单元格 LookupCellRenderer(packages/fields/src/index.tsx:1171)四处调用 pickRecordDisplayName 均不传 preferredField,走硬编码启发式(name 优先,L30-47);display_field 虽在关系元数据白名单里(plugin-grid/src/ObjectGrid.tsx:210-212),但只有内联选择器 LookupField 消费,只读单元格不消费。
后续动作建议(按优先级)
立即 :为①开回归 bug(或直接修)——security-plugin.ts:133 词表对齐 + 更新 stale 单测,一行级修复堵回锚点删除;引用 feat(plugin-security): 内置行写护栏 — sys_position / sys_capability 平台/应用托管行可被删改 #2918 / feat(plugin-security): 内置行写护栏 — sys_position / sys_capability 平台/应用托管行不可删改 #2930 / feat(plugin-security): A4 — managed_by 三态统一 + listView 露出 (#2920) #2934 。
②拆两半跟进:a) showcase 岗位声明式绑定 / 应用级集进建议表(特性缺口);b) permission.zod.ts:187 "never auto-bound" 文案改写以区分应用级自动绑 vs 包级建议确认双轨(文档级)。
③⑦为根因明确、改动小的框架修复:③ hook 的 isSystem 短路对共享物化放行或 boot backfill;⑦ mapDataError 尊重 error.status/error.code。
⑤降级为 app-showcase 示例完善项;④⑧归 objectui 排期;⑩的 unknown-param 校验并入 查询过滤器遇到"不认识的条件"时,应统一报错而不是悄悄放行(所有数据驱动) #2873 后续。
复跑方式
refs/pull/2921/head 检出后:bash docs/test/scripts/perm-setup.sh → 手工补 ⑨ 剩余步骤(showcase 绑定、announcement 造数、共享触碰;everyone 基线已由 boot 自动绑定覆盖)→ bash docs/test/scripts/perm-test.sh(49 断言)→ PERM_BASE_URL=... pnpm exec playwright test --config playwright.permission.config.ts(25 条)。测试账号:admin@objectos.ai ;personas @example.com。
问题④的两张对比截图(R3-I2a/R3-I2b)留存本地,可按需以评论附件补充。
重评核验方法:framework origin/main c5e68b2 / objectui origin/main a637ab6 源码逐项对照(文中行号即当前 main);关联 PR/issue 状态核对(#2918 已由 #2930 修复合并、#2873 已关闭、#2920 开放跟踪中)。
背景
对
examples/app-showcase权限模型(ADR-0090)做第三轮全量复测:全新 DB 起服务 → REST 49 断言 → Playwright 25 条 UI 用例。只测试、不修改代码。修复测试环境(补岗位绑定、造 announcement 数据、物化共享)后 REST 49/49、Playwright 25/25 全部通过;下列问题均为复测过程中暴露的记录,且同日已用一手证据逐条二次核验(在线 REST 重放、SQLite 物理表直查、fresh DB 副本引导、源码/规格对照)。📌 重评说明(2026-07-15)
原清单基于 2026-07-14 复测时的 main。当日晚间起 main 合入了大量授权改动(#2930 写护栏、#2934 A4 三态统一、B1/B2/B4 内核链、audience-binding suggestion 机制等),本次已逐项对照最新 main(framework
c5e68b2/ objectuia637ab6)源码复核,结论重写如下。最重要的变化:分级速览(重评后)
system/config,A4 后落库值是platform/package,护栏对 sys_position 完全不触发isSystem短路(rule-hooks.ts:54)status=403/code=FORBIDDEN,但 REST 层mapDataError丢弃,净结果未修$filter$filter已归一到where;unknown-param 校验仍缺(#2873 治本项未落)🔴 ① 锚点岗位可删 —— 已修复但被回归打穿(当前唯一 🔴)
原始现象(07-14 实测,全链路重放):
managed_by: system的 everyone 锚点无删除保护;带绑定删除得到的 409 只是 FK 引用完整性假象——先删 everyone→showcase_member_default 绑定行(200),再 DELETE everyone 岗位 → HTTP 200,锚点真删;重启后bootstrapDeclaredPositions只补锚点行(新 id),绑定不补,基线授权丢失。重评(对照 main
c5e68b2)——缺陷仍成立,原因已变:assertSystemRowWriteGate(packages/plugins/plugin-security/src/security-plugin.ts:598接线,实现 ~L1958-2033),本应对托管行 delete/update fail-closed 拒绝,连modifyAllRecords超管也拦。security-plugin.ts:133:platform/package/admin:新锚点行落库即managed_by: 'platform'(bootstrap-builtin-positions.ts:84),且normalize-managed-by.ts的 boot reconciler 会把存量system/config行主动改写为platform/package。spec.managed['platform']查无 → 护栏不抛错 → DELETE 直达驱动。先删绑定绕过 FK 后,everyone 锚点今天依然可被物理删除。 sys_capability 侧词表一致(platform/package),保护有效——只有 sys_position 裸奔。security-plugin.test.ts:1282起)仍喂system/config旧值,与过期的门自洽,CI 全绿。另normalize-managed-by.ts注释自称 "NO runtime path branches on the legacy values"——SYSTEM_ROW_PROVENANCE.sys_position恰恰 branch 在 legacy 值上,该安全声明不成立。"重启不自愈"半句修正:重启时
security-plugin.ts:1301-1318会幂等重建 everyone→fallback 集这一条基线绑定(见②),但管理员手工加到 everyone 的其余绑定不恢复,锚点 id 漂移仍在。修复(极小改动):
security-plugin.ts:133词表对齐 A4({ platform: 'the platform', package: 'an application package' },与 sys_capability 行一致),同步把security-plugin.test.ts:1282-1435仍用system/config/user的用例改为新词表;并修正normalize-managed-by.ts的错误安全注释。建议单独开回归 bug 引用 #2918 / #2930 / #2934。🟠 ② fresh 部署 0 绑定 —— 部分修复,三点分述
已修:everyone 基线不再空壳。
fallbackPermissionSet现在几乎恒有值——取 app 的isDefault集,无则兜底内置member_default(security-plugin.ts:294-304);kernel:ready 时以isSystem上下文幂等绑到 everyone(L1285-1322),并新增高权位集拒绑护栏(loud warn)。fresh boot 下sys_position_permission_set不再为 0 行。新增sys_audience_binding_suggestion建议表 +listAudienceBindingSuggestions服务(ADR-0090 D5/D9,suggested-audience-bindings.ts),"待绑定"首次有了可查询诊断面。未修:7 个 showcase 岗位(contributor/manager/exec/auditor/ops/field_ops_delegate/client_portal_user)fresh 部署仍全部空壳。建议机制只收带
packageId的包级声明集(suggested-audience-bindings.tscollectDeclaredSuggestionsL129-136 拒绝无 packageId 的应用级集),岗位↔权限集的声明式绑定仍不存在;persona 静默降级依旧,只是 everyone 基线不再一起坏。规格矛盾仍在,且形态更清晰:
packages/spec/src/security/permission.zod.ts:187仍逐字写 "[ADR-0090 D5] Install-time suggestion to bind this set to the everyone position (admin confirms; never auto-bound)",而 isDefault 集恰恰经 CLIappDefaultPermissionSetName(packages/cli/src/commands/serve.ts:1455-1462)解析为 fallback,在 boot 时被自动写入绑定(security-plugin.ts:1310,无管理员确认)。现在实际是双轨:应用级 isDefault → 自动绑(违背规格文案);包级 isDefault → 建议表+管理员确认(符合规格)。规格文案需改写区分两轨。绑定失败仍是 catch→warn 非致命。🟡 ③ 种子不物化共享规则 —— 仍成立,根因已定位
种子并未绕过 hook 层:
SeedLoaderService走engine.insert/update(packages/metadata-protocol/src/seed-loader.ts:255-257等)。真正原因是共享物化 hook 首行短路:packages/plugins/plugin-sharing/src/rule-hooks.ts:54—if ((ctx?.session as any)?.isSystem) return;{ isSystem: true, skipTriggers: true }(seed-loader.ts:699)。全表 reconcile 入口只有手动 REST 端点(
packages/rest/src/rest-server.ts:5237evaluateRule);启动路径仅bindRuleHooks+bootstrapDeclaredSharingRules(播种规则行,不评估既有记录),无自动 backfill。这与"admin 空触碰一次即物化"的实测现象完全吻合。修复方向:种子通道对命中共享规则的对象放行物化,或 boot 后对 declared rules 跑一次 backfill(复用
SharingRuleService.evaluateRule)。🟡 ④ 无 cookie 时 console FLS fail-open —— 仍成立(objectui)
packages/permissions/src/MePermissionsProvider.tsx:80-96用裸fetch+credentials:'include',不注入 localStorageauth-session-tokenBearer(console 其余数据层走createAuthenticatedFetch()),Provider 也没有自定义 fetch 的口子。MePermissionsProvider.tsx:118if (!objPerm) return true;表单侧packages/plugin-form/src/ObjectForm.tsx:304-322在!perms?.isLoaded时原样返回可编辑字段。🟢 ⑤ showcase_announcement —— 建议降级为示例完善项
name字段属实(examples/app-showcase/src/data/objects/announcement.object.ts:36-40,仅 title/body/owner_id),但原清单担心的"显示名回退异常"已不成立:packages/spec/src/data/display-name.ts的deriveDisplayField(L163-187)会命中 Tier-1 候选title,空值 floor 到Record #<id>,回退健全。src/data/seed/index.ts无 announcement 条目);创建权仅showcase_ops(permission-sets.ts:186唯一 allowCreate)——原清单已承认"mia 403 是设计使然"。🟡 ⑦ 400 vs 403 分层不一致 —— 仍成立,只差最后一公里
抛出点已修了一半:
packages/plugins/plugin-sharing/src/sharing-plugin.ts:403-409现在抛错时已带err.status = 403; err.code = 'FORBIDDEN'。REST 层未接:数据 CRUD 路由 catch 走
mapDataError(POSTrest-server.ts:3318/ PATCH:3404/ DELETE:3447),它从不读取error.status;其 403 短路(L111-124)只认code === 'PERMISSION_DENIED'/PermissionDeniedError/'[Security] Access denied'前缀,均不匹配本错误 → 落默认分支rest-server.ts:325→ 仍 400 + 裸 error 无 code。(只有sendErrorL338-349 会采纳error.status,但 CRUD 路径不走它。)修复:让
mapDataError尊重已标注的error.status/error.code(或把FORBIDDENcode 加入 403 短路),客户端即可统一分支。🟡 ⑨ 复跑脚本不自足 —— 部分缓解,跟随②③⑤
脚本本体按 #2923 政策不入库。三个手工步骤重评:
everyone→member_default 基线绑定—— 已免(②的 boot 自动绑定覆盖);7 条 showcase 岗位绑定仍需 REST 循环补建;注:zsh 下补绑定不能用
declare -A(bad substitution),用${pair%%:*}字符串切分。🟠 ⑩ REST
$filter—— 部分修复已修:
packages/metadata-protocol/src/protocol.ts:2352-2368现在显式识别$filter并归一到where(options.filter ?? options.filters ?? options.$filter ?? options.where;字符串先试 JSON.parse / FilterAST)。原清单里"整个$filter被丢弃、按名取 id 实得第一条记录"的具体危险场景已消除(OData 表达式字符串结构上进入where,语义未必被驱动接受,但不再静默返回全量——配合 #2873 已修的驱动层 fail-loud,大概率报错而非放行)。未修:广义的 unknown-param 校验仍缺。
protocol.ts:2411-2432的knownParams白名单在!options.where时把未知键静默转成隐式字段等值过滤;where已存在时未知键静默残留。无任何 4xx 或回显生效过滤条件的机制——#2873 建议的"上游统一校验"仍是缺口。🔵 环境 / 既知观察(维持原判)
⑥ dev 服务器反复被外部 SIGKILL
受控后台监控中尾标 echo 未执行、shell 一并消失 → 外部 SIGKILL,非进程内部崩溃;与权限模型代码无关,属测试机环境问题,记录备查。
⑧ lookup 列显示 API name 而非 displayNameField
重评确认仍成立(objectui):网格只读单元格
LookupCellRenderer(packages/fields/src/index.tsx:1171)四处调用pickRecordDisplayName均不传 preferredField,走硬编码启发式(name优先,L30-47);display_field虽在关系元数据白名单里(plugin-grid/src/ObjectGrid.tsx:210-212),但只有内联选择器 LookupField 消费,只读单元格不消费。后续动作建议(按优先级)
security-plugin.ts:133词表对齐 + 更新 stale 单测,一行级修复堵回锚点删除;引用 feat(plugin-security): 内置行写护栏 — sys_position / sys_capability 平台/应用托管行可被删改 #2918 / feat(plugin-security): 内置行写护栏 — sys_position / sys_capability 平台/应用托管行不可删改 #2930 / feat(plugin-security): A4 — managed_by 三态统一 + listView 露出 (#2920) #2934。permission.zod.ts:187"never auto-bound" 文案改写以区分应用级自动绑 vs 包级建议确认双轨(文档级)。isSystem短路对共享物化放行或 boot backfill;⑦mapDataError尊重error.status/error.code。复跑方式
refs/pull/2921/head检出后:bash docs/test/scripts/perm-setup.sh→ 手工补 ⑨ 剩余步骤(showcase 绑定、announcement 造数、共享触碰;everyone 基线已由 boot 自动绑定覆盖)→bash docs/test/scripts/perm-test.sh(49 断言)→PERM_BASE_URL=... pnpm exec playwright test --config playwright.permission.config.ts(25 条)。测试账号:admin@objectos.ai;personas @example.com。问题④的两张对比截图(R3-I2a/R3-I2b)留存本地,可按需以评论附件补充。
重评核验方法:framework
origin/main c5e68b2/ objectuiorigin/main a637ab6源码逐项对照(文中行号即当前 main);关联 PR/issue 状态核对(#2918 已由 #2930 修复合并、#2873 已关闭、#2920 开放跟踪中)。