归档本地并发问题修复任务并补收口记录(09-18-local-concurrency-product-fixes)
- 已完成 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]>
这个提交包含在:
@@ -0,0 +1 @@
|
||||
{"file": ".trellis/spec/hyb-oa/deployment-trialrun.md", "reason": "受管本地验证与真实发布区分"}
|
||||
@@ -0,0 +1,91 @@
|
||||
## 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
|
||||
- [x] backend-fastify-prisma的采购事务节补PATCH、不变量、失败与当前已提交状态语义。
|
||||
- [x] 当前task design/implement记录边界与分轮证据。
|
||||
- 模板同步不适用:业务仓库无对应打包模板树。用户明确不提交,未执行skill中默认commit步骤。
|
||||
@@ -0,0 +1,2 @@
|
||||
{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "PWA升级与认证输入保护"}
|
||||
{"file": ".trellis/spec/hyb-oa/backend-fastify-prisma.md", "reason": "事务审计和现有采购合同"}
|
||||
@@ -0,0 +1,106 @@
|
||||
## 2026-09-19 P9 定向补审接收与旧预算缺陷分流
|
||||
|
||||
Claude 补审 b1rubx7qf 已完成,原报告 `artifacts/qa-governance/business-followup-claude-review-20260919T023537Z.txt`。P9 三个纯函数共享一次实体读取且无跨请求缓存的结论 PASS;已审报销锁序、金额重算后同事务 precheck 为 PASS。reviewer 未逐行审全部路由分支/工作流 snapshot 内部,不扩为本任务全量独立 PASS。
|
||||
|
||||
预算池 used_amount 的无锁读改写确认为遗留并发缺陷,三模块共四处计数片段与 HEAD 一致;两 service 的周边错误码有既存差异,不声称整文件一致。按用户要求单列 `.trellis/tasks/09-19-budget-pool-concurrency/`,统一处理计数与锁后超额判定;目前只规划,未实施。P9 性能目标已通过与这个遗留缺陷待修分别记录,旧 r6/测试结果保留,发布资格仍 false。总体接回状态与未覆盖范围由 09-06 当前入口协调。
|
||||
|
||||
## 2026-09-19 P6–P10本地验收完成
|
||||
|
||||
g20-full-r6从static完成同一冻结候选:后端224文件4437通过/1原条件跳过、372本地浏览器全部通过,零失败/跳过/重试。资产、采购、PWA更新、R75四项和报销付款整链通过,P6/P7/P9/P10边界与原整链、P8完整负载验收完成。P10的原实现4红、修后167/167仍保留;写事务及响应读取语义不变更。
|
||||
|
||||
采购整例125.161秒;付款helper步骤264.491秒、Playwright总记录373.383秒,原300秒设置未改,前后开销差额没有独立拆分。完整来源、计时与证据统一见09-06 implement顶部。PARTIAL仅dirty_candidate,独立PENDING、无部署。
|
||||
|
||||
P5包含旧材料保护合取条件,因旧WebKit派生registry一处已披露改写而保持开放;原baseline不改,r6无新增漂移,其余12137旧文件与HEAD/index不变。不得将代码验证通过写成保护或独立复核通过。本次结束后仅补task记录,整体in_progress,不提交推送部署/归档。
|
||||
|
||||
## 2026-09-19 四文件定向通过,接完整候选r6(当前入口)
|
||||
|
||||
r5-fixed-r2四完整文件31/31通过,浏览器约5.5分钟、受管总571.747秒,零跳过/重试;采购整链、R75四项、付款提交至归档全链及视觉25项通过。付款约244.773秒,保持300秒;视觉7组各180秒、25PC+8手机/33PNG全部完成、覆盖问题与findings为空。环境/source/repository/owner清理PASS。原r5完整FAIL与r5-fixed-r1登录跳转失败均保留,不拼接为完整通过。
|
||||
|
||||
P10采购提交后读取边界167/167及QA专用类型已通过;登录仅在无query/hash的规范/login复用,保留原表单/portal/profile断言。下一g20-full-r6从static开始普通完整候选,全部源码/测试/task/spec/docs冻结,只写本轮ignored证据;N5/G20及产品完整负载验收仍待终态,独立PENDING、生产编号未启用。
|
||||
|
||||
旧WebKit派生registry保护异常保留,原baseline不改;后续运行使用本轮独立WebKit副本,不下载或安装。禁止将一处已知漂移描述为全部旧材料零变化;无提交推送部署或真实操作。
|
||||
|
||||
## 2026-09-19 当前入口:P10采购PATCH保存续修
|
||||
|
||||
P9的R75四项已在g20-full-r5完整负载通过,整体仍失败。新增采购PATCH P2028见design;原付款300秒/管理员视觉180秒累计超时由09-06接QA冗余前置优化。
|
||||
|
||||
- [x] P10a:证据/不变量定稿;原实现75项71通过、4边界红灯,失败记录保留。
|
||||
- [x] P10b:仅移出原响应select,新增9项边界;采购5文件167/167通过(11.68秒),源码语法/diff通过。
|
||||
- [ ] P10c:采购相关回归与原主链原预算验证,再接完整候选。
|
||||
|
||||
旧材料检查发现仅WebKit自动改写旧浏览器包GStreamer派生索引,原baseline不改,改写副本和FAIL留存;另建本轮独占缓存避免继续写旧目录,不能声称旧12138文件全不变。业务冻结材料、HEAD/index不变。独立PENDING。
|
||||
|
||||
## 2026-09-19 完整候选接续
|
||||
|
||||
grouped-visual-r1完整文件25/25通过(7真实组+13覆盖正反例+5原到达用例),浏览器91.788秒、受管总352.799秒;25PC+8移动全部审完,33PNG、findings为空、覆盖问题为空,环境/输入/owner清理PASS,零跳过/重试。P9/编号N5/G20仍待新完整负载验收;由官方current 09-06从static开始g20-full-r5,运行时全部受管输入冻结,独立PENDING。
|
||||
|
||||
## 2026-09-19 当前P9验证状态
|
||||
|
||||
完整后端224文件4428项通过、1原条件跳过,537.01秒,644输入文件/集合结束后SHA核验零变化。P9产品实现、确定性边界与无预载R75/付款链已通过,完整负载仍交09-06新候选验证,不能据此关闭P9/P8。7组视觉验收已获用户批准并实施,13覆盖正反例/专用类型通过,下一真实矩阵整文件定向后从static完整门禁;独立PENDING。
|
||||
|
||||
## 2026-09-18 新观察:报销提交事务(待定稿实施)
|
||||
|
||||
09-06的numbering-browser-closeout-20260918/browser-r2中,R75通知场景报销提交返回SYS_001;同一受管server日志定位P2028:原5000ms事务在5412ms后执行workflowHistory.create失败(reimbursements提交事务)。该轮64项58通过/4未过/2串行未执行,报销付款原整链另已通过。安全错误摘要在browser-r2-server-errors.json;未复制原payload,旧失败保留。
|
||||
|
||||
- [ ] P9a:重现并区分锁等待、事务内重复查询和同步计算;核对已编号创建提交不会进入缺号补号分支,不能只凭出现时点认定新编号导致,也不能据一个样本归因为机器慢。
|
||||
- [ ] P9b:在PRD/design定稿最小优化与不变量,再实施。保持FOR UPDATE、权限/所有权/状态、金额票据/预算、审批规则及workflow历史/审计的原子性;原5000ms、并发、零重试不调宽。事务内需要一致性的读不得无条件移到外部。
|
||||
- [ ] P9c:先有确定性边界回归,再做受影响unit与合成DB/HTTP;原R75通知及两个串行后继整文件验证,最后09-06从static完整新候选。定向通过不能代替完整门禁;独立review仍PENDING。
|
||||
|
||||
本轮先由09-06完成编号消费者/QA前置收口,没有改报销提交产品源码;P9为新增待办,不与之前资产/账号已通过结果混为完成。
|
||||
|
||||
## G20 产品续修单测已通过
|
||||
|
||||
两个接口最小修复已完成,原实现红灯7项/112通过,修复后两文件119/119通过(17.54秒);资产操作/搜索/校验与账号导入/敏感权限五文件148/148通过(23.71秒),受影响源码Node语法通过。合计267项包含13项新增边界,真实cost12未改;原事务预算、角色、审计语义与批量导入位置保持。下一步由09-06修QA前置及定向整例,再从static全量;P6/P7整体及P8仍待真实整例/全量,独立PENDING。
|
||||
|
||||
## 2026-09-18 G20 续修(已批准本地缺陷修复范围)
|
||||
|
||||
g20-full-r4已结束FAIL,5768.636秒:静态及完整内部前11阶段PASS,浏览器342通过/5失败/3超时/1串行后继未执行,零重试。环境PASS,source/repository未变,归属容器和scratch清理PASS。两个在用产品错误分别为资产创建P2028(5983/5000ms)、账号创建P2028(6004/5000ms),不归因于考勤/退役ERP。
|
||||
|
||||
先按更新PRD/design加入8项资产与5项账号边界回归并运行原实现取得红灯;再最小实现、相关回归及原资产/R75整文件验证。所有旧失败与冻结包保留,原超时/并发/零重试不变。证据release-receipt-g20-20260918,独立PENDING。
|
||||
|
||||
- [ ] P6:资产标量写入/提交后详情及原异步审计;先红后绿与资产相关回归。
|
||||
- [ ] P7:单个账号事务前cost12,原子写入/导入/权限合同回归。
|
||||
- [ ] P8:原整例和最新完整候选验收,协调09-06/09-08;不据定向绿结案。
|
||||
|
||||
治理收口:补齐本task标准Goal/Scope/Out of Scope/Acceptance/Test Plan章节与scope字段后,Trellis治理通过。3条大规约的自动注入截断告警保留;本轮inline按相关章节读取,独立审阅须按新增PWA/采购章节和原合同完整阅读,不依赖被截断上下文。
|
||||
|
||||
## 本地修复验证完成
|
||||
|
||||
131项Vitest、前端typecheck/production build、Prisma、浏览器专用类型通过;原四文件并发4/4,最终完整认证/门户与OCR18/18通过,环境/输入/清理PASS。PWA新资源实际加载与旧缓存清理共同成立;采购走完审批归档。原两轮失败与诊断不覆盖;不声明全仓CPU或完整负载已解决。
|
||||
|
||||
源码自检确认单一PWA注册所有者、先原生监听后异步register、首次/重复/失效/认证输入边界、更新保留precache、显式登出保留旧清理合同;采购权限/切换/默认字段/草稿审计原子性保持,详情只在提交后读取。模拟事务测试不冒充PG故障注入回滚证据。首次部署旧客户端仍需既有刷新验收。
|
||||
|
||||
最终治理与冻结见local-coverage-g18-20260918;独立只读review在inline限制下PENDING。产品本地实施完成,task仍in_progress,交由09-06/09-08协调后续完整门禁及发布边界;本轮无提交推送部署。
|
||||
|
||||
## 原并发整组通过,接最终共享入口回归
|
||||
|
||||
g18-concurrency-fixed-r3 583.240秒,原四文件4/4通过(浏览器约4.5分钟),4 workers/零重试/预算未变。观察器仅被动采本轮结构化日志,未加载r2预载诊断;995响应/0未处理异常。PWA B文档/active controller/worker摘要/68新缓存与2实际加载新资源,旧独有缓存0,零登录回落/静态404;采购已实际走完创建至审批/归档,而非只验证POST200。环境/source/repository/owner清理PASS。完整发现64文件363用例,无遗漏/未知/重复。
|
||||
|
||||
最后运行g18-final-ux-ocr-r4:完整login-portal-ux(16项)与invoice-ocr-flow(2项),验证共享PWA入口下认证输入/前台提示与本轮OCR产品修复保持;原预算/配置并发/零重试,不再改代码。此轮仍是本地定向,不能拼接旧full-r2为完整全绿。之后更新规约/09-06/09-08与最终治理/保护/增量冻结,独立PENDING。
|
||||
|
||||
## 第一轮定向结果
|
||||
|
||||
6文件131项Vitest通过,包括13项原生PWA生命周期及4项新增采购事务边界回归;采购提交/预算/附件/项目关联现有回归保持。浏览器专用类型与Prisma validate通过。产品前端typecheck正在完成;随后执行不带预载诊断的g18-concurrency-fixed-r3,原四文件4 workers/零重试/原预算。PWA加强新资源实测,只计performance已完成资源,并同时要求B缓存与实际B资源均存在,不用DOM标签或缓存替代真实加载。
|
||||
|
||||
# 执行记录
|
||||
|
||||
2026-09-18:依用户“按规划连续做、缺方案先更新”授权,先建立本task再编码。承接G18两条重复失败,证据在local-coverage-g18-20260918,旧包与两次失败不覆盖。范围与验收详见PRD/design,不扩权或加预算。
|
||||
|
||||
- [x] 实施PWA原生监听与单一注册所有者,回归首次/更新/认证页/失效/重复/显式清理。
|
||||
- [x] 最小采购写事务与提交后详情,路由审计原子性/顺序/响应回归。
|
||||
- [x] 不带观察器的四文件4-worker受管重验及受影响类型/build/Prisma。
|
||||
- [x] 只读自检、规约/协调状态、最终治理/保护;独立PENDING。新候选终态以本轮candidate-integrity.json为准。
|
||||
## 2026-09-18 P9已获批进入诊断
|
||||
|
||||
官方current已切入本task;用户同意后续清单。旧差异/冻结材料保护基线位于submit-visual-closeout-20260918:352项差异、34目录12138文件。先运行原实现诊断,只有全页面测试新增安全阶段耗时;原产品输入不变。收到终态、确认owner清理后再据证据定稿P9设计与确定性回归。原5000ms/并发/零重试保持,独立PENDING,生产/ARM/真实资料/提交推送部署边界不扩展。
|
||||
## P9诊断终态与最小实施
|
||||
|
||||
p9-diagnostic-r2:10项9通过/1视觉超时,R75四项全通过,0未处理服务异常;两次提交646.077/244.180ms、各26操作,未复现原P2028。确认预检重复实体/明细读取,按design的共享单次实体读取及提交旅行/票据条件查询最小方案先红后绿,不改变aggregate、事务原子性或预算。随后原R75/付款链与视觉同配置验证,再回09-06全量。旧失败与首轮选择器拒绝均保留,独立PENDING。
|
||||
## P9最小实现与单元验证
|
||||
|
||||
已完成feeControl内部单次报销实体读取,原公开helper/其他实体入口保持;submit仅复用旅行分类、按需执行旧绑定票据count,保留aggregate/写入顺序/原事务。原服务反例分别观察预算关闭3次、开启4次读取及跨调用6次,修复后每调用1次且下次重新读;路由三项重复查询反例先失败后通过。
|
||||
|
||||
七文件第一轮115通过/3失败,失败均为既有补助fixture有travel明细却未带出差结构、旧findFirst桩返回null隐藏了矛盾;按实际业务补齐三项合成出差字段,不改产品旅行校验。最终路由36/36通过(3.89秒),其他六文件82项保持前次通过(包括新服务8项),分轮不虚报为一次全量。首轮新增服务测试缺括号及预算开关fixture缺记录已修,失败日志保留,不计产品缺陷。下一按原配置无预载验证R75、完整付款链及全页面,再完整候选。
|
||||
## P9无预载原合成链已通过
|
||||
|
||||
p9-fixed-r3环境/输入/清理PASS、零重试,R75四项全部通过(通知95.039秒),真实报销付款主链281.132秒通过;同轮只有全页面视觉180秒超时,10/11通过,服务端1347响应无未处理异常。此结果支持本次提交优化与下游兼容,不代表已排除全部负载下P2028;P9/原P8完整候选门槛仍保持。09-06已提出不删页面的分组巡检具体方案,因改变累计预算已获用户明确批准7组验收;当前产品源码冻结供静态与治理检查。
|
||||
@@ -0,0 +1,58 @@
|
||||
# PWA 更新事件与本地并发产品缺陷最小修复
|
||||
|
||||
## 2026-10-11 收口记录(待归档批准)
|
||||
|
||||
**已完成的范围**:P1–P4、P6–P10 已勾选——PWA 更新后页面收敛,采购创建/保存草稿、资产创建、单个账号创建与报销提交的事务过期最小修复。本地完整候选 g20-full-r6:后端 4437 通过/1 原条件跳过、372 本地浏览器全过(证据入口见 09-06 implement 顶部)。实现随 `1f8d5b65` 进入候选分支,合并提交 `46a70aa5` 已包含于当前生产 `4a5cd8f2`;其后 10 月历次发布均经完整门禁通过。2026-09-27 用户关于事务上限的决定由已归档的 `09-27-purchase-submit-tx-timeout` 实施。
|
||||
|
||||
**未完成、如实保留**:
|
||||
- P5 保持未勾:旧测试材料中一份 WebKit 派生 registry 已披露的字节变化使“旧材料保护”合取项未恢复,原 baseline 不改。这是测试材料保护问题,不是产品代码缺陷;作为余项由 `09-08-reimbursement-payment-closeout` 继续跟进。
|
||||
- 独立复核:仅 P9(报销提交)经补审 PASS,且 reviewer 未逐行审全部路由分支;本任务全量独立复核未做,不补记为通过。
|
||||
|
||||
**已分流**:预算池 used_amount 无锁读改写缺陷已单列 `09-19-budget-pool-concurrency` 修复并归档。
|
||||
|
||||
原未勾清单与历史“未发布/PENDING”表述为当时记录,保留原样。
|
||||
|
||||
|
||||
## 来源与批准范围
|
||||
|
||||
用户已批准按余项连续推进,未规划内容先落方案。09-06 G18两次同样的四文件4-worker并发验证复现采购500及PWA45秒不收敛;环境与输入/清理PASS。此task拥有两个在用产品缺陷的最小本地修复,09-06仍拥有完整覆盖合同。不能改变R2/R1或自动取得真实操作与发布授权。
|
||||
|
||||
## Goal
|
||||
|
||||
修复已复现的 PWA 更新后页面不收敛和采购创建事务过期,在原并发、预算与业务规则下完成本地验证。
|
||||
|
||||
## Scope
|
||||
|
||||
- PWA:页面已经受A控制,B worker安装/激活并接管后,当前普通业务页自动收敛到B。新版本监听须在异步注册前建立,不能只依赖Workbox注册完成后的updatefound/activated。首次安装不重复刷新;登录/改密/找回/重置密码页保留输入并使用既有更新提示,用户选择后才刷新;前台版本提示原合同不变。
|
||||
- 不在更新过程中删除刚安装的Workbox precache;旧独有预缓存由worker激活清理。运行时缓存清理与显式登出/人工刷新清理区分,保留后者原行为。
|
||||
> 2026-09-27 用户决定(取代下列「不提高5000ms事务预算」约束):负载复现与分段计时显示提交事务无单一瓶颈(事件循环/连接池排队导致整体变慢),P9/P10 缩短事务后仍复现 P2028。采购提交、报销新建/提交三处改用项目既有 `{ maxWait: 5000, timeout: 10000 }`,见任务 09-27-purchase-submit-tx-timeout。其余事务未改。
|
||||
|
||||
- 采购创建:写事务只创建草稿及其审计,最小字段返回后提交,再按相同详情select读响应。权限、切换控制、默认字段、成功响应、审计内容和二者原子性不变;不提高5000ms事务预算或绕过任何审计。
|
||||
- G20续修:资产创建的关系详情读取移至原业务写事务提交后,保留事务内校验、编号、资产与领用写入及原异步审计语义。
|
||||
- G20续修:单个账号创建的原cost12哈希移至事务开始前,保留权限/引用校验、账号/角色/审计原子性及原提交后同步;不改批量导入哈希位置。
|
||||
- P9:修复本地已复现的报销提交事务超时。先核事务步骤耗时/数据库等待及已编号提交路径,再定稿最小优化;保持FOR UPDATE、权限、票据金额、预算、审批历史和审计的同事务一致性,不提高5000ms预算或增加重试。
|
||||
|
||||
- P10:g20-full-r5暴露采购PATCH保存草稿P2028(6529/5000ms),沿用已批准的在用缺陷最小修复范围:保留锁、所有权/状态、主数据、项目关联、明细替换、金额/两次父记录更新顺序及审计同事务,只把响应详情投影移至提交后,不增加重试或超时。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
保留现有差异及旧冻结包。仅本地合成、禁止外联/真实配置密钥备份/生产ARM/恢复/通知付款/提交推送部署归档。
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] P1:本地 production 构建 A→B同profile,原45秒窗口、无测试刷新/清缓存,B文档/active控制器/worker摘要/实际新资源及旧缓存清理共同成立,零页面/静态404/登录回退/重载循环。
|
||||
- [x] P2:可执行生命周期回归覆盖注册Promise未完成时控制器已切换、首次安装、重复事件、worker未激活/失效、认证页延后刷新;已有前台提示与登出缓存清理合同保持。
|
||||
- [x] P3:正式采购路由回归证明草稿/审计同事务、失败不返回成功,详情仅提交后读取、完整响应保持;原采购提交/附件/审批及预算回归不退化。
|
||||
- [x] P4:不带预载观察器的原四文件4-worker/零重试/原预算运行通过;仅证明该组,不能关闭旧full-r2或全负载可靠性。
|
||||
- [ ] P5:前端typecheck/build、Prisma/受影响语法、任务治理和保护检查通过;2026-09-19代码/治理验证保持通过,但新增一处旧WebKit派生registry保护异常未恢复,故此合取项保持开放;只读独立review仍按inline限制单列PENDING,不虚报。
|
||||
|
||||
- [x] P6:资产原响应/可选领用/异步审计语义与提交前后失败边界通过;原资产整链原配置重验。
|
||||
- [x] P7:单个账号原cost12在事务前完成,账号/角色/审计保持同事务;原写入/敏感角色/导入回归及R75完整文件通过。
|
||||
- [x] P8:续修后的完整候选从static重新执行并如实记录,不用旧定向证据抵扣完整验收。
|
||||
- [x] P9:报销提交的重复读取/无效事务开销按证据优化,确定性边界回归和真实合成R75通知原整文件通过;已编号提交不重新取号,失败事务不遗留部分审批/预算写入。
|
||||
|
||||
- [x] P10:保存草稿写入/审计仍原子,完整响应投影只在提交后读取;写入/明细/审计/commit失败不读取、不假成功,提交后详情失败不得宣称回滚或自动重试。原采购主链原预算重验。
|
||||
|
||||
## Test Plan
|
||||
|
||||
使用现有server Vitest与浏览器专用tsc;复用受管retained-local四文件命令。精确命令/结果落implement与本轮独占证据,不读取真实输入、不联网安装依赖。
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"id": "local-concurrency-product-fixes",
|
||||
"name": "local-concurrency-product-fixes",
|
||||
"title": "PWA 更新事件与采购创建事务最小修复",
|
||||
"description": "PWA原生控制器更新与采购最小写事务已本地实施;131单测、原四文件并发4/4、认证/OCR18/18通过。独立及完整门禁仍待,不提交发布。",
|
||||
"status": "completed",
|
||||
"dev_type": null,
|
||||
"scope": "client PWA lifecycle and server purchase draft transaction",
|
||||
"package": null,
|
||||
"priority": "P1",
|
||||
"creator": "shunli",
|
||||
"assignee": "shunli",
|
||||
"createdAt": "2026-09-18",
|
||||
"completedAt": "2026-10-11",
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": "46a70aa5",
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [
|
||||
"client/src/pwa.ts",
|
||||
"client/vite.config.ts",
|
||||
"server/src/routes/purchaseRequests.js",
|
||||
"server/tests/unit/utils/client-pwa-lifecycle.test.js",
|
||||
"server/tests/unit/routes/purchase-request.errors.test.js",
|
||||
"client/tests/e2e/pwa-cross-version-upgrade.spec.ts"
|
||||
],
|
||||
"notes": "2026-09-19 g20-full-r6:4437后端通过/1原跳过,372本地浏览器全过;PARTIAL仅dirty_candidate,独立PENDING/无部署,旧registry保护例外保留且无新增漂移。当前余额见implement顶部。\n2026-09-18本地验证完成,失败/诊断/修后回执与候选在local-coverage-g18-20260918。主会话自检不代替独立PENDING;无预算/并发/权限/审计弱化,未发布。\n 2026-09-26 更新:本地实现已通过候选分支合并落地到 origin/main(合并提交 46a70aa5),不再是仅存在于未提交分支的工作;但真实样本验证/独立复核/生产切换等验收项仍开放,任务状态维持 in_progress,未视为完成。",
|
||||
"meta": {
|
||||
"localImplementation": "VERIFIED",
|
||||
"independentReview": "PARTIAL_WITH_LEGACY_BUDGET_FINDING",
|
||||
"normalReleaseEligible": false,
|
||||
"latestLocalCandidate": {
|
||||
"run": "g20-full-r6",
|
||||
"localChecksPassed": true,
|
||||
"receiptStatus": "PARTIAL",
|
||||
"browserPassed": 372,
|
||||
"publicPending": 12,
|
||||
"independentReview": "PARTIAL_WITH_LEGACY_BUDGET_FINDING",
|
||||
"deploymentEligible": false,
|
||||
"legacyProtectionStatus": "FAIL_ONE_KNOWN_DERIVED_REGISTRY",
|
||||
"newProtectedDrift": false,
|
||||
"productionNumberingActivated": false
|
||||
},
|
||||
"p9TargetedReview20260919": {
|
||||
"status": "PASS_SCOPED",
|
||||
"report": "artifacts/qa-governance/business-followup-claude-review-20260919T023537Z.txt",
|
||||
"reportSha256": "b48e5f53340e139e5a97b5fdcb6d7003881a80a8a08d4004d01aaa6a759d2d0b",
|
||||
"runtimeTestsRerun": false,
|
||||
"budgetPoolFinding": "LEGACY_CONFIRMED_STATIC_UNFIXED",
|
||||
"remediationTask": ".trellis/tasks/09-19-budget-pool-concurrency",
|
||||
"evidence": "artifacts/qa-governance/business-followup-reception-20260919"
|
||||
}
|
||||
}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户