diff --git a/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/design.md b/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/design.md index c5e1f4d3..33840fb9 100644 --- a/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/design.md +++ b/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/design.md @@ -30,9 +30,11 @@ B2 全局启用:同一应用候选 - admin smoke:只用于系统设置、非参与人视图和 flag 操作,不代行财务审批。 - employee smoke:从当前 5 人部门迁入已确认零成员的隔离部门,建立合成草稿并验证 owner 合同;终态常驻该部门,不再迁回。 - manager smoke:新建 manager + employee 的 OA-only 专用身份并设为 employee smoke 的直属 manager。普通 employee 没有直属 manager 时,提交会被 `no_manager_found` 阻断,不会走 finance fallback。 -- finance smoke:新建 finance + employee 的 OA-only 专用身份,放入隔离部门,用于财务只读投影;不恢复已消失旧账号,不绑定真人身份。 +- finance smoke:新建 finance + employee 的 OA-only 专用身份,放入隔离部门,用于财务只读投影;不恢复已消失旧账号,不绑定真人身份。因为完整 finance 角色包含付款能力,账号在验收窗口外保持 disabled,每次启停均需生产账号写入授权。 - 真实 finance:仅负责 4 张真人单据的业务退回和重提复核,凭据不交给自动化。 +隔离部门改名为“系统测试专用(勿分配员工)”。名称用于降低 HR 误分配概率,但每次灰度仍必须以实时成员集合为准:只允许 employee/manager/finance 三个 smoke,任何第四个成员都使灰度门关闭。 + 合成材料必须是无真实抬头、号码、账户和业务正文的测试 PDF/图片。成功提交的合成单据通过 owner 撤回回到草稿再删除;阻断场景直接删除草稿。审计记录保留。 ## Migration 与 seed @@ -51,9 +53,9 @@ B2 全局启用:同一应用候选 1. B1 init 后确认 DB flag 记录已由 seed 显式创建为 `force_off`,不得接受 `missing_flag_record`,并保存完整快照。 2. 经生产配置授权把 env hard gate 设为 true,重启同一候选。 3. 验证 `envEnabled=true`、`effectiveEnabled=false`、reason=`flag_force_off`。 -4. 经灰度授权把 DB 更新为 department allowlist,仅含隔离部门。 +4. 经灰度授权前实时确认隔离部门只有三个 smoke,并在获批窗口临时启用 finance smoke;随后把 DB 更新为 department allowlist,仅含隔离部门。 5. 执行合成验证;失败恢复调用前快照,优先 `force_off`。 -6. 灰度 PASS 后,经全局授权更新为 global force_on。 +6. 灰度 PASS 后,经全局授权更新为 global force_on;验收窗口结束立即 disabled finance smoke。 flag 更新使用 API 的 expectedVersion 并发控制并自动写审计。关闭 flag 只改变后续行为,不删除已建立的关联。 diff --git a/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/implement.md b/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/implement.md index 7a6a5928..f437c2ff 100644 --- a/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/implement.md +++ b/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/implement.md @@ -8,9 +8,10 @@ ## 2. 验收准备(独立生产写入授权) -- [ ] 再次只读确认隔离部门零真人成员,把它固定为常驻 smoke 部门。 +- [ ] 再次只读确认隔离部门零真人成员,经生产写入批准改名为“系统测试专用(勿分配员工)”,并固定为常驻 smoke 部门。 - [ ] 新建 OA-only manager smoke(manager + employee)与 finance smoke(finance + employee),凭据写入私有 smoke env,不输出、不绑定真人。 - [ ] 把 employee smoke 迁入常驻 smoke 部门,将 manager smoke 设置为其直属 manager;先用合成空壳草稿确认 workflow 可分配,再创建明显标识的合成历史草稿和非真实票据/附件。 +- [ ] finance smoke 创建后默认 disabled;验收窗口开始前经单独批准临时启用,窗口结束立即 disabled。不得让持付款能力的 smoke finance 常驻 active。 - [ ] 明确授权材料合并预览产生设计内审计记录;真实材料不落测试报告。 ## 3. Push 与来源门禁 @@ -44,7 +45,7 @@ ## 7. B2 隔离灰度(独立 flag 授权) -- [ ] 用 expectedVersion 把 flag 更新为 `force_on + department_allowlist + 隔离部门`;受控容器内只读诊断确认隔离部门 reason=`flag_force_on_department_allowed`、名单外 reason=`department_not_allowed`,并与详情 DTO `invoiceGuardEnabled` 交叉核对。 +- [ ] 灰度前实时读取隔离部门成员,确认恰好只有 employee/manager/finance 三个 smoke、无真人;临时启用 finance smoke 后,用 expectedVersion 把 flag 更新为 `force_on + department_allowlist + 隔离部门`。受控容器内只读诊断确认隔离部门 reason=`flag_force_on_department_allowed`、名单外 reason=`department_not_allowed`,并与详情 DTO `invoiceGuardEnabled` 交叉核对。 - [ ] 合成验证 owner 普通提交成功。 - [ ] 合成验证两项无票补助不被阻断。 - [ ] 合成验证多票显式关联成功。 @@ -59,7 +60,7 @@ - [ ] 灰度七项全 PASS,成功合成单据已撤回并删除,失败草稿已删除;审计历史保留。 - [ ] 用户单独批准 global enable;用 expectedVersion 更新为 global force_on。 - [ ] 验证全局 effective on、reason=`flag_force_on_global`、owner 基线、非参与人只读、错误提示、runtime 指标和审计记录。 -- [ ] employee/manager/finance smoke 常驻隔离部门,确认部门仍无真人成员;不再执行迁回写入。 +- [ ] employee/manager/finance smoke 常驻隔离部门,确认成员集合仍只有三个 smoke且无真人;不再执行迁回写入,finance smoke 在窗口结束后立即 disabled。 ## 9. 四张真实单据退回与重提 diff --git a/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/prd.md b/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/prd.md index 50d371b2..717899c6 100644 --- a/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/prd.md +++ b/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/prd.md @@ -36,7 +36,8 @@ ### R2 验收身份与合成数据 - 不恢复已从用户表消失的旧 manager/finance smoke;新建角色纯净的 OA-only manager smoke(manager + employee)和 finance smoke(finance + employee),不绑定或重置真实员工身份。 -- 把已确认无成员的部门固定为常驻 smoke 部门;employee smoke 迁入后不再迁回,manager smoke 设置为其直属 manager,三类 smoke 身份留在该部门供后续隔离灰度复用。迁移前再次确认部门仍无真人成员。 +- 把已确认无成员的部门改名为“系统测试专用(勿分配员工)”并固定为常驻 smoke 部门;employee smoke 迁入后不再迁回,manager smoke 设置为其直属 manager,三类 smoke 身份留在该部门供后续隔离灰度复用。迁移前以及每次部门灰度开启前,都必须确认成员集合恰好只有这三个 smoke;部门名称只是防误用提示,不能替代成员集合校验。 +- finance smoke 持有完整 finance + employee 角色,包含付款和全量财务职责,因此只允许在单独获批的验收窗口内启用。窗口结束后立即置为 disabled;后续再次启用、使用和停用都属于生产账号写入,不得从既往验收授权推定。 - 普通 employee 缺直属 manager 时,报销提交会因 `blockOnUnresolvedAssignee=true` 和 `no_manager_found` 返回 409;`owner_self_fallback_role=finance` 只处理 owner 本人持有 CEO 角色的特殊情形,不得把 finance fallback 当作普通 smoke 的兜底方案。 - 合成草稿、明细、票据和附件必须使用明显测试标识与非真实材料;不得复制真人票据、金额、说明或附件。 - 所有成功提交的合成单据在验证后按合法 owner 流程撤回并删除;失败场景草稿直接删除。审计/工作流历史按系统合同保留,不做数据库硬删。 @@ -54,6 +55,7 @@ - B1 验收通过后,先确认 DB 为 `force_off`,再经单独生产配置批准把 `REIMBURSEMENT_INVOICE_GUARD_ENABLED=true` 写入受控生产 env,并重启同一候选。重启后应显示 env enabled 但 effective off。 - 隔离灰度只能将 DB flag 设置为 `force_on + department_allowlist + 隔离部门 ID`;不得使用 employee smoke 原部门,不得把 4 张真人单据作为灰度样本。 +- 更新部门 allowlist 前必须重新读取部门成员与状态,确认只有 employee/manager/finance 三个 smoke、无真人成员,且 finance smoke 仅在当前获批窗口临时启用;任何额外成员或身份不确定都阻断灰度。 - 每个状态必须记录精确 reason:env 未开为 `env_hard_off`;env on + DB off 为 `flag_force_off`;灰度名单外部门为 `department_not_allowed`;隔离部门在本轮 `force_on` 模式下为 `flag_force_on_department_allowed`;全局开启为 `flag_force_on_global`。不得只凭提交成功/失败推断门禁已运行。 - 普通 feature flag 列表使用 `strictDepartment=false`,在部门 allowlist 状态只能给出延后判断,不能证明具体 actor 命中。灰度证据必须运行受控容器内只读 actor/department 诊断,并与报销详情 DTO 的 `invoiceGuardEnabled` 交叉验证;诊断不输出部门 ID、账号或原始 payload。 - 隔离灰度必须验证:owner 普通提交成功;两项无票补助不被阻断;多票显式关联成功;超票面准确阻断;旧草稿补齐后可提交;非参与人零写入副作用;切回 `force_off` 后旧提交路径恢复且既有关联数据不删除、不解绑。 @@ -77,7 +79,7 @@ ## Acceptance Criteria -- [ ] 常驻 smoke 部门、专用 manager/finance smoke、employee smoke 迁入和直属 manager 关系经单独生产写入批准;准备完成后不涉及任何真实员工身份或材料。 +- [ ] 常驻部门已改名为“系统测试专用(勿分配员工)”;专用 manager/finance smoke、employee smoke 迁入和直属 manager 关系经单独生产写入批准,成员集合只有三个 smoke且不涉及任何真实员工身份或材料。 - [ ] 最终候选冻结、单独 push、upstream 祖先关系和严格 provenance 全部通过。 - [ ] 用户在 provenance 通过后另行批准 B1 生产部署;pre/post migration status 均明确记录,唯一 migration 正确应用。 - [ ] B1 schema、费用主数据、requires_invoice、assets 批准依据、2,000 元提示和 account code 保留检查通过;B2 DB 记录明确存在且为 force_off,effective off reason 不是 missing record。 @@ -85,7 +87,7 @@ - [ ] owner 合成草稿维护正常;finance/admin 非参与人无维护入口;材料合并预览成功并只产生获批的设计内审计。 - [ ] env hard gate 在 DB `force_off` 状态下单独启用并重启,确认 env on / effective off 后才进入隔离灰度。 - [ ] B2 隔离灰度七项合同全部通过;失败时 DB 快照恢复,既有关联数据未回滚。 -- [ ] 用户单独批准后 B2 全局 effective on;合成数据已按合法流程清理,employee/manager/finance smoke 常驻隔离部门且无真人混入。 +- [ ] 用户单独批准后 B2 全局 effective on;合成数据已按合法流程清理,employee/manager/finance smoke 常驻隔离部门且无真人混入,finance smoke 已在验收窗口结束后 disabled。 - [ ] 真实财务按明确说明退回 0014/0016/0017/0018,重提后人工复核日期粒度;0008 与 0013 未被误改。 - [ ] 任一失败按固定回滚/补偿边界处理,无 reset、无逆 migration、无批量伪造批准依据或票据关联。 - [ ] 所有公网门禁完成前不通知普通用户测试、不归档父任务。 diff --git a/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/task.json b/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/task.json index d48fa86c..9430b235 100644 --- a/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/task.json +++ b/.trellis/tasks/08-30-reimbursement-expense-policy-invoice-guard-deploy/task.json @@ -28,6 +28,6 @@ "server/src/services/featureFlags/index.js", "server/src/routes/reimbursements.js" ], - "notes": "规划阶段;不执行 push、生产账号/部门/合成数据写入、migration、部署、env 配置、feature flag 更新或真实单据退回。固定应用回滚基线为 59dc5f6。B2 不校验日期粒度,0014 必须依赖退回说明和财务人工复核。employee/manager/finance smoke 终态常驻隔离部门;普通 employee 无直属 manager 时 workflow 会以 no_manager_found 阻断。B2 DB 记录必须显式存在为 force_off,灰度必须记录 actor 级精确 reason。", + "notes": "规划阶段;不执行未单独授权的 push、生产账号/部门/合成数据写入、migration、部署、env 配置、feature flag 更新或真实单据退回。固定应用回滚基线为 59dc5f6。B2 不校验日期粒度,0014 必须依赖退回说明和财务人工复核。employee/manager/finance smoke 终态常驻‘系统测试专用(勿分配员工)’部门;每次灰度前成员集合必须恰好为三个 smoke。finance smoke 含付款能力,仅在获批验收窗口临时 active,窗口外 disabled。普通 employee 无直属 manager 时 workflow 会以 no_manager_found 阻断。B2 DB 记录必须显式存在为 force_off,灰度必须记录 actor 级精确 reason。", "meta": {} -} \ No newline at end of file +}