R33-1 R33-3: 收口采购资产差旅事务超时

这个提交包含在:
2026-03-24 20:27:11 +08:00
父节点 1056c81940
当前提交 48f3909be3
共修改 8 个文件,包含 432 行新增和 147 行删除
@@ -0,0 +1,6 @@
ID,Title,Description,Acceptance,Test_Method,Tools,Dev_Status,Review1_Status,Regression_Status,Files,Dependencies,Notes
R33-1-0,新执行合同建档与范围锁定,基于 R32 后 full-local 暴露的 procurement submit P2028 超时问题建立单独热补合同并锁定只修采购提交链路,新 CSV 校验通过 且 Notes 写明本轮只修采购 submit 不扩散到报销/差旅 submit,python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-24_12-37-48-r33-1-procurement-submit-timeout-hotfix.csv,manual,DONE,TODO,DONE,issues/2026-03-24_12-37-48-r33-1-procurement-submit-timeout-hotfix.csv,[],"R32 作为历史快照不回写;已完成 CSV 建档与校验;本轮不调整 Prisma transaction timeout,仅通过缩事务收口。"
R33-1-1,采购提交事务边界收紧,把 purchase submit 的主状态变更与通知副作用拆成事务内外两段以消除 P2028 超时,submit 路由仍返回原有 purchaseRequestId requestNo workflowInstanceId currentTaskId budgetPoolId warnings budgetReservation 且通知 IM email 任一失败不影响 200 返回,cd server && node --check src/routes/purchaseRequests.js,manual,DONE,TODO,DONE,server/src/routes/purchaseRequests.js|server/src/services/notifications/*,"[""R33-1-0""]","已把 recipients/createNotifications/enqueueIm/sendNotificationEmailSafe 移到事务外;另把 budget precheck 挪到事务外并把 submit 读模型缩成 PURCHASE_SUBMIT_SELECT;2026-03-24 13:11 与 13:31 `cd server && node --check src/routes/purchaseRequests.js` 通过;/tmp/hyb-oa-web-gates-server.log 不再出现 purchase submit P2028。"
R33-1-2,采购提交副作用 helper 与单测,提取采购提交成功后的事务外副作用 helper 并补 route 级单测证明其失败不会阻断业务提交,新增 __testables helper 且单测覆盖 resolveRecipients 或 enqueueImNotifications 失败时 helper 只记日志不抛致命错误,cd server && npm test -- tests/unit/routes/purchase.submit-side-effects.test.js,manual,DONE,TODO,DONE,server/src/routes/purchaseRequests.js|server/tests/unit/routes/purchase.submit-side-effects.test.js,"[""R33-1-1""]","新增 __testables.finalizePurchaseSubmitSideEffects;2026-03-24 12:52 与 13:11 `cd server && npm test -- tests/unit/routes/purchase.submit-side-effects.test.js` 通过(2 tests passed)。"
R33-1-3,采购 E2E 失败可读性补强,改善 procurement-flow 在 submit 非 200 时的报错可读性避免 currentTaskId 空值误报,submitResponse 在解析 data 前先断言 ok 非 200 时输出响应体文本并保持原有业务主链路不拆分,cd client && npm run test:e2e -- tests/e2e/procurement-flow.spec.ts,manual,DONE,TODO,DONE,client/tests/e2e/procurement-flow.spec.ts,"[""R33-1-1""]","已补 submitResponse.ok() 失败时带响应体报错;在 `PurchaseRequestsPage.tsx` 额外修复 archiveOrderQuery 覆盖归档输入的竞态;2026-03-24 13:37 于临时环境复跑 `cd client && npm run test:e2e -- tests/e2e/procurement-flow.spec.ts` 通过(1 passed)。"
R33-1-4,恢复 procurement 与 full-local 绿灯,验证 procurement submit 不再触发 P2028 并恢复整套本地门禁,procurement-flow 通过 且 bash scripts/qa/run-web-gates.sh full-local 通过且日志中不再出现 purchase submit P2028,cd client && npm run test:e2e -- tests/e2e/procurement-flow.spec.ts && bash scripts/qa/run-web-gates.sh full-local,manual,DONE,DONE,DONE,server/src/routes/purchaseRequests.js|client/tests/e2e/procurement-flow.spec.ts|scripts/qa/run-web-gates.sh,"[""R33-1-2"",""R33-1-3""]","2026-03-24 13:31 full-local:procurement regression 通过,但 Playwright 仍有 procurement archive 输入竞态与 mobile-approvals-offline 失败;2026-03-24 13:46 full-local:procurement-flow 已恢复通过且 purchase submit P2028 清零,但整套门禁仍被范围外 `tests/e2e/main-flow.spec.ts` 的 OCR 状态断言阻塞,因此本项未置 DONE。2026-03-24 17:00 后已通过 R33-2 与 R33-3 继续收口范围外阻塞;同日 bash scripts/qa/run-web-gates.sh full-local 最终通过,结果为 26 passed / 3 skipped / 0 failed,且日志未再出现 purchase submit P2028,本项已完成收口。"
1 ID Title Description Acceptance Test_Method Tools Dev_Status Review1_Status Regression_Status Files Dependencies Notes
2 R33-1-0 新执行合同建档与范围锁定 基于 R32 后 full-local 暴露的 procurement submit P2028 超时问题建立单独热补合同并锁定只修采购提交链路 新 CSV 校验通过 且 Notes 写明本轮只修采购 submit 不扩散到报销/差旅 submit python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-24_12-37-48-r33-1-procurement-submit-timeout-hotfix.csv manual DONE TODO DONE issues/2026-03-24_12-37-48-r33-1-procurement-submit-timeout-hotfix.csv [] R32 作为历史快照不回写;已完成 CSV 建档与校验;本轮不调整 Prisma transaction timeout,仅通过缩事务收口。
3 R33-1-1 采购提交事务边界收紧 把 purchase submit 的主状态变更与通知副作用拆成事务内外两段以消除 P2028 超时 submit 路由仍返回原有 purchaseRequestId requestNo workflowInstanceId currentTaskId budgetPoolId warnings budgetReservation 且通知 IM email 任一失败不影响 200 返回 cd server && node --check src/routes/purchaseRequests.js manual DONE TODO DONE server/src/routes/purchaseRequests.js|server/src/services/notifications/* ["R33-1-0"] 已把 recipients/createNotifications/enqueueIm/sendNotificationEmailSafe 移到事务外;另把 budget precheck 挪到事务外并把 submit 读模型缩成 PURCHASE_SUBMIT_SELECT;2026-03-24 13:11 与 13:31 `cd server && node --check src/routes/purchaseRequests.js` 通过;/tmp/hyb-oa-web-gates-server.log 不再出现 purchase submit P2028。
4 R33-1-2 采购提交副作用 helper 与单测 提取采购提交成功后的事务外副作用 helper 并补 route 级单测证明其失败不会阻断业务提交 新增 __testables helper 且单测覆盖 resolveRecipients 或 enqueueImNotifications 失败时 helper 只记日志不抛致命错误 cd server && npm test -- tests/unit/routes/purchase.submit-side-effects.test.js manual DONE TODO DONE server/src/routes/purchaseRequests.js|server/tests/unit/routes/purchase.submit-side-effects.test.js ["R33-1-1"] 新增 __testables.finalizePurchaseSubmitSideEffects;2026-03-24 12:52 与 13:11 `cd server && npm test -- tests/unit/routes/purchase.submit-side-effects.test.js` 通过(2 tests passed)。
5 R33-1-3 采购 E2E 失败可读性补强 改善 procurement-flow 在 submit 非 200 时的报错可读性避免 currentTaskId 空值误报 submitResponse 在解析 data 前先断言 ok 非 200 时输出响应体文本并保持原有业务主链路不拆分 cd client && npm run test:e2e -- tests/e2e/procurement-flow.spec.ts manual DONE TODO DONE client/tests/e2e/procurement-flow.spec.ts ["R33-1-1"] 已补 submitResponse.ok() 失败时带响应体报错;在 `PurchaseRequestsPage.tsx` 额外修复 archiveOrderQuery 覆盖归档输入的竞态;2026-03-24 13:37 于临时环境复跑 `cd client && npm run test:e2e -- tests/e2e/procurement-flow.spec.ts` 通过(1 passed)。
6 R33-1-4 恢复 procurement 与 full-local 绿灯 验证 procurement submit 不再触发 P2028 并恢复整套本地门禁 procurement-flow 通过 且 bash scripts/qa/run-web-gates.sh full-local 通过且日志中不再出现 purchase submit P2028 cd client && npm run test:e2e -- tests/e2e/procurement-flow.spec.ts && bash scripts/qa/run-web-gates.sh full-local manual DONE DONE DONE server/src/routes/purchaseRequests.js|client/tests/e2e/procurement-flow.spec.ts|scripts/qa/run-web-gates.sh ["R33-1-2","R33-1-3"] 2026-03-24 13:31 full-local:procurement regression 通过,但 Playwright 仍有 procurement archive 输入竞态与 mobile-approvals-offline 失败;2026-03-24 13:46 full-local:procurement-flow 已恢复通过且 purchase submit P2028 清零,但整套门禁仍被范围外 `tests/e2e/main-flow.spec.ts` 的 OCR 状态断言阻塞,因此本项未置 DONE。2026-03-24 17:00 后已通过 R33-2 与 R33-3 继续收口范围外阻塞;同日 bash scripts/qa/run-web-gates.sh full-local 最终通过,结果为 26 passed / 3 skipped / 0 failed,且日志未再出现 purchase submit P2028,本项已完成收口。
@@ -0,0 +1,6 @@
ID,Title,Description,Acceptance,Test_Method,Tools,Dev_Status,Review1_Status,Regression_Status,Files,Dependencies,Notes
R33-3-0,新执行合同建档与范围锁定,基于 R33-2 后 full-local 暴露的 assets create purchase submit travel create 三条事务尾部超时问题建立单独热补合同并锁定只修这三条链路,新 CSV 校验通过 且 Notes 写明本轮只收口事务尾部超时不扩散到其他业务域,python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-24_17-00-26-r33-3-transaction-timeout-tail-cleanup.csv,manual,DONE,DONE,DONE,issues/2026-03-24_17-00-26-r33-3-transaction-timeout-tail-cleanup.csv,[],"R33-2 作为历史快照不回写;本轮不调整 Prisma transaction timeout,仅通过缩事务与审计后移收口。2026-03-24 已完成 R33-3 CSV 建档并校验通过。"
R33-3-1,资产建卡事务尾部收口,把 POST /api/assets 中无原子性要求的 audit log 移到事务提交后执行以消除资产建卡 P2028,事务内仅保留 assetCard.create 与条件 assetAssignment.create 且资产创建响应结构不变 审计失败只记日志不影响成功返回,cd server && node --check src/routes/assets.js,manual,DONE,DONE,DONE,server/src/routes/assets.js,"[""R33-3-0""]","不新增事务外副作用;只把 ASSET_CARD_CREATED 审计改为 best-effort。2026-03-24 `cd server && node --check src/routes/assets.js` 通过;同日 full-local 中 assets regression 与 `tests/e2e/assets-flow.spec.ts` 通过,server log 未再出现 asset create 对应 P2028。"
R33-3-2,采购 submit 二次收口,把 purchase submit 中 PURCHASE_REQUEST_SUBMITTED 审计移到事务后执行并保留现有事务外通知 helper,submit 路由返回字段保持 purchaseRequestId requestNo workflowInstanceId currentTaskId budgetPoolId warnings budgetReservation 不变 且审计失败只记日志不影响 200 返回,cd server && node --check src/routes/purchaseRequests.js,manual,DONE,DONE,DONE,server/src/routes/purchaseRequests.js|server/src/services/notifications/*,"[""R33-3-0""]","第一阶段只移审计;若 full-local 仍仅在 purchase submit 报 P2028,允许在同合同内把 resolveActionableStep 纯读解析前置到事务外,不改审批规则与错误语义。2026-03-24 `cd server && node --check src/routes/purchaseRequests.js` 通过;同日 full-local 中 procurement regression 与 `tests/e2e/procurement-flow.spec.ts` 通过,采购 fallback 未触发且 server log 未再出现 purchase submit P2028。"
R33-3-3,差旅建单事务尾部收口,把 POST /api/travel-requests 的 financial dimensions 只读校验前置并将创建审计移到事务后执行,事务内仅保留 travelRequest.create 与 nested segments 写入 且创建成功返回结构与前端 URL 契约不变 审计失败只记日志不影响成功返回,cd server && node --check src/routes/travelRequests.js,manual,DONE,DONE,DONE,server/src/routes/travelRequests.js,"[""R33-3-0""]","只修 create 路由,不动 submit pay reconciliation;ensureFinancialDimensions 前置到事务外。2026-03-24 `cd server && node --check src/routes/travelRequests.js` 通过;同日 full-local 中 `tests/e2e/travel-payment-flow.spec.ts` 通过,server log 未再出现 travel create 对应 P2028。"
R33-3-4,定向回归与 full-local 全绿验收,验证 assets procurement travel 三条链路不再触发事务尾部 P2028 并恢复整套本地门禁,assets-flow procurement-flow travel-payment-flow 通过 且 bash scripts/qa/run-web-gates.sh full-local 通过并且日志中不再出现这三条链路对应的 P2028,cd client && npm run typecheck && cd client && npm run test:e2e -- tests/e2e/assets-flow.spec.ts tests/e2e/procurement-flow.spec.ts tests/e2e/travel-payment-flow.spec.ts && bash scripts/qa/run-web-gates.sh full-local,manual,DONE,DONE,DONE,server/src/routes/assets.js|server/src/routes/purchaseRequests.js|server/src/routes/travelRequests.js|client/tests/e2e/assets-flow.spec.ts|client/tests/e2e/procurement-flow.spec.ts|client/tests/e2e/travel-payment-flow.spec.ts|scripts/qa/run-web-gates.sh,"[""R33-3-1"",""R33-3-2"",""R33-3-3""]","定向 E2E 直接运行时因本地未起 server 返回 ECONNREFUSED,已改用项目标准门禁编排验证。2026-03-24 `cd client && npm run typecheck` 通过;同日 `bash scripts/qa/run-web-gates.sh full-local` 通过,结果为 26 passed / 3 skipped / 0 failed,且日志未再出现 assets create purchase submit travel create 对应 P2028。"
1 ID Title Description Acceptance Test_Method Tools Dev_Status Review1_Status Regression_Status Files Dependencies Notes
2 R33-3-0 新执行合同建档与范围锁定 基于 R33-2 后 full-local 暴露的 assets create purchase submit travel create 三条事务尾部超时问题建立单独热补合同并锁定只修这三条链路 新 CSV 校验通过 且 Notes 写明本轮只收口事务尾部超时不扩散到其他业务域 python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-24_17-00-26-r33-3-transaction-timeout-tail-cleanup.csv manual DONE DONE DONE issues/2026-03-24_17-00-26-r33-3-transaction-timeout-tail-cleanup.csv [] R33-2 作为历史快照不回写;本轮不调整 Prisma transaction timeout,仅通过缩事务与审计后移收口。2026-03-24 已完成 R33-3 CSV 建档并校验通过。
3 R33-3-1 资产建卡事务尾部收口 把 POST /api/assets 中无原子性要求的 audit log 移到事务提交后执行以消除资产建卡 P2028 事务内仅保留 assetCard.create 与条件 assetAssignment.create 且资产创建响应结构不变 审计失败只记日志不影响成功返回 cd server && node --check src/routes/assets.js manual DONE DONE DONE server/src/routes/assets.js ["R33-3-0"] 不新增事务外副作用;只把 ASSET_CARD_CREATED 审计改为 best-effort。2026-03-24 `cd server && node --check src/routes/assets.js` 通过;同日 full-local 中 assets regression 与 `tests/e2e/assets-flow.spec.ts` 通过,server log 未再出现 asset create 对应 P2028。
4 R33-3-2 采购 submit 二次收口 把 purchase submit 中 PURCHASE_REQUEST_SUBMITTED 审计移到事务后执行并保留现有事务外通知 helper submit 路由返回字段保持 purchaseRequestId requestNo workflowInstanceId currentTaskId budgetPoolId warnings budgetReservation 不变 且审计失败只记日志不影响 200 返回 cd server && node --check src/routes/purchaseRequests.js manual DONE DONE DONE server/src/routes/purchaseRequests.js|server/src/services/notifications/* ["R33-3-0"] 第一阶段只移审计;若 full-local 仍仅在 purchase submit 报 P2028,允许在同合同内把 resolveActionableStep 纯读解析前置到事务外,不改审批规则与错误语义。2026-03-24 `cd server && node --check src/routes/purchaseRequests.js` 通过;同日 full-local 中 procurement regression 与 `tests/e2e/procurement-flow.spec.ts` 通过,采购 fallback 未触发且 server log 未再出现 purchase submit P2028。
5 R33-3-3 差旅建单事务尾部收口 把 POST /api/travel-requests 的 financial dimensions 只读校验前置并将创建审计移到事务后执行 事务内仅保留 travelRequest.create 与 nested segments 写入 且创建成功返回结构与前端 URL 契约不变 审计失败只记日志不影响成功返回 cd server && node --check src/routes/travelRequests.js manual DONE DONE DONE server/src/routes/travelRequests.js ["R33-3-0"] 只修 create 路由,不动 submit pay reconciliation;ensureFinancialDimensions 前置到事务外。2026-03-24 `cd server && node --check src/routes/travelRequests.js` 通过;同日 full-local 中 `tests/e2e/travel-payment-flow.spec.ts` 通过,server log 未再出现 travel create 对应 P2028。
6 R33-3-4 定向回归与 full-local 全绿验收 验证 assets procurement travel 三条链路不再触发事务尾部 P2028 并恢复整套本地门禁 assets-flow procurement-flow travel-payment-flow 通过 且 bash scripts/qa/run-web-gates.sh full-local 通过并且日志中不再出现这三条链路对应的 P2028 cd client && npm run typecheck && cd client && npm run test:e2e -- tests/e2e/assets-flow.spec.ts tests/e2e/procurement-flow.spec.ts tests/e2e/travel-payment-flow.spec.ts && bash scripts/qa/run-web-gates.sh full-local manual DONE DONE DONE server/src/routes/assets.js|server/src/routes/purchaseRequests.js|server/src/routes/travelRequests.js|client/tests/e2e/assets-flow.spec.ts|client/tests/e2e/procurement-flow.spec.ts|client/tests/e2e/travel-payment-flow.spec.ts|scripts/qa/run-web-gates.sh ["R33-3-1","R33-3-2","R33-3-3"] 定向 E2E 直接运行时因本地未起 server 返回 ECONNREFUSED,已改用项目标准门禁编排验证。2026-03-24 `cd client && npm run typecheck` 通过;同日 `bash scripts/qa/run-web-gates.sh full-local` 通过,结果为 26 passed / 3 skipped / 0 failed,且日志未再出现 assets create purchase submit travel create 对应 P2028。