## 背景(来源:#23 UI 实测 K-4,维护者 2026-09-03 拍板口径:各部门目标值互相保密,按主体过滤) 部门填报人员(张伟)能打开「方案版本 / 指标下达 / 参与主体 / 到人分工 / 指标争议 / 指标库 / 归档快照 / 审核记录」,指标下达 36 条(全部主体的目标值与权重)、审核记录 96 条全部可读;左侧菜单对所有岗位全量展示。与需求 §2.2「本部门范围仅可见本部门」、手册 §1.2「每个角色只看得到自己权限内的菜单」不符。 ## 口径(已拍板) - 各部门目标值与权重互相保密:指标下达、参与主体、到人分工、审核记录、归档快照、核对任务对**部门填报人员**只开放本部门主体相关行;对**分公司核对人员**只开放本分公司相关行;分管领导只开放分管主体;人力审核 / 人力负责人 / 管理员全量。 - 指标库(指标定义与计分规则)视为公共口径,所有岗位可读,不过滤。 - 配置类菜单(方案版本、指标下达、参与主体、到人分工、指标争议、指标库、流程进度)对部门填报人员与分公司核对人员隐藏或收成只读入口——按平台 app 导航能力决定;做不到按岗位裁剪导航时如实记录为平台能力缺口(只上报不修复),数据层过滤仍必须完成。 ## 范围 1. `src/services/sharing-service.ts`:按方案的动态共享规则扩到上述对象(现有规则已覆盖填报单/明细/核对任务/数据调整等,核对哪些对象缺规则、哪些对象的权限集还是 `readOrg`),部门 / 分公司 / 分管领导三类范围与现有填报单规则同一口径;`src/security/index.ts` 权限集相应从 `readOrg` 收成 `own` + 共享。 2. `src/apps/index.ts` 导航按岗位裁剪(平台能力允许时)。 3. 单测/服务测试:为新增共享规则补覆盖(沿用 sharing-service 现有测试风格)。 4. 演示与手册不改;若手册 §1.2 的表述与实现最终不一致,在测试报告「基准差异」如实列出。 ## 不做 不改状态机与计分;不改指标库可见范围;不做「到人结果只见本人」以外的个人维度调整(已存在)。 ## 方案分级与放行(调度员) 改已有共享规则与权限集 = 高风险(影响所有岗位的可见范围)。放行方向 = 上述口径;开发子 agent 开工前须在本单评论列出「对象 × 岗位」的可见范围矩阵(改前 / 改后)与受影响的既有测试,与口径一致即可开工;若发现平台共享规则对某对象无法按主体条件表达,停手上报(objectstack-ai/objectstack 只上报不修复)并在本单记录。 ## 验收标准 1. 软件档案实例:张伟(研发部)在指标下达列表只见研发部的 3 条;审核记录只见研发部填报单的记录;归档快照只见研发部;陈东(华东)在参与主体/指标下达只见华东相关;徐涛只见技术线三主体;马丽全量。越权直接访问记录 URL 或 REST 返回 404/403。 2. 默认档案实例上 `scripts/e2e-flow.mjs` 的数据范围断言仍全 PASS;`scripts/software-flow.mjs` 仍 54/54(脚本以管理员建链,不应受影响)。 3. 导航:部门填报人员登录后看不到配置类菜单组(或如实记录平台缺口)。 4. `pnpm verify` 绿;测试报告(各岗位截图,含越权被拒)与符合度清单挂本单评论,截图走 `acceptance-evidence`。 ## 测试计划草稿 T1 可见范围矩阵评论 | T2 界面:张伟/陈东/徐涛/马丽四账号逐对象计数 | T3 越权 URL 与 REST 拒绝 | T4 导航裁剪 | T5 两脚本全 PASS | T6 pnpm verify
Activity
baozhoutao commentedon Sep 3, 2026
认领(调度员占坑,2026-09-03)
local_0e65d2bc-719b-4314-aae2-351176a17e5f(同批派发:流程按钮绕过岗位校验:动作体以受信任身份写入被 hook 当系统写入免检,任何岗位可越节点审批/归档 #28 / 发布前完整性检查缺「每个参与主体须配分管领导」,未配置的主体流程死在领导审批节点 #29 / 数据范围:指标下达、参与主体、审核记录等配置/审计对象按主体过滤,菜单按岗位裁剪(各部门目标值互相保密) #30 并行)issue-30-data-scope,基线 main @a760651293af660a8a4a13f7ec30fb3983f9a868../kpi-issue-30-data-scope,dev 端口3115,数据库file:./.objectstack/issue-30-data-scope.dbbaozhoutao commentedon Sep 4, 2026
开工前方案:「对象 × 岗位」可见范围矩阵(改前 / 改后)+ 实现方式
会话:开发子 agent(Opus),worktree
../kpi-issue-30-data-scope,分支issue-30-data-scope,基线 main @a760651293af660a8a4a13f7ec30fb3983f9a868。一、根因(读平台源码得到,不是猜)
@objectstack/plugin-sharing@17.2.0的effectiveSharingModel():而
buildReadFilter()第一道闸门是if (effectiveSharingModel(schema) !== 'private') return null;—— 返回 null = 不加任何过滤。于是:
controlled_by_parent,在共享层被当成 public,记录级过滤根本不参与求值;权限集里的readScope也随之失效(buildReadFilter提前 return 了)。public_read→ 映射为read,读侧同样不过滤。所以只改权限集不够:这些对象的 OWD 必须先落到
private,记录级共享与readScope: 'own'才开始起作用。这一条是本次改动的地基。第二条平台事实(已有代码里已记录,本次沿用):
bindRuleHooks对ctx.session.isSystem的写入 跳过共享物化(sharing materialisation skipped for isSystem writes)。本应用的审核记录、归档快照都由 hook 以系统上下文创建,因此这两个对象需要在创建后重新声明一次规则来补齐物化 —— 与现有kpi_check_task/kpi_result完全相同的补偿路径。二、可见范围矩阵
「全量」= 所在组织全部行;数字口径以软件档案实例为准(研发部 3 条下达、6 个参与主体)。
kpi_plan_indicatorkpi_plan_subjectkpi_staff_assignmentkpi_review_recordkpi_snapshotkpi_check_taskkpi_indicatorkpi_plan/ 指标争议kpi_dispute三、实现方式(三处 + 一处新增)
对象 OWD(
src/objects/plan.object.ts、entry.object.ts、result.object.ts)kpi_plan_subject/kpi_plan_indicator/kpi_staff_assignment:controlled_by_parent→private;kpi_review_record/kpi_snapshot:public_read→private。kpi_personal_item保持controlled_by_parent(主记录是到人分工,随主记录收窄)。动态共享规则(
src/services/sharing-service.ts)——沿用现有「按方案建规则、发布时对账、关闭后降只读」的同一套机制,每个参与主体单元新增:psub_<unit>→ 参与主体,条件{plan, subject: unit},收件方unit_and_subordinates(unit),readpind_<unit>→ 指标下达,条件{plan, subject: unit},同上,readassign_<unit>→ 到人分工,条件{plan, unit},同上,readsnap_<unit>→ 归档快照,条件{plan, subject: unit},同上,read..._leader_<unit>_<leader>,收件方user(leader),read{sheet: sheetId}(审核记录对象上没有主体列,平台共享条件不支持跨对象遍历,只能用它自己的列),收件方 = 该填报单主体单元unit_and_subordinates+ 分管领导user。填报单在方案发布时、provisionPlanSharing之前就已生成,取得到。规则名长度校验:最长形态
kpi_p{20}_pind_leader_{26}_{26}= 95 ≤ 100,仍在RULE_NAME_MAX以内。权限集(
src/security/index.ts)——部门填报 / 分公司核对 / 分管领导三套,把上述对象由readOrg收成{ allowRead: true, readScope: 'own' },可见性完全交给记录共享;管理员 / 人力审核 / 人力负责人保持org全量。新增一个补物化 hook(新文件,注册在
objectstack.config.ts,不动src/hooks/下任何既有文件 —— 那里有并行工作项在改):审核记录 / 归档快照afterInsert后重新声明对应对象的规则,补上系统上下文写入被跳过的物化。这与sheet.hook.ts里既有的kpi_check_task/kpi_result补偿是同一条路径,只是换个触发点。导航裁剪(
src/apps/index.ts):考核方案与基础设置两个菜单组加visibleCEL 谓词,对kpi_dept_reporter/kpi_branch_checker两个岗位隐藏。如实说明:平台把导航visible定为前端渲染谓词(requiredPermissions才是服务端闸门),因此它是「界面不呈现入口」,不是权限边界 —— 真正的边界是第 1~3 条的数据层过滤。若实测visible在分组上不生效,按平台能力缺口如实记录(只上报不修复)。测试(
test/sharing.test.ts):按现有风格给planSharingIntents补规则集合断言(新增六类规则、按方案前缀、关闭后降只读不影响只读类规则、规则名长度上界)。四、受影响的既有测试与脚本
test/sharing.test.ts—— 规则集合断言要扩(新增规则条数变化)。test/design-alignment.test.ts—— 若断言了 OWD / 权限集形态需同步。scripts/e2e-flow.mjs(默认档案)、scripts/software-flow.mjs(软件档案,54/54)—— 两个脚本都以管理员建链,管理员保持org全量,预期不受影响;实测逐条核对,不预设。五、与口径的一致性自查
与拍板口径一致,按此开工。
baozhoutao commentedon Sep 4, 2026
测试报告 — 数据范围按主体过滤 + 菜单按岗位裁剪
结论:通过。 6 个对象的按主体过滤全部生效,越权访问一律 404,配置类菜单对部门填报人员与分公司核对人员在服务端就被剥离。软件档案
software-flow.mjs54/54 全绿。默认档案e2e-flow.mjs72 通过 / 1 失败 —— 失败的 T39 是一条共享规则条数常量断言,随本次新增规则类别机械变化,而scripts/本轮禁改,已在下方「需拍板」列出精确改法。所有数据范围类断言(T50 / T51 / T53 / T55~T57 / T64 / T70)全 PASS。issue-30-data-scope@1eb5051../kpi-issue-30-data-scope,dev 端口 3115,OS_DATABASE_URL=file:./.objectstack/issue-30.dbOS_SEED_PROFILE=software,99 行种子)+ 默认档案(46 行种子,独立空库)Passw0rd!23acceptance-evidence分支issue-30/,commit224e77a0611679ecea92d9f264ae12506b182e4bpnpm verify绿(validate / typecheck / 103 单测 / i18n 同步)T1 可见范围矩阵(REST 逐对象计数,软件档案实例)
以管理员为全量基准,同一时刻同一份数据,五个账号各查一遍:
「归档快照」这一维度用已归档主体的填报人复验:赵敏(销售部,本档案唯一已归档的主体)可见快照 1 条、指标下达 3 条、审核记录 16 条 —— 说明归档快照的补物化生效(快照由 hook 以系统上下文创建,平台跳过共享物化,靠新增的补物化 hook 重新求值规则补齐)。
readScope: 'org'(他要核对全部部门的填报单),该对象不在本次拍板口径列出的六个对象内。见下方「基准差异」。界面证据
张伟(研发部·部门填报人员) —— 左侧只剩「工作台 / 填报与审核 / 结果与归档 / 审计查询」,配置类的「考核方案」「基础设置」两组不呈现;指标下达列表底部「3 条记录」,全部是研发部:
陈东(华东·分公司核对人员) —— 指标下达只见华东分公司;核对任务只见华东:
徐涛(技术线·分管领导) —— 只见分管的三个主体,菜单保持完整:
马丽(人力审核)与管理员 —— 全量可见,菜单完整:
赵敏(销售部·已归档主体) —— 可见本部门归档快照 1 条:
T3 越权访问
张伟(研发部)拿到销售部记录的真实 id 后直接访问:
GET /data/kpi_plan_indicator/{id}GET /data/kpi_plan_subject/{id}GET /data/kpi_review_record/{id}GET /data/kpi_snapshot/{id}?subject={销售部单元 id}{"records":[],"total":0}陈东(华东)同样:研发部的指标下达 404,销售部的归档快照 404。
T4 导航裁剪(服务端剥离,不是前端隐藏)
直接读
GET /api/v1/meta/app/kpi_app,看下发到浏览器的导航项 id:group_plan/group_setup及其子项这一项经历了一次实现返工,如实记录: 最初按方案写的是导航项的
visibleCEL 谓词。实测发现本版本控制台对导航项的visible根本不求值 —— 谓词原样下发到浏览器后被忽略,分组与叶子项都不生效,菜单对所有岗位照旧全量呈现。已按「只上报不修复」报到平台:objectstack-ai/objectstack#15135。改用requiredPermissions(平台在/meta里就把不满足的项剥掉)后达成目标。T5 两个脚本
scripts/software-flow.mjsscripts/e2e-flow.mjsT17c 在开发中途曾一度失败,是本次自测抓到的真缺陷:最初给「本单填报单的核对任务」建的规则不分主体类型,而分公司既是被考核主体、又是核对方,它自己那张填报单上挂着全部分公司的核对任务 —— 华东的核对人员于是看见了华南、华北的核对意见,与「分公司核对人员只开放本分公司相关行」的拍板口径直接冲突。改为只给总公司部门主体建这条规则后 T17c 恢复,并补了针对性单测。
T6 门禁
pnpm verify绿:os validate通过、tsc --noEmit无错、103 个单测全过(本次新增 12 条:四类按主体规则、按填报单规则、分公司主体不拿本单核对规则、条件收窄不变式、关闭方案后只读类不降级、超长 id 规则名仍 ≤ 100、按对象/按填报单收窄重申)、i18n 包与元数据同步(本次未新增任何 label,zh-CN529 键无变化)。基准差异(如实列出)
requiredPermissions),不是前端按角色渲染;平台的前端谓词visible在本版本不工作(平台单已上报)。手册无需改。readScope: 'org'—— 他要核对全部部门的填报单,这是既有设计;这两个对象不在本次拍板口径列出的六个对象内,本次未动。若「各部门实际值与得分也需互相保密」,那是另一条口径,需 PM 拍板后另立工作项。controlled_by_parent的子对象在读侧不随主记录收窄 —— 平台把这种 OWD 在共享层映射为public,只对 update / delete 委托主记录判定(plugin-security的masterGateCoversOperation)。因此填报明细kpi_entry_line、个人承接项kpi_personal_item、加减分kpi_bonus的读仍不按主体过滤。这是平台既有且有意的语义(describeOwd明确标注effect: 'public'),不是缺陷,本次未扩围;kpi_personal_item上的个人目标值因此仍全员可读,如需收窄要先给它自己的 OWD 与规则,属新工作项。scripts/e2e-flow.mjsT39 未过 —— 见下方「需拍板」。需拍板(一条)
scripts/e2e-flow.mjs第 227 行的常量EXPECTED_RULES是按方案配置精确推导的规则条数,新增规则类别后必然变化,scripts/本轮在禁改清单里,故未动。实测拆解已核对到条(5 个参与主体、2 个总公司部门主体、1 位分管领导、2 条到人分工):实测
rules=56,与该式逐项对上(按对象 × 收件方类型的分布也已核对)。请调度员决定:授权本子 agent 改这一行,或交由scripts/的归属方改。同一处的 T39b(「每条规则条件里都带本方案 id」)现已 PASS 且无需改动 —— 审核记录规则的条件带的是填报单 id(比方案更细),不落在 T39b 的筛选集合里。baozhoutao commentedon Sep 4, 2026
需求符合度清单
逐条对照工作项正文的「口径」「范围」「不做」「验收标准」「测试计划」。分支
issue-30-data-scope@1eb5051。一、口径
bu_sw_east)/ 到人分工 0(华东无到人分工)/ 快照 0(未归档)kpi_indicator的 OWD 与权限集本次未动/meta里即被剥掉,不下发到浏览器requiredPermissions);过程中发现的visible不求值缺口已如实记录并只上报:objectstack-ai/objectstack#15135二、范围
sharing-service.ts按方案的动态共享规则扩到上述对象psub_/pind_/assign_/snap_四类 + 分管领导同名_leader_变体;审核记录review_与本单核对任务scheck_按填报单建readOrgreadOrg的是这五类在三个受限岗位上的授权unit_and_subordinates(主体单元)+user(分管领导)的收件方组合,同一套方案前缀、发布时对账、关闭后处理src/security/index.ts权限集从readOrg收成own+ 共享readOwn常量;三个受限岗位的五个对象改用它src/apps/index.ts导航按岗位裁剪(平台能力允许时)test/sharing.test.ts新增 12 条,同文件既有风格;pnpm test103 全过docs/与演示数据零改动三、不做
src/hooks/、src/lib/scoring.ts零改动kpi_indicator/kpi_indicator_step的 OWD 与全部权限集授权未动kpi_result的 OWD、规则与行级安全谓词未动四、验收标准
e2e-flow.mjs的数据范围断言仍全 PASSscripts/e2e-flow.mjs整体全 PASSEXPECTED_RULES = 29),新增规则类别后实测 56,该常量按定义必须同步。scripts/在本次派发的禁改清单内,故未改。出口:失败升级 —— 已在测试报告「需拍板」给出逐项核对到条的新常量与改法,交调度员裁决(授权本子 agent 改,或交scripts/归属方改)。 该断言与数据范围行为无关,不构成功能缺陷。出口链接:#30 (comment)
scripts/software-flow.mjs仍 54/54/meta双向确认;分公司核对人员同visible不求值),含最小复现、期望能力、平台版本pnpm verify绿acceptance-evidence224e77a0611679ecea92d9f264ae12506b182e4b,14 张,已用 contents API 核对文件齐全五、测试计划(T1~T6)
pnpm verify统计:41 条 ✅ / 2 条⚠️ (同一件事:
e2e-flow.mjsT39 的常量,已走失败升级出口)/ 0 条 ❌。范围外但需要知会的两项改动(均为达成本单目标的必要条件,非静默扩围)
src/services/scope-materialize.ts,在objectstack.config.ts注册)。审核记录与归档快照由 hook 以系统上下文写入,平台对isSystem写入跳过共享物化(sharing materialisation skipped for isSystem writes),官方补偿手段是重新求值规则。不补这一手,这两个对象 OWD 收成private之后是「谁都看不到」,包括本该看到的本部门成员。做法与hooks/sheet.hook.ts里既有的kpi_check_task/kpi_result补偿完全同路,只是触发点换成记录自己的afterInsert;单独成文件、单独注册,src/hooks/下既有文件零改动(该目录本轮禁改)。src/security/bind-admin-set.ts)。导航裁剪走的requiredPermissions是逐条 AND、字符串精确匹配、无通配、无超级用户豁免,平台管理员的admin_full_access在这里不构成豁免 —— 实测:不加这条绑定,管理员自己会丢掉「考核方案」「基础设置」两个菜单组。本项目「考核系统管理员由平台内置管理员账号承担」(CLAUDE.md D4)此前是隐含安排,菜单闸门不认隐含,故写成幂等绑定行;按「持有admin_full_access的用户」匹配而不是按邮箱,换人、多管理员、改邮箱都不需要改代码。baozhoutao commentedon Sep 4, 2026
交接验收侧 @baozhoutao(状态 →
status:PR审查中)。issue-30-data-scope@1eb5051,基线 main @a760651293af660a8a4a13f7ec30fb3983f9a868acceptance-evidence分支issue-30/,commit224e77a0611679ecea92d9f264ae12506b182e4b(14 张,已用 contents API 核对齐全)visible(CEL) is served to the client but never evaluated — a silently inert gate (17.2.0) objectstack#15135 —— 导航项的visibleCEL 谓词下发到浏览器后不被求值;本单改用服务端闸门requiredPermissions达成裁剪,不受该缺口阻塞。待拍板一条(唯一的⚠️ ):
scripts/e2e-flow.mjsT39 的EXPECTED_RULES常量需由5*4+3+2+2*2(29)改为5*8+7+2+2*2+3(56),推导已逐项核对到条、实测吻合。scripts/在本次派发的禁改清单内故未动 —— 请裁决:授权本子 agent 改这一行,或交scripts/归属方改。除此之外自测全部通过。Merge pull request #32: subject-scoped visibility for config/audit ob…
baozhoutao commentedon Sep 4, 2026
合并记录(调度员,2026-09-03)
bind-admin-set.ts、scope-materialize.ts+objectstack.config.ts注册)已在清单披露且有据(平台导航visible不求值 → App nav itemvisible(CEL) is served to the client but never evaluated — a silently inert gate (17.2.0) objectstack#15135,改用服务端权限闸门需为管理员幂等绑定);禁触碰面 hook / 动作 / 种子 / 脚本零改动;CI 绿;测试报告、需求符合度清单、14 张证据图核对存在。全项通过。kpi_plan_config未 defineCapability(权限界面显示机器名);bind-admin-set.ts只扫直接授权且只增不减;「指标争议」菜单隐藏但填报人员仍有 allowCreate;sharing-service.ts取填报单limit: 2000;每条审核记录触发一次共享物化的扇出代价。status:PM验收中,处理人不变(验收侧)。