Skip to content

Align code with confirmed design V1.0: bonus role segregation, one active plan per period, "adjusted" marker; refresh compliance checklist and self-test record #10

Open

Description

@baozhoutao

业务场景(设计方案 docs/00 第 10 章第 6 / 10 / 13 / 14 项;第 5.6 / 5.7 / 8 章)

客户方 2026-09-02 确认《设计方案》全部口径(第 1~12 项同意产品默认,第 13 / 14 / 15 项选 A)。与当前 main(8cce30c)对照,三处代码尚未落实已确认口径,另有符合度清单与自测记录需按 os-project-dev-issue 步骤 4.5 与 os-project-dev-test 报告模板整改:

  • 第 6 项「加减分:人力审核提出、人力负责人审批」——当前 src/hooks/bonus.hook.ts 允许人力审核或人力负责人任一岗位审批,且未限制谁能登记;
  • 第 10 项「同一周期只有一个生效版本」——发布时未校验同周期是否已有已发布方案;
  • 第 14 项「结果调整改某指标得分并标记「已调整」」——kpi_entry_line 有 adjusted_score / last_adjustment,但没有用户可见的「已调整」标记,列表与汇总看不出哪一行被调过;
  • 第 13 项「分公司只核对相关指标、只能确认 / 提出争议不能改值」——实现已如此,本项只补一条权限反例用例证明;
  • 第 8 章到人口径「Σ(部门板块得分 × 分工权重 × 个人系数)+ Σ(承接项得分率 × 承接权重)」——src/lib/aggregate.ts 实现一致,但注释仍写「疑点 Q-03 未拍板,按推断口径实现」;
  • docs/04-需求符合度清单.md:Data scope via dynamic sharing rules; rescore results when a bonus is decided #4 态列为 ✅ 而统计行计为 ⚠️(docs/04 compliance checklist: statistics line and exit paragraph disagree with row #4's verdict #7);⚠️ 条目缺出口链接;多处仍写「待拍板」;证据列引用 T39~T57 而 docs/05 只到 T37;
  • docs/05-自测记录.md:单元测试数写 32(实际 55)、用例只到 T37(脚本实际 59 条);缺被测版本 commit、测试日期、用例类型 / 端 / 角色列、逐用例明细;问题记录缺复现步骤、必现 / 偶现、绕行办法、处置列。

触发操作

  1. 填报单「加减分」明细新建 / 保存(人力审核);
  2. 加减分「批准」「驳回」按钮(人力负责人);
  3. 方案「发布方案」按钮;
  4. 数据调整「批准」落地(调整类型 = 计算结果 或 源数据)。

输入与字段

  1. kpi_bonus:新建(登记)要求当前用户持有岗位 kpi_hr_reviewer(组织 owner / admin 视同管理员放行);审批动作(批准 / 驳回)要求岗位 kpi_hr_head(管理员放行);人力审核不能审批自己登记的加减分,人力负责人不能登记。
  2. kpi_plan 发布:同一考核周期 = period_type + year + period_no 三者相同;若已存在另一条状态为「已发布」的方案,发布被拒绝;「已关闭 / 已归档」的不算生效版本,不阻断。
  3. kpi_entry_line 新增字段 is_adjusted(布尔,label「已调整」,readonly,默认 false)与 adjust_type_applied(select,label「调整类型」,选项同 kpi_adjustment.adjust_type,readonly,可空);调整批准落地时由 hook 以系统上下文写入(源数据调整与结果调整都标);「已调整」列加入填报明细的列表视图与填报单内嵌网格,结果对象的计算明细 JSON 中每条指标带 is_adjusted。
  4. src/lib/aggregate.ts 顶部注释改为「口径依据《设计方案》V1.0 第 8 章表 6」,删去「未拍板 / 推断」字样;算法不改。
  5. docs/04-需求符合度清单.md:头部改为对照《设计方案》V1.0(章节号引用设计方案而非疑点编号);Product close-out: record design decisions as product defaults, add CI #6 / Align code with confirmed design V1.0: bonus role segregation, one active plan per period, "adjusted" marker; refresh compliance checklist and self-test record #10 / docs: design baseline V1.0 and delivery-document conformance fixes; add CI #11 / Align code with confirmed design V1.0: bonus role segregation, one live plan per period, "adjusted" marker #12 的「偏差与出口」改为引用设计方案第 10 章对应项,态为 ✅ 无偏差;Align code with confirmed design V1.0: bonus role segregation, one live plan per period, "adjusted" marker #12 增加「提出 = 人力审核、审批 = 人力负责人(本工作项)」;新增行:「结果调整标记已调整(设计 5.7、第 14 项)」「同周期单一生效版本(设计 5.2、第 10 项)」「分公司核对不能改值(第 13 项)」;Data scope via dynamic sharing rules; rescore results when a bonus is decided #4 的态与统计行一致(态列 ✅ 且偏差列写二期候选并链接设计方案表 10;或态改 ⚠️ 并计入统计,二选一,全文一致);Session handover: project state, pending decisions, and 12 UI findings from the manual screenshots #22 改 ✅(自由公式不进系统已由第 16 项确认为范围边界);软件公司岗位 KPI 演示数据集(独立种子档案 + 岗位人员脚本)与全流程实测 #23 保持 ⚠️,出口写「升级:实施期真实数据量验证,见设计方案表 10 试运行阶段」;统计行按最终态列重新计数;证据列引用的每个 T 编号必须在 docs/05 总表中存在。
  6. docs/05-自测记录.md 按 os-project-dev-test report-template.md 重写(最低限度档:同会话、REST 级证据,首段如实声明):首页「结论:✅ 通过 / ❌ 存在问题」+ 一行用例计数;§2 环境表含被测版本 commit SHA(本 PR head)、启动命令与端口、账号(含无权对照账号的获取方式)、前置数据、测试日期;§3 计划与结果总表列「编号 | 标题 | 类型(主流程 / 边界 / 异常 / 权限)| 端 | 角色 | 结果 | 证据」,覆盖 scripts/e2e-flow.mjs 全部用例(含本工作项新增);§4 逐用例明细至少覆盖本工作项新增 / 改动的用例(前置条件 / 操作步骤 / 预期 / 实际观察 / 结果);§5 问题记录列「# | 用例 | 现象 | 复现步骤(必现 / 偶现)| 原因分析 | 处理建议(含绕行)| 截图 | 处置」;静态门禁数字取当次真跑输出。

校验规则

  1. 非人力审核登记加减分 → 拒绝:「登记加减分失败:只有人力审核岗位可以登记加减分。请联系人力审核办理。」;
  2. 非人力负责人批准 / 驳回加减分 → 拒绝:「审批加减分失败:只有人力负责人岗位可以审批加减分。请转交人力负责人处理。」;
  3. 同周期已有已发布方案时发布 → 拒绝:「发布失败:该考核周期已有生效版本「<方案名>」。请先关闭该版本,或改用复制出的新版本替换。」(三段式:什么失败 + 原因 + 下一步);
  4. 调整批准落地后,对应明细行 is_adjusted = true、adjust_type_applied = 该调整的类型;未被调整的行保持 false;
  5. 分公司核对人员账号直接修改填报明细实际值 → 被拒绝(权限反例);
  6. 全部报错文案过 os-project-std-copy 四条红线;新增字段数字四件套 / 标签中文;pnpm validate、pnpm typecheck、pnpm test 绿;scripts/e2e-flow.mjs 全绿且新增用例编号连续。

输出 / 反馈

  • 单元测试:加减分岗位判定、发布周期唯一性、调整标记各至少 1 条;
  • e2e 新增用例:加减分登记 / 审批岗位反例各 1、同周期重复发布反例 1、调整落地后「已调整」标记 1、分公司核对人员改值反例 1;
  • 结果对象计算明细 JSON 含 is_adjusted。

依赖

无(main 8cce30c 已含 #2)。禁触碰 docs/00~docs/03、README.md、CLAUDE.md、.github/(并行工作项负责)。

验收标准

  1. 以人力审核账号登记加减分成功,以同账号批准 → 拒绝并出现校验规则 2 的文案 → 通过;
  2. 以人力负责人账号批准 → 成功,填报单最终得分随之重算 → 通过;
  3. 同周期第二个草稿方案点发布 → 拒绝并出现校验规则 3 的文案(含已生效方案名)→ 通过;先关闭已发布方案再发布 → 成功 → 通过;
  4. 结果调整批准后,填报明细列表该行「已调整」= 是、「调整类型」= 计算结果;考核结果计算明细中该指标 is_adjusted: true → 通过;
  5. docs/04 统计行 = 态列实际计数;每个 T 引用在 docs/05 §3 存在 → 通过;
  6. docs/05 首页结论与计数、§2 被测版本 SHA、§3 七列总表覆盖 e2e 全部用例 → 通过;
  7. pnpm verify 与 pnpm e2e 输出块为当次真跑原样 → 通过。

Activity

  1. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Claimed by dispatcher session session_01VR2khJ3Me96btawVsfG6jb. Branch: issue-10-align-confirmed-design. Worktree ../kpi-issue-10, baseline main @ 8cce30c, dev port 3110, database .objectstack/issue-10.db. Developer subagent dispatched; parallel item #9 owns docs/00–docs/03, README.md, CLAUDE.md, .github/ (do not touch).


    Generated by Claude Code

  2. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Self-test report for #10 — same content as docs/05-自测记录.md on branch issue-10-align-confirmed-design (commit 92721a6; tested code commit 79437b2). The report body is in the project's delivery language; §6 verbatim run output is kept in the file (it is long) and summarized here.


    KPI 考核管理系统 自测记录(开发侧)

    按 os-project-dev-test「最低限度档」执行:同会话自测,计划先落盘、逐条对照回填。
    降级声明:本轮为接口级(REST)真机验证 —— 驱动脚本以真实账号登录运行中的 dev 实例逐条调用数据接口,不是浏览器 UI 走查,也没有截图。按 os-project-std-evidence,接口级证据只能作为写操作落库的第二观察点,不替代 UI 功能证据;UI 走查与截图留待有浏览器环境的验收轮次(pm-test)。

    第 1 页:结论

    结论:❌ 存在问题

    共 66 条用例:通过 66。静态门禁 3/3 绿(validate / typecheck / vitest 64 条)。
    本工作项新增用例 7 条(T58~T64)全部通过;但工作项 #10 的验收标准 1、2 要求「以人力审核账号登记加减分」「以人力负责人账号批准」,这两步在当前数据范围设计下任何人力岗位账号都执行不了(问题记录 #1),因此结论按模板取「存在问题」。

    问题清单

    用例 问题现象(预期 vs 实际) 严重程度 问题原因(初步定位) 处理建议 截图
    验收标准 1 / 2(无对应用例:该路径不可达) 预期:持「人力审核」岗位的账号能在填报单下登记加减分、持「人力负责人」岗位的账号能批准;实际:两个账号都被平台以 403 挡在业务规则之前 —— 登记报「requires edit access to its master record」,连改填报单备注也报「You do not have access to this record」 阻塞 填报单默认共享为 private,记录级写权限只由方案发布写入的共享规则授予(参与主体单元、分公司、分管领导),人力岗位不在其中;人力岗位的权限集虽是 org 范围,读得到、写不到 【要改代码】需先拍板人力岗位的记录级写范围,再由数据范围工作项补规则;本工作项的岗位判定本身已验证(T58、T59、T60) 无(接口级证据,见问题记录 #1)

    关键观察(接口级,替代截图)

    • T58 拒绝原文:{"error":"登记加减分失败:只有人力审核岗位可以登记加减分。请联系人力审核办理。","code":"VALIDATION_ERROR","declaredCode":"KPI_BONUS_REGISTER_POSITION","object":"kpi_bonus"}
    • T61 拒绝原文:{"error":"发布失败:该考核周期已有生效版本「2026 年 11 月 月度考核」。请先关闭该版本,或改用复制出的新版本替换。","code":"VALIDATION_ERROR","declaredCode":"KPI_PLAN_PERIOD_CONFLICT","object":"kpi_plan"}
    • T63 计算明细原文:{"plan_indicator":"1GLVXvVPxDO9xY2G","indicator_name":"客户满意度","score_rate":90,"score":12.5,"is_adjusted":true,"adjust_type_applied":"result"}

    2. 测试环境与账号

    项 值
    被测版本 commit 79437b2bfa0611237c4bd2e1c17e1eb3354f8bf5(分支 issue-10-align-confirmed-design 的代码提交)。核实方式(开测前三级核对):① /proc/net/tcp 中处于 LISTEN 的端口含 3110,且无 3100 / 3111;② 占用 3110 的进程 pid 3441,/proc/3441/cwd = /home/user/kpi-issue-10;③ 该 worktree git rev-parse HEAD = 79437b2,git status 干净。文档提交 92721a6 叠在其上,不改任何被测代码
    平台 @objectstack/* 17.2.0(npm 发布版),SqlDriver(better-sqlite3),单租户
    环境 / 启动 OS_PORT=3110 OS_DATABASE_URL=file:./.objectstack/issue-10.db pnpm dev(空库启动,自动加载 46 行演示种子),地址 http://localhost:3110
    端 REST 接口(PC 端服务侧)。UI 未走查 —— 见首段降级声明
    测试账号 管理员 admin@objectos.ai / admin123(组织 owner,等同考核系统管理员岗位)。无权对照账号由脚本当场创建:管理员经 REST POST /auth/sign-up/email 建号 → sys_business_unit_member 入单元 → sys_user_position 分配岗位,口令统一 Passw0rd!23;本轮建了部门填报人员(市场部)、分公司核对人员(华东)、分管领导(前任 / 新任)四个账号
    前置数据 仅演示种子(组织单元 8、指标库、2026 年 8 月月度考核方案及其下达);其余数据由脚本按序创建,凭本表可从空库重建
    驱动脚本 scripts/e2e-flow.mjs(目标地址取环境变量 KPI_BASE_URL,本轮 http://localhost:3110)
    测试日期 2026-09-02
    未覆盖 浏览器 UI 走查与截图;大数据量性能;人力岗位账号的写路径(问题记录 #1)

    3. 测试计划与结果总表

    四类齐全:主流程 35、边界 3、异常 14、权限 14(合计 66)。全部 66 条 ✅ 通过。总表七列全文见 docs/05-自测记录.md §3;本工作项新增的 7 条摘录如下。

    编号 标题 类型 端 角色 结果 证据
    T58 非人力审核岗位登记加减分被拒绝(第 10 章第 6 项:人力审核提出) 权限 REST 部门填报人员 ✅ 通过 §6 运行输出 T58
    T59 非人力负责人岗位批准加减分被拒绝(第 10 章第 6 项:人力负责人审批) 权限 REST 部门填报人员 ✅ 通过 §6 运行输出 T59
    T60 人力负责人岗位批准加减分成功,最终得分随之重算 主流程 REST 管理员(等同人力负责人岗位) ✅ 通过 §6 运行输出 T60
    T61 同周期已有生效版本时发布被拒并点名该版本;关闭后可发布(第 10 章第 10 项) 异常 REST 管理员 ✅ 通过 §6 运行输出 T61
    T62 结果调整落地后该行标记「已调整」= 是、调整类型 = 计算结果,未调整行保持否 主流程 REST 管理员 ✅ 通过 §6 运行输出 T62
    T63 考核结果的计算明细 JSON 逐指标带 is_adjusted,被调整的那条为 true 主流程 REST 管理员 ✅ 通过 §6 运行输出 T63
    T64 分公司核对人员直接修改填报明细实际值被拒绝(第 10 章第 13 项:只能确认 / 提出争议) 权限 REST 分公司核对人员 ✅ 通过 §6 运行输出 T64

    4. 逐用例明细(本工作项新增 / 改动的用例)

    T58:非人力审核岗位登记加减分被拒绝

    • 前置条件:2026 年 11 月方案已发布(市场部为参与主体),部门填报人员账号 A 已入市场部并持岗位 kpi_dept_reporter;等待该方案的市场部填报单共享到 A 后再操作。
    • 操作步骤:以账号 A 登录 → POST /api/v1/data/kpi_bonus,body:{ sheet: <11 月市场部填报单>, title: '越权登记', bonus_type: 'add', points: 1, reason: '岗位反例' }。
    • 预期结果:① 请求被拒绝(4xx);② 提示三段式且点名岗位。
    • 实际观察:① HTTP 422;② 登记加减分失败:只有人力审核岗位可以登记加减分。请联系人力审核办理。(declaredCode KPI_BONUS_REGISTER_POSITION)。
    • 结果:✅ 通过

    T59:非人力负责人岗位批准加减分被拒绝

    • 前置条件:同 T58;管理员先在同一张填报单上登记一条待审批加减分(事项「安全生产先进」,加分 2)。
    • 操作步骤:以账号 A(对该填报单有记录级编辑权)登录 → PATCH /api/v1/data/kpi_bonus/<id>:{ status: 'approved' }。
    • 预期结果:① 被拒绝;② 提示「审批加减分失败:只有人力负责人岗位可以审批加减分。请转交人力负责人处理。」
    • 实际观察:① HTTP 422;② 文案一致(declaredCode KPI_BONUS_APPROVE_POSITION)。
    • 结果:✅ 通过
    • 补充说明:本用例用部门填报人员做反例,是因为人力审核账号连这一步都够不到(问题记录 KPI assessment app on ObjectStack: design docs, data model, scoring, review flow, security, dashboards #1);用 A 做反例反而能证明「唯一被拒的原因是岗位判定」。

    T60:人力负责人岗位批准加减分成功,最终得分随之重算

    • 前置条件:2026 年 10 月方案的市场部填报单已通过,批准前最终得分 106、加减分合计 3。管理员是组织 owner,岗位判定上等同人力负责人。
    • 操作步骤:登记加分 2 → PATCH { status: 'approved' } → 重读填报单。
    • 预期结果:① 批准成功且盖上审批人;② 加减分合计 3 → 5;③ 最终得分 106 → 108。
    • 实际观察:① status=approved、approved_by 非空;② bonus_total=5;③ before=106 after=108。
    • 结果:✅ 通过

    T61:同周期已有生效版本时发布被拒;关闭后可发布

    • 前置条件:2026 年 11 月月度考核已「已发布」。
    • 操作步骤:复制该版本新建同周期方案 → 发布 → 把原方案改为「已关闭」→ 再次发布。
    • 预期结果:① 第一次发布被拒并点名生效版本、给出下一步;② 关闭后发布成功。
    • 实际观察:① HTTP 422,发布失败:该考核周期已有生效版本「2026 年 11 月 月度考核」。请先关闭该版本,或改用复制出的新版本替换。;② 200,status=published。
    • 结果:✅ 通过

    T62:结果调整落地后标记「已调整」

    • 前置条件:2026 年 10 月方案的市场部填报单已通过,明细「客户满意度」已有得分。
    • 操作步骤:POST kpi_adjustment { adjust_type: 'result', new_value: 12.5 } → submitted → approved → 重读被调整行与另一未调整行。
    • 预期结果:① 被调整行「已调整」= 是、「调整类型」= 计算结果;② 该行得分 12.5;③ 未调整行保持否、类型为空。
    • 实际观察:① is_adjusted=true type=result;② final=12.5;③ 未调整行 is_adjusted=false、类型为空。
    • 结果:✅ 通过

    T63:考核结果计算明细 JSON 逐指标带 is_adjusted

    • 操作步骤:GET /api/v1/data/kpi_result?plan=<2026 年 10 月方案>,取部门维度、市场部那一行的 breakdown。
    • 预期结果:① lines 逐指标列出;② 被调整那条 is_adjusted: true、adjust_type_applied: 'result';③ 未调整那条 false。
    • 实际观察:① lines=3;② {"plan_indicator":"1GLVXvVPxDO9xY2G","indicator_name":"客户满意度","score_rate":90,"score":12.5,"is_adjusted":true,"adjust_type_applied":"result"};③ 未调整行 false。
    • 结果:✅ 通过

    T64:分公司核对人员改填报明细实际值被拒绝

    • 前置条件:核对人员账号 B 持岗位 kpi_branch_checker、属华东分公司(T45 已证明它能确认本分公司核对任务)。
    • 操作步骤:以 B 登录 → PATCH /api/v1/data/kpi_entry_line/<明细>:{ actual_value: 1 } → 管理员重读该行。
    • 预期结果:① 403;② 实际值未变。
    • 实际观察:① HTTP 403 PERMISSION_DENIED;② 实际值与操作前一致。
    • 结果:✅ 通过
    • 补充说明:拒绝发生在权限层(核对人员对填报明细只有读 / 导出),「只能确认 / 提出争议、不能改值」由权限模型直接兑现。

    5. 问题记录

    # 用例 现象 复现步骤 原因分析 处理建议 处置
    1 验收标准 1 / 2(无对应用例) 人力审核账号登记不了加减分、人力负责人账号批准不了加减分,连改填报单备注都被拒;两个账号都看得到填报单列表 ① 管理员建号并 POST sys_user_position {position:'kpi_hr_reviewer'};② 以该账号登录;③ GET /data/kpi_entry_sheet 能读到 25 张;④ POST /data/kpi_bonus {sheet:<任一已发布方案的填报单>,...} → 403;⑤ PATCH /data/kpi_entry_sheet/<同一张> {remark:'x'} → 403。必现(本轮 3 次 3 次出现) 填报单 OWD 为 private,记录级写权限只来自方案发布写入的动态共享规则(收件人 = 参与主体单元、核对分公司、分管领导、被下达员工),人力岗位不在其列;权限集里的 org 范围只放开了读。平台原文:[Security] Access denied: insert on 'kpi_bonus' requires edit access to its master record (master 'kpi_entry_sheet' not editable by this user (row-level security)) 【要改代码】先拍板人力岗位的记录级写范围(全部方案 / 仅本方案;写到哪些对象),再在方案发布的共享规则里补一类收件人。绕行:由考核系统管理员(或组织 owner)代为登记 / 审批 待细化退回:已写入 PR #12 与返回报告的「需拍板事项」
    2 T58 部门填报人员的权限集仍声明了加减分的新建权限,而业务规则已只允许人力审核登记 —— 声明与执行不一致(按钮点了才报错) 见 T58 kpi_dept_reporter_set 的 kpi_bonus.allowCreate 仍为 true;本工作项只改业务规则,未动权限集(范围纪律) 【要改代码】随问题 #1 的拍板一起收窄该权限声明;绕行:无需绕行,业务规则已挡住 待定(遗留问题)

    6. 运行输出(当次真跑原样)

    完整原样输出在 docs/05-自测记录.md §6(pnpm verify 与 pnpm e2e 各一段,逐条用例带接口返回摘要)。关键行:

    ✓ Validation passed (654ms)
      Data: 17 Objects  184 Fields   UI: 1 Apps  17 Views ...  Security: 6 Positions  6 Permissions
    > tsc --noEmit            (0 error)
     Test Files  6 passed (6)
          Tests  64 passed (64)
    
    PASS T58 非人力审核岗位登记加减分被拒绝(第 10 章第 6 项:人力审核提出) — status=422 {"error":"登记加减分失败:只有人力审核岗位可以登记加减分。请联系人力审核办理。","code":"VALIDATION_ERROR","declaredCode":"KPI_BONUS_REGISTER_POSITION","object":"kpi_bonus"}
    PASS T59 非人力负责人岗位批准加减分被拒绝(第 10 章第 6 项:人力负责人审批) — status=422 {"error":"审批加减分失败:只有人力负责人岗位可以审批加减分。请转交人力负责人处理。","code":"VALIDATION_ERROR","declaredCode":"KPI_BONUS_APPROVE_POSITION","object":"kpi_bonus"}
    PASS T60 人力负责人岗位批准加减分成功,最终得分随之重算 — before=106 after=108 bonus_total=5
    PASS T61 同周期已有生效版本时发布被拒并点名该版本;关闭后可发布(第 10 章第 10 项) — dup=422 {"error":"发布失败:该考核周期已有生效版本「2026 年 11 月 月度考核」。请先关闭该版本,或改用复制出的新版本替换。","code":"VALIDATION_ERROR","declaredCode":"KPI_PLAN_PERIOD_CONFLICT","object":"kpi_plan"} | after_close=200 status=published
    PASS T62 结果调整落地后该行标记「已调整」= 是、调整类型 = 计算结果,未调整行保持否 — adjusted: is_adjusted=true type=result final=12.5 | untouched: is_adjusted=false
    PASS T63 考核结果的计算明细 JSON 逐指标带 is_adjusted,被调整的那条为 true — lines=3 adjusted={"plan_indicator":"1GLVXvVPxDO9xY2G","indicator_name":"客户满意度","score_rate":90,"score":12.5,"is_adjusted":true,"adjust_type_applied":"result"}
    PASS T64 分公司核对人员直接修改填报明细实际值被拒绝(第 10 章第 13 项:只能确认 / 提出争议) — status=403 {"error":"You do not have permission to perform this action. ...","code":"PERMISSION_DENIED"}
    {"passed":66,"failed":0}
    

    Generated by Claude Code

  3. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Requirement compliance checklist for #10 — same content as docs/04-需求符合度清单.md on branch issue-10-align-confirmed-design (commit 92721a6). Three states only, no "basically implemented"; every non-✅ row carries its exit. Two rows are not ✅ and their exits are linked at the bottom.


    需求符合度清单(对照《设计方案》V1.0,客户 2026-09-02 确认第 10 章 17 项)

    章节引用一律指向设计方案(「设计 5.2」「第 10 章第 10 项」「表 10」),不再引用疑点编号;证据列的每个 T 编号都能在 docs/05-自测记录.md §3 总表查到。

    一、核心业务流程(需求 §3 / 设计第 4 章)

    # 需求 态 实现落点 / 证据 偏差与出口
    1 配置方案 ✅ kpi_plan + 五张主从明细,内联网格录入(设计 5.2);T1、T2 —
    2 发布前完整性检查 ✅ PlanPublishHook 逐条列出问题;T3 —
    3 发布:冻结配置、生成填报单与到人分工 ✅ 子配置冻结(T7);生成填报单与明细并冻结口径副本(T5、T6) 站内通知与到期提醒在设计表 10 列为二期候选
    4 填报:录入 / 导入 → 即时算分 → 提交冻结 ✅ 保存即算分(T8、T9、T11);提交后冻结(T16);CSV 导入向导 + xlsx 导出 xlsx 直接导入按钮按设计表 10 列为二期候选,不计为本期偏差
    5 核对与审核、驳回退回上一环节 ✅ 并行核对(T15)、争议阻断(T18)、全部确认自动推进(T19)、驳回原因必填与退回(T20、T21)、人力 → 领导 → 已通过(T22、T23) —
    6 计分口径 ✅ src/lib/scoring.ts + 单元测试 14 条;逆向完成率(第 4 项)、个人得分合成(第 5 项)、四种计分方式(第 12 项);aggregate.ts 顶部注释已改引设计第 8 章表 6;T8、T9、T11、T37 — 口径由第 10 章第 4 / 5 / 12 项确认,无偏差
    7 四维汇总,可钻取 ✅ 通过 / 归档 / 调整落地时生成(T24、T27),加减分审批后立即重算(T48、T49、T60);计算明细逐指标带「已调整」(T63) —
    8 归档不可变快照 ✅ SHA-256 快照 + 不可变 hook(T28~T30);归档后锁定(T31、T32);归档不可改(第 11 项) —

    二、范围功能(需求 §1.3 / 设计第 5 章)

    # 需求 态 实现落点 / 证据 偏差与出口
    9 指标管理 ✅ kpi_indicator + 阶梯区间;历史跟踪;版本与替代版本 —
    10 方案多版本、发布冻结、复制上一版 ✅ 状态机 + PlanCloneHook(T35);同周期唯一生效版本见 #26 — 「草稿与已发布并存、同周期一个生效版本」= 第 10 项确认口径
    11 流程可配置、随版本冻结 ✅ kpi_plan_step 数据化节点;两节点流程(T36) — 粒度 = 可增删节点、可改审核岗位(第 9 项);「不同部门不同流程」在表 10 列为二期候选
    12 加减分 ✅ 审批后计入最终得分(T25、T60);提出 = 人力审核、审批 = 人力负责人(第 6 项,本工作项落地:requiredBonusPosition;反例 T58、T59) — 不封顶不保底 = 第 6 项确认口径。人力岗位账号当前够不到写路径,记在 #17
    13 数据调整(源数据 / 计算结果) ✅ 记录调整前值、审批、批准即落地并重算(T26、T27);落地标记见 #25 —
    14 审计查询 ✅ kpi_review_record 只增不改(T33、T34)+ 平台审计日志 —
    15 组织与权限 ✅ 岗位 6、权限集 6;共享规则由方案发布动态写入(T39) 见 §三 #17、#18
    16 数据接入与归档 ✅ 三类数据来源在指标上声明;归档快照 「系统计算」自动取数需对接客户数据源;Excel 自由公式不进系统 = 第 16 项确认的范围边界
    25 结果调整改某指标得分并标记「已调整」(设计 5.7、第 14 项 = A) ✅ kpi_entry_line.is_adjusted / adjust_type_applied(只读,调整批准落地时由 hook 以系统上下文写入,源数据与结果调整都标);列入明细列表视图与填报单内嵌网格;结果计算明细 JSON 每条指标带 is_adjusted;T62、T63 —
    26 同一周期只有一个生效版本(设计 5.2、第 10 项) ✅ 发布前校验同 period_type + year + period_no 是否已有「已发布」方案,已关闭 / 已归档不阻断;拒绝文案点名生效版本;T61 + 单元测试 3 条 —

    三、角色与安全(需求 §2 / 设计第 9 章)

    # 需求 态 实现落点 / 证据 偏差与出口
    17 六类角色职责 ⚠️ 六个岗位 + 流程节点按岗位把关(经 sys_user_position 查询);加减分岗位分离已落地(T58、T59) 偏差:人力审核、人力负责人两个岗位当前只有读范围 —— 填报单 OWD 为 private,记录级写权限只授予参与主体单元、核对分公司、分管领导,人力岗位不在其中,因此加减分登记 / 审批与人力审核节点的推进实际只有管理员执行得了。出口:升级裁决 —— 见本工作项的测试报告问题记录 #1(含最小复现与绕行:管理员代办)与 PR #12 的「需拍板事项」
    18 数据范围:全部 / 分管 / 本部门 / 仅本人 ✅ private 基线 + 方案发布写入的动态共享规则;到人结果行级安全只挡他人(T41、T44、T46、T51、T54~T57) 实现说明四点(按方案建规则并对账、方案结束后留读去写、系统写入后重新声明规则、演示夹具对齐)见仓库文件
    19 越权访问拒绝、经办人以登录账号为准 ✅ 权限集对象级 + 字段级;经办人 / 审批人由 hook 盖章;越权反例 T42、T58、T59、T64 —
    20 账号安全 ✅ 平台账号体系;审批、驳回、归档留痕 访问来源白名单归部署层配置
    27 分公司核对只能确认 / 提出争议,不能改值(第 13 项 = A) ✅ 核对人员权限集对填报明细只有读 / 导出,改值在权限层即被拒(T64);确认与争议走核对任务(T45、T17) —

    四、非功能(需求 §4)

    # 需求 态 实现落点 / 证据 偏差与出口
    21 得分口径唯一、历史不漂移 ✅ 计分只在 scoring.ts、汇总只在 aggregate.ts(依据设计第 8 章表 6);明细冻结口径副本;快照不可变 —
    22 遵循 Excel 习惯、即时出分、逐层钻取 ✅ 内联网格、即时算分、三段式提示、报表钻取 自由公式 / 跨 sheet 引用不进系统 —— 第 16 项已确认为范围边界,不再计为偏差
    23 性能:大数据量表格 ⚠️ 填报单按主体拆分,列表分页 出口:升级 —— 实施期用真实数据量验证,见设计表 10「试运行」阶段
    24 可扩展 ✅ 计分方式数据化;考核关系与流程节点是方案数据;视图为元数据 新计分「方式」需加代码分支(口径参数不需要);清单四种 = 第 12 项确认

    五、统计


    Generated by Claude Code

  4. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Dispatcher decisions on the three items raised in the developer's report (PR #12 @ 92721a6):

    1. HR positions' record-level write access → option A. On plan publish, the sharing service creates two additional per-plan rules granting kpi_hr_reviewer and kpi_hr_head edit on that plan's entry sheets (child bonus rows follow) and on its adjustments; same naming/condition/reconcile/close-to-read-only mechanics as the existing three rule kinds. This is in scope of design item 6 ("HR reviewer proposes, HR head approves") — the feature is not usable by those positions without it. The T39 rule-count assertion is updated accordingly.
    2. Dual-position / admin self-approval → option A (position segregation is sufficient; no "cannot approve own entry" rule).
    3. Comment language: English header + Chinese report body, as done.
      Also folded in: kpi_dept_reporter_set no longer declares create on kpi_bonus (declaration now matches the rule).

    Required re-verification with real position accounts (not admin): HR reviewer registers a bonus and is refused approval; HR head approves and the sheet total is rescored; HR reviewer advances the HR review node; a closed plan drops HR to read-only. Returned to the developer on the same branch.


    Generated by Claude Code

  5. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Review round 1 — self-test report update for #10. Same content as docs/05-自测记录.md on branch issue-10-align-confirmed-design (commit a92c9d9; tested code commit 98cf887). Supersedes the earlier report comment: the verdict changes to a pass, and problem records 1 and 2 are closed as fixed-and-retested. Report body in the project's delivery language; §6 verbatim output stays in the file.


    第 1 页:结论

    结论:✅ 通过

    共 72 条用例:通过 72。静态门禁 3/3 绿(validate / typecheck / vitest 67 条)。
    工作项 #10 的七条验收标准全部达成 —— 其中验收标准 1、2(以人力审核账号登记、以人力负责人账号批准)在第一轮受数据范围所限无法演示,第二轮按调度员 2026-09-02 的裁定(选项 A)补上人力岗位共享规则后,由真实岗位账号取证通过(T65、T66、T67)。

    关键观察(接口级,替代截图)

    • T65 人力审核账号登记加减分:share=true register=201,加减分落库状态「待审批」
    • T66 拒绝原文:{"error":"审批加减分失败:只有人力负责人岗位可以审批加减分。请转交人力负责人处理。","code":"VALIDATION_ERROR","declaredCode":"KPI_BONUS_APPROVE_POSITION","object":"kpi_bonus"}
    • T67 人力负责人批准后:approved_by = 该账号本人,填报单最终得分 before=103 after=105
    • T68 人力负责人登记加减分:HTTP 403,拒绝层 = 权限集
    • T69 人力审核账号推进流程:reject=200→draft approve=200→approved
    • T70 方案关闭后:该方案岗位规则 4 条全部 read,该账号读填报单 200、写加减分 403

    2. 测试环境(变化部分)

    项 值
    被测版本 commit 98cf887450737d4375dd6eacfacae140c3afb1d4(第二轮代码提交;第一轮为 79437b2)。三级核对:① LISTEN 端口含 3110、无 3100 / 3111;② 占 3110 的进程 pid 5428,cwd = /home/user/kpi-issue-10;③ worktree HEAD = 98cf887 且工作树干净
    启动 OS_PORT=3110 OS_DATABASE_URL=file:./.objectstack/issue-10.db pnpm dev。改元数据 / 服务后必须先 rm -rf dist 再重启,否则 dev 会沿用上一次的构建产物(问题记录 #3)
    测试账号 在原四个非管理员账号之外,新增人力审核、人力负责人两个真实岗位账号(经 REST 建号 → 分配 sys_user_position),本轮的岗位验证一律用它们,不用管理员

    3. 总表(新增部分)

    四类齐全:主流程 38、边界 3、异常 14、权限 17(合计 72),全部 ✅ 通过。第二轮新增 6 条:

    编号 标题 类型 端 角色 结果 证据
    T65 人力审核账号登记加减分成功(岗位规则已授予记录级编辑权) 主流程 REST 人力审核 ✅ 通过 §6 运行输出 T65
    T66 人力审核账号批准自己登记的加减分被拒绝(第 10 章第 6 项:人力负责人审批) 权限 REST 人力审核 ✅ 通过 §6 运行输出 T66
    T67 人力负责人账号批准加减分成功,填报单最终得分随之重算 主流程 REST 人力负责人 ✅ 通过 §6 运行输出 T67
    T68 人力负责人账号登记加减分被拒绝(权限集不声明新建权限) 权限 REST 人力负责人 ✅ 通过 §6 运行输出 T68
    T69 人力审核账号在人力审核节点驳回与审核通过均成功(真实岗位账号推进流程) 主流程 REST 人力审核 ✅ 通过 §6 运行输出 T69
    T70 方案关闭后人力岗位对该方案填报单降为只读(留读、去写) 权限 REST 人力审核 ✅ 通过 §6 运行输出 T70

    第一轮用例 T58 的判定同步更新:部门填报人员登记加减分现在被权限集挡下(该权限集不再声明加减分新建权限),业务规则本身的文案由单元测试 requiredBonusPosition 取证。

    4. 逐用例明细(第二轮新增)

    T65:人力审核账号登记加减分成功

    • 前置条件:第二轮新建 2026 年 12 月方案(两节点流程:部门填报 → 人力审核),发布后由管理员填完市场部填报单并提交,填报单处于「人力审核中」;人力审核账号持岗位 kpi_hr_reviewer,不属于任何考核主体单元、也不是分管领导。
    • 操作步骤:① 轮询 sys_record_share,等岗位共享规则求值出该账号对该填报单的 edit 行;② 以该账号 POST /api/v1/data/kpi_bonus(加分 2);③ 重读该加减分。
    • 预期 / 实际:① 共享行出现 / share=true;② 登记成功 / HTTP 201;③ 状态「待审批」/ status=draft。
    • 结果:✅ 通过

    T66:人力审核账号批准自己登记的加减分被拒绝

    • 前置条件:T65 的加减分待审批,操作账号仍是登记它的人力审核账号(此时它对填报单已有记录级编辑权,拒绝只可能来自岗位判定)。
    • 操作步骤:PATCH /api/v1/data/kpi_bonus/<id>:{ status: 'approved' }。
    • 预期 / 实际:① 被拒 / HTTP 422;② 文案「审批加减分失败:只有人力负责人岗位可以审批加减分。请转交人力负责人处理。」/ 一致,declaredCode = KPI_BONUS_APPROVE_POSITION。
    • 结果:✅ 通过 —— 同时兑现「人力审核不能审批自己登记的加减分」。

    T67:人力负责人账号批准加减分成功,最终得分随之重算

    • 前置条件:T65 的加减分待审批;批准前填报单最终得分 103、加减分合计 0。
    • 操作步骤:以人力负责人账号 PATCH { status: 'approved' } → 管理员重读填报单与加减分。
    • 预期 / 实际:① 批准成功 / 2xx;② 审批人 = 该账号 / approved_by 相符;③ 加减分合计 +2 / bonus_total=2;④ 最终得分 103 → 105 / before=103 after=105。
    • 结果:✅ 通过

    T68:人力负责人账号登记加减分被拒绝

    • 操作步骤:以人力负责人账号 POST /api/v1/data/kpi_bonus(同一张填报单)。
    • 预期 / 实际:① 被拒 / HTTP 403;② 记录拒绝层 / 权限集(kpi_hr_head_set 不声明新建权限)—— 与「登记 = 人力审核」一致,拒绝早于业务规则。
    • 结果:✅ 通过

    T69:人力审核账号在人力审核节点驳回与审核通过

    • 前置条件:12 月方案的市场部填报单处于「人力审核中」,该节点审核岗位 = kpi_hr_reviewer。
    • 操作步骤:① 该账号 { pending_action: 'reject', action_reason: '数据口径请复核' };② 管理员重新提交;③ 该账号 { pending_action: 'approve' }。
    • 预期 / 实际:① 驳回成功、退回「填报中」并留原因 / reject=200 → draft,last_reject_reason 相符;② 审核通过、两节点流程下直接「已通过」/ approve=200 → approved。
    • 结果:✅ 通过 —— 人力审核节点第一次由真实岗位账号推进。

    T70:方案关闭后人力岗位对该方案填报单降为只读

    • 操作步骤:① 管理员把 12 月方案改「已关闭」,轮询岗位规则降为 read;② 该账号 GET 填报单;③ 该账号 POST 加减分。
    • 预期 / 实际:① 4 条岗位规则全部 read / 相符;② 读得到 / 200;③ 写被拒 / 403。
    • 结果:✅ 通过

    5. 问题记录(处置更新)

    # 用例 现象 原因分析 处理 处置
    1 第一轮:验收标准 1 / 2;第二轮:T65~T70 人力岗位账号登记不了、审批不了加减分,连改填报单备注都被拒 填报单 OWD = private,记录级写权限只来自方案发布写入的动态共享规则,收件人不含人力岗位;权限集的 org 范围只放开读 按裁定选项 A:方案发布时为两个人力岗位建按方案的共享规则(收件方类型 = position),授予本方案全部填报单与数据调整 edit;加减分作为主从子记录随之可写 已修复并重测 —— 修复与重测所在提交 98cf887,证据 T65~T70
    2 T58 / T68 部门填报人员的权限集仍声明加减分新建权限,与业务规则不一致 kpi_dept_reporter_set.kpi_bonus.allowCreate = true 改为 allowCreate: false;kpi_hr_head_set 保持不可新建 已修复并重测 —— 提交 98cf887,证据 T58、T68
    3 第二轮首跑 T39 / T65~T70 改完共享规则代码重启 dev 后规则一条没写出来、T39 规则数仍是旧值,服务端无任何报错 objectstack dev 沿用了 dist/ 里上一轮的构建产物,新源码没进运行实例;grep _pos_ dist/*.mjs = 0 命中 【环境问题】改元数据 / hook / 服务后,重启前先 rm -rf dist(项目 CLAUDE.md D3),重启后确认新产物含新代码再开测 已解决:清 dist/ 后同一份脚本 72/72 通过

    6. 运行输出

    完整原样输出在 docs/05-自测记录.md §6。关键行:

    ✓ Validation passed (597ms)
      Data: 17 Objects  184 Fields ... Security: 6 Positions  6 Permissions
    > tsc --noEmit            (0 error)
     Test Files  6 passed (6)
          Tests  67 passed (67)
    
    PASS T39 发布按方案配置写入动态共享规则,条数与方案配置精确相符,元数据零改动 — rules=29 expected=29
    PASS T65 人力审核账号登记加减分成功(岗位规则已授予记录级编辑权) — share=true register=201
    PASS T66 人力审核账号批准自己登记的加减分被拒绝(第 10 章第 6 项:人力负责人审批) — status=422 {"error":"审批加减分失败:只有人力负责人岗位可以审批加减分。请转交人力负责人处理。","code":"VALIDATION_ERROR","declaredCode":"KPI_BONUS_APPROVE_POSITION","object":"kpi_bonus"}
    PASS T67 人力负责人账号批准加减分成功,填报单最终得分随之重算 — approved_by=true before=103 after=105
    PASS T68 人力负责人账号登记加减分被拒绝(权限集不声明新建权限) — status=403 拒绝层=权限集
    PASS T69 人力审核账号在人力审核节点驳回与审核通过均成功(真实岗位账号推进流程) — reject=200→draft approve=200→approved
    PASS T70 方案关闭后人力岗位对该方案填报单降为只读(留读、去写) — 岗位规则 4 条全部 read=true read=200 write=403
    {"passed":72,"failed":0}
    

    需求符合度清单同步更新:#17「六类角色职责」由 ⚠️ 改 ✅,统计行改为 ✅ 26、⚠️ 1(#23 未压测)、❌ 0 —— 全文见 docs/04-需求符合度清单.md(commit a92c9d9)。


    Generated by Claude Code

  6. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Dispatcher collection check for PR #12 (head a92c9d9, base now fbf64da): passed.

    • 14 changed files, all within the allowed set (src/, test/, scripts/, docs/04, docs/05); none of docs/00–03, README, CLAUDE.md, .github; no binaries.
    • git merge-tree --write-tree origin/main HEAD against the advanced main: clean.
    • pnpm verify re-run by the dispatcher: validation passed (17 objects, 184 fields, 6 positions, 6 permission sets), typecheck clean, 67/67 unit tests.
    • docs/04 statistics line matches the state column (26 ✅ / 1 ⚠️ / 0 ❌); every T reference in docs/04 exists in the docs/05 summary table; docs/05 carries the tested commit and test date.
    • Commit trailers present on all 4 commits; no model identifiers in messages or diff.

    Next: independent review gate, then merge.


    Generated by Claude Code

  7. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Review gate (independent reviewer, PR #12 @ a92c9d9): NOT MERGEABLE — 0 blocking, 1 should-fix, 8 notes. Returned to the developer on the same branch.

    Should-fix: the explicit inlineColumns added to the entry-sheet inline grid (src/objects/entry.object.ts) replaces the platform-derived column set, silently dropping six existing columns (plan_indicator — required —, indicator, direction, scoring_method, calc_trace, last_adjustment). Fix: list them back, folding the verbose ones with defaultHidden: true.

    Folded in (small, same files): organization filter on the "one live plan per period" lookup so other tenants' plans cannot collide; JSDoc placement in the sharing service.

    Recorded, not acted on: publish race window between two drafts (no platform unique constraint available); bonus register-position message no longer reachable by a real account after the permission-set tightening (permission set refuses first); personal-item score stays rate-based while flagged adjusted (matches design table 6); HR edit on sheets extends to lines only while the sheet is still in draft.

    Degradation reconciliation: all 27 checklist rows verified against code; the single ⚠️ (#23 load test) has a legitimate exit.


    Generated by Claude Code

  8. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Review round 2 — gate findings fixed on branch issue-10-align-confirmed-design (code commit 6ba334f, docs commit 783fa80). PR #12 stays draft, status label unchanged. Report body in the project's delivery language; full report and verbatim output live in docs/05-自测记录.md.

    结论:✅ 通过 — 72 条 e2e 用例全部通过,静态门禁 3/3 绿(validate / typecheck / vitest 68 条)。

    本轮改动

    项 改动 证据
    🟡-1 内嵌网格列集回归 填报单「指标填报」内嵌网格补回全部 19 列(= kpi_entry_line 除主从字段外的全部字段),顺序沿用字段定义顺序、新增的「已调整 / 调整类型」排最后;计算说明、最近调整、指标三列用平台原生 defaultHidden 折叠而非删除 逐列核对子对象 20 个字段一一对应(缺列 0、多列 0);读回构建产物 dist/objectstack.json:19 列、3 列默认隐藏;pnpm validate 绿
    🔵-1 同周期唯一性的租户隔离 查「同周期已发布方案」的 find 加 organization_id 等值条件(组织从落库的方案行上取,不从 ctx.previous 取);纯函数 findPublishedConflict 同步比较租户,两边都有组织才比,缺组织时退回只按周期判定(缺字段不得变成静默放行) 单元测试新增「不同组织同周期不冲突 / 同组织仍冲突 / 缺组织时仍按周期判定」;e2e T61 仍绿
    🔵-7 注释位置 人力岗位说明块并入 planSharingIntents 的 JSDoc,常量移到 JSDoc 之上,注释与函数签名之间不再有代码 结构核对 + typecheck

    未动的 🔵(并发发布窗口、承接项得分与「已调整」标记的关系)按指示只记录、不改。

    问题记录(新增 #4,已闭环)

    # 现象 原因分析 处理 处置
    4 填报单内嵌网格少了六列:来源下达(必填)、指标、指标方向、计分方式、计算说明、最近调整 —— 本工作项只要求加一列「已调整」 给主从字段显式声明 inlineColumns 会整体替换平台从子对象派生的列集,而新列表只写了 13 列 补齐 19 列并保序,冗长列用 defaultHidden 折叠 已修复并重测:修复与重测所在提交 6ba334f,构建产物核对 19 列(3 列默认隐藏),pnpm validate 绿、e2e 72/72

    问题记录 #1(人力岗位写范围)、#2(部门填报人员权限声明)仍为「已修复并重测(98cf887)」;#3(dev 沿用旧 dist/ 构建产物)已解决,本轮开测前照此先 rm -rf dist 并核对新产物含本轮代码。

    原样命令输出

    $ pnpm verify
    ✓ Validation passed
      Data: 17 Objects  184 Fields
      UI: 1 Apps  17 Views  1 Pages  2 Dashboards  3 Reports  16 Actions
      Security: 6 Positions  6 Permissions
    > tsc --noEmit
     Test Files  6 passed (6)
          Tests  68 passed (68)
    
    $ KPI_BASE_URL=http://localhost:3110 node scripts/e2e-flow.mjs
    {"passed":72,"failed":0}
    

    被测版本 6ba334fab01a02da5ce60cb6e556ae718fa1eea8;开测前三级核对:LISTEN 端口含 3110 且无 3100 / 3111 · 占用进程 pid 7077 的 cwd 为任务 worktree · worktree HEAD = 被测提交且工作树干净。需求符合度清单 #25 已注明网格列为显式声明且派生列一列未少;统计行仍为 ✅ 26 / ⚠️ 1(#23 未压测)/ ❌ 0。


    Generated by Claude Code

  9. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Review gate round 2 (PR #12 @ 783fa80): the inline-grid column set and the JSDoc placement are closed. One new should-fix was introduced by the tenant-filter change: the "one live plan per period" lookup filters organization_id by equality in the query, which excludes published plans whose organization is empty (seeded/imported rows, e.g. the demo plan published in T4) before the fail-closed tenant check can see them. Dispatcher decision: one more targeted commit on the same branch (drop the query-side organization filter, keep the function-side check, add a case proving an organization-less published plan still blocks), then a focused re-check — not an escalation, since the fix is deterministic and two lines.


    Generated by Claude Code

  10. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Review round 3 — 🟡-2 fixed on branch issue-10-align-confirmed-design (code commit 69a33c6, docs commit 0252185). PR #12 stays draft, status label unchanged. Report body in the project's delivery language; full report and verbatim output live in docs/05-自测记录.md.

    结论:✅ 通过 — 73 条 e2e 用例全部通过(新增 T71),静态门禁 3/3 绿(validate / typecheck / vitest 68 条)。

    本轮改动

    项 改动 证据
    🟡-2 租户过滤造成同周期漏判 去掉 where.organization_id,候选只按 status: 'published' 取;租户判定完全留在纯函数 sameTenant(两边都有组织才比,任一边缺失退回只按周期判定) 单测补「组织为空的候选仍冲突」;新增 e2e T71;消融对照见下
    ⚪-1 注释措辞 内嵌网格注释改为「前 17 项 = 本次之前就有的全部字段」 typecheck / validate 绿

    为什么是漏判:等值条件不匹配 NULL,而种子 / 导入写进来的方案行组织就是空的(docs/05 里 T4 发布的种子方案 organization_id: null),于是这类已发布方案在进入判定之前就被查询滤掉,sameTenant() 的兜底永远轮不到它 —— 同周期唯一性变成「看数据从哪来」。第三轮之前没有这个问题。

    反向验证(消融),T71 不是一条恒绿的断言

    腿 做法 读数
    变异 把 where.organization_id 过滤加回去 → 证明改动落盘(注入命中 3、原文本命中 0、blob 哈希变化)→ rm -rf dist 重建 → 确认变异进入构建产物(命中 3)→ 重跑 e2e T71 转红:dup=200(重复发布成功);T61(两条方案都有组织)保持绿;汇总 {"passed":72,"failed":1}
    还原 git checkout HEAD -- src/hooks/plan.hook.ts → git diff HEAD 空、blob 哈希 = HEAD: 版本(dae1c9f8…)→ rm -rf dist 重建 → 确认变异标记从产物消失(命中 0)→ 重跑 T71 恢复绿,汇总 {"passed":73,"failed":0}

    方向与评审判断完全吻合:只在「候选组织为空」这一条数据路径上失效,带组织的用例照常拦截。

    问题记录(新增 #5,已闭环)

    # 现象 原因分析 处理 处置
    5 组织为空的已发布方案挡不住同周期发布(HTTP 200 直接发布成功) 等值条件不匹配 NULL,候选在判定前被滤掉,纯函数的兜底分支永远不生效 候选只按状态取,租户判定交给纯函数;补空组织候选的单测与 e2e T71 已修复并重测:提交 69a33c6,证据 T71 + 上表消融对照

    #1、#2(98cf887)、#4(6ba334f)仍为「已修复并重测」;#3(dev 沿用旧 dist/)已解决,本轮开测前照例先 rm -rf dist 重建。本轮新增一条经验并写进报告环境章节:打包器会剥离注释,所以「grep 注释串」不是有效的新鲜度探针 —— 只有行为(消融对照)才是。

    原样命令输出

    $ pnpm verify
    ✓ Validation passed
      Data: 17 Objects  184 Fields
      UI: 1 Apps  17 Views  1 Pages  2 Dashboards  3 Reports  16 Actions
      Security: 6 Positions  6 Permissions
    > tsc --noEmit
     Test Files  6 passed (6)
          Tests  68 passed (68)
    
    $ rm -rf dist .objectstack/issue-10.db* && OS_PORT=3110 ... pnpm dev      # 旧实例按 PID 停
    $ KPI_BASE_URL=http://localhost:3110 node scripts/e2e-flow.mjs
    PASS T71 组织为空的已发布方案仍阻断同周期发布(租户判定不靠查询过滤) — seed_org=null seed_status=published dup=422 {"error":"发布失败:该考核周期已有生效版本「2026 年 8 月 月度考核」。请先关闭该版本,或改用复制出的新版本替换。","code":"VALIDATION_ERROR","declaredCode":"KPI_PLAN_PERIOD_CONFLICT","object":"kpi_plan"}
    {"passed":73,"failed":0}
    

    被测版本 69a33c6f1bafc57254862d89b8b355235edc78ce;三级核对:LISTEN 端口含 3110 且无 3100 / 3111 · 监听进程 cwd 为任务 worktree · HEAD = 被测提交、工作树干净且被改文件 blob 与 HEAD: 一致。需求符合度清单 #26 已注明「候选只按状态取、租户判定在纯函数里做」并引用 T71;统计行仍 ✅ 26 / ⚠️ 1(#23 未压测)/ ❌ 0。


    Generated by Claude Code

  11. added a commit that references this issue on Sep 2, 2026
  12. baozhoutao commented on Sep 2, 2026

    @baozhoutao
    ContributorAuthor

    Merged PR #12 into main as 50ab3ac (collection check passed at every round; review gate MERGEABLE at 0252185; CI verify green). Status → PM验收中; handed to the work-item creator for acceptance. Evidence for this item is REST-level (declared in docs/05); UI walkthrough and screenshots remain for the pm-test round. Reviewer notes left open for later items: concurrent-publish window on the period check, personal-item score vs. the adjusted marker, and the demo fixture in src/data/align-demo-units.ts to be removed once objectstack-ai/objectstack#14547 lands.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions