- 已完成 P1–P4、P6–P10,实现 1f8d5b65/合并46a70aa5包含于生产4a5cd8f2- P5 旧 WebKit 派生 registry 保护余项转由 09-08-reimbursement-payment-closeout 跟进 - 仅 P9 经补审,全量独立复核未做,不补记为通过;原清单保留 Co-Authored-By: Claude Opus 5.5 <[email protected]>
11 KiB
2026-09-19 P10采购保存事务最小续修(沿用G20在用缺陷授权)
g20-full-r5完整372项为367通过/1失败/2超时/2串行未执行;环境和source/repository/owner清理PASS。采购唯一失败在PATCH保存草稿,原5000ms事务耗至6529ms、HTTP500,尚未进入precheck/submit或取号。已核运行日志归属(runner PID、namespace、入口、cwd、fd),只保留安全状态与耗时。日志未足以唯一归因数据库或调度耗时。
PATCH目前在FOR UPDATE后的写事务末尾读取PURCHASE_DETAIL_SELECT,包含多级关系,仅用于响应,不参与业务判定。复用已批准采购创建与资产响应读取边界:事务内原校验、两次父更新顺序、明细替换/金额计算、审计完全保留;await事务提交后,由同一服务器Prisma读取原详情select并按原mapper响应。保持原5000ms、无重试、权限和数据原子性;不合并更新、不重算编号、不移动一致性校验。
新增确定性边界回归:有明细/无明细PATCH完整响应和字段、只在提交后读取;父写入/明细/审计/commit失败均不读详情不成功;提交后详情失败返回错误但不宣称回滚、不自动再写。mock只证明调用边界,实际采购提单→审批→归档由原整例证明。先原实现红例,再最小源码绿例与采购相关文件,最后交09-06做四文件原并发定向及新完整候选。
此为在用缺陷最小优化,不新增业务规则或改变验收。独立review继续PENDING,不提交、部署或访问真实数据。
最小修复设计
2026-09-18 P9诊断与实施约束
诊断结果与最小方案定稿
p9-diagnostic-r2原R75四项全过,整个选择10项9过/1视觉超时,513.621秒,环境/输入/owner清理PASS。两次已编号提交26个Prisma操作,事务646.077/244.180ms;原5秒失败未在本轮复现。PG采样未见Lock,存在idle-in-transaction/Client等待;事件循环/池等待峰值属于整轮观察,不宣称都是提交原因。首轮仅因选择器用逗号在测试前拒绝,清理PASS且不计业务用例。
实施范围限定为已证明的重复开销:resolveEntityPrecheck在报销分支一次读取所需实体/排序明细/费用分类字段,内部私有计算函数共享这次服务器读取;费用标准、预算/审批规则、财务本人审批、票据/附件、时效等校验全部保留。原公开helper仍自己读取,不接受请求传入的快照,不引入跨请求缓存,也不把本次对象读取声称为整库RepeatableRead。采购/差旅分支不变。普通预算开关关闭路径的3次实体读取变为1次,开启路径4次变为1次。
提交路由保留原aggregate权威重算及写入顺序,不为微小收益改金额来源;旅行分类直接使用已在同一FOR UPDATE事务读取的明细分类,已关联差旅仍强制结构字段。绑定票据count仅在旧门禁关闭且存在需票明细时查询;开启逐项门禁仍执行原完整校验。状态、权限、锁、预算及审批历史/审计同事务、原5000ms均保持。
先添加确定性回归证明重复读取及无条件查询开销;覆盖两种预算开关、费用标准阻断、财务本人无CEO、真实实体缺失、跨调用重新读取和非报销旧分支,以及逐项票据/旧缺票/旅行字段边界。修复后跑相关unit与无预载原R75和付款链,最后仍须新完整负载通过;专项优化通过不声称已彻底排除原P2028。
用户已同意按六组后续清单推进。原失败为已编号报销提交的5000ms事务在5412ms后workflowHistory.create报P2028;旧号存在时不调用issueDocumentNumber,因此不能仅因时点关联归因新编号。先在本轮独占无网络合成环境运行原R75整文件,并与全页面阶段计时同轮观察。诊断仅从ignored预载记录Prisma模型/方法耗时与序号、事务耗时、事件循环和池等待;不输出参数、SQL正文、结果、凭据或原始异常。PG只读取聚合state/wait类别与事务年龄;校验本轮容器owner/namespace/目录绑定。预载不改变业务参数/返回值/错误或预算,正式验收移除预载。
已识别待核实的重复读取包括提交明细后再次aggregate、旅行分类查询和无条件绑定票据count,以及预检再次读取实体/审批信息。它们只是候选,不能把代码重复当作唯一耗时根因。最小方案须在诊断后具体定稿,涉及一致性的读不能移到事务外;确定性回归先证明旧实现的问题,修复后再原合成链验证。不得通过禁用预检、缩审批、增加事务超时或回退编号求绿。
证据
两轮分别采购P2028:5000ms预算、5952/6839ms后过期。诊断轮729次PG采样无Lock等待;失败窗口持续idle in transaction/Client,事件循环满载且池曾排队。此证据支持减少无关事务存续时间,不足以声称已定位全仓CPU根因;不改bcrypt/连接池大小或全局预算。
PWA诊断:B文档仍A,B预缓存首页与68个独有资源存在,controller=active且activated、no-store worker摘要匹配B,零页面/分块异常。native updatefound早于后一次sw.js请求记录(未直接采集register Promise完成时点);源码确认现workbox-window在await register后才订阅updatefound,且不补订阅已installing worker;autoUpdate只靠activated刷新,故可能漏事件。framenavigated含SPA同文档跳转,导航计数不等于重载次数。旧失败日志占位已纠正为实际快照/null,不能用占位推因。
PWA
client/src/pwa.ts改为原生注册生命周期,先捕获controller并同步订阅controllerchange,再调用register。控制器切换后等待该worker activated,重复事件合并;首次接管只发原offline-ready,不刷新。已受控→新worker的更新:普通页清运行时缓存并刷新一次,认证输入页只发既有事件并交用户触发。同页失效worker不刷新。
vite.config.ts明确injectRegister:false,避免插件自动插入第二个注册/重载所有者;保留generateSW、skipWaiting、clientsClaim、缓存与manifest。不引入新UI/依赖,不改前台版本检测合同。显式登出/人工刷新保留既有全缓存清理;自动更新只清app-api-runtime/app-static-runtime。
本修复覆盖装载本次生命周期代码的浏览器;已运行旧代码的部署客户端无法被新页面代码追溯改写,首次发布仍按既有手册人工刷新并验证,不宣称旧版本历史代码全覆盖。
采购
创建事务select只含id/applicant_id/department_id,沿原extra写审计,返回id;提交后findUnique使用原PURCHASE_DETAIL_SELECT,再按原mapper响应。保留全部前置与原子性;响应读取失败仍按现有错误处理,不将已提交写入虚报回滚,也不新增自动重试。详情响应是提交后的当前状态,符合列表/详情同一读取合同。
验证与边界
产品测试先红后绿;生命周期用可控合成ServiceWorker事件验证顺序,真实A/B整例证明浏览器实际行为;采购路由模拟测试检查提交顺序/审计失败,真实PG采购整链证明成功下游。不带观察器的四文件并发作最终本地证据;全量、WebKit、独立/真实业务仍由协调task保留。主会话可检查事务/生命周期,但不能冒充独立review。
2026-09-18 G20 完整负载续修设计(已收齐并核清理)
来源:g20-full-r4 的资产创建与账号创建两个在用接口均出现原5000ms事务预算过期;资产5983ms,账号6004ms。观察器仅消费归属已核的本轮合成服务日志,无SQL或锁归因,不能声称唯一原因或全仓性能问题已解决。
资产创建
所有分类/主体/成本中心/人员/采购可用性校验、单号分配、资产写入、可选领用写入仍在原事务中。assetCard.create只返回原领用和审计所需标量;事务提交后按原ASSET_CARD_SELECT读取完整响应。原ASSET_CARD_CREATED审计仍在提交后发起并单独捕获失败,不挪入事务、不等待成功、不删除字段。详情读取失败不得重试创建或称写入已回滚;缺失沿现有asset.not_found合同。提交后详情是当前状态,不承诺和写入瞬间的关系快照一致。
单个账号创建
在现有权限、输入、受保护角色、部门/主管校验之后,使用相同hashPassword/真实cost12完成哈希,再进入事务。账号、角色与SYSTEM_USER_CREATED审计仍一起提交;P2002、一次性口令/强制改密、角色回读和提交后企微目录同步语义保持。createSystemUser内部只消费由服务器生成的passwordHash,不能从请求接收哈希。批量导入在既有事务/循环位置计算哈希,不扩改导入事务;不调整加密成本、连接池、事务预算或重试。
验证
先加入8项资产边界和5项账号边界回归,原实现运行取得真实红灯,再实施并运行相同测试及相关资产操作/搜索/校验、账号写入/角色保护/导入回归。Mock事务不冒充PG故障回滚;真实整链在受管合成PG上按原并发、预算、零重试验证,最后新完整候选从static开始。原失败、旧差异与冻结包保留,独立review仍PENDING。
不实施考勤重建,不改业务权限/审批状态机,不作线上写入。用户已另行授权的指定付款批次只读查询是单独证据,不影响本地环境归属或取得部署资格。
Bug Analysis: 采购保存事务与完整负载
1. Root Cause Category
- E 隐含假设:把多级响应关系读取放入5秒业务写事务,假定负载下仍有充足时间;PATCH已实测P2028,具体数据库/调度比例未知。
- D 覆盖缺口:创建路径的定向通过不能证明保存路径和完整负载。此次原实现确定性边界红4项,修改后新增9项与原采购回归共167项通过。
2. Why Fixes Failed
此前创建、资产、账号与报销修复各自只覆盖已批准入口;采购PATCH仍保留独立的响应关系读取。7组视觉独立运行通过也未证明15页管理员组在全负载可于180秒完成。不得据这些局部结果关闭完整门禁。
3. Prevention Mechanisms
| 优先级 | 机制 | 状态 |
|---|---|---|
| P0 | 非判定用途的响应详情提交后读取,锁/一致性校验/写入审计保留事务 | PATCH已实施;167项通过 |
| P0 | 漏项/失败组拒绝及完整同候选运行 | 已捕获视觉缺页并拒绝;新完整待验 |
| P1 | omitted/empty/items及write/items/audit/commit/read边界 | 新9项通过;mock不冒充PG故障注入 |
4. Systematic Expansion
已只读检查采购邻近入口:submit/withdraw沿用各自业务事务与返回边界;archive小投影含审计所需字段,不能按关键词机械外移。当前仅修改已观察失败的PATCH,不把推测扩成全仓重构。当前未建立全负载耗时的唯一根因;修复仍须原整例和完整候选。
5. Knowledge Capture
- backend-fastify-prisma的采购事务节补PATCH、不变量、失败与当前已提交状态语义。
- 当前task design/implement记录边界与分轮证据。
- 模板同步不适用:业务仓库无对应打包模板树。用户明确不提交,未执行skill中默认commit步骤。