归档10-05错误码可解释性与付款就绪任务(09-05-error-explainability-payment-readiness)
591条历史豁免基线已清零,794条新增reasonCode已通过候选分支合并落地至 origin/main(46a70aa5),主链路零例外,无剩余阻塞验收项。 work landed via 已删除的候选分支而非专属分支,故用 --skip-branch-validation 归档。
这个提交包含在:
@@ -0,0 +1 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
@@ -0,0 +1,276 @@
|
||||
# Design:错误可解释性与付款就绪治理
|
||||
|
||||
## B34 实施前解析器分类补充
|
||||
|
||||
实际依赖合成观测见 import-parser-fix-20260917/library-observations.json。仅普通 Error 的确切格式进入白名单:fast-csv 默认引号未闭合/引号后缺分隔符;JSZip 非 ZIP 的完整固定提示/缺少中央目录结尾;saxes 带行列前缀的未匹配闭合标签、未定义实体、无引号属性值。白名单按 CSV/XLSX 分开,未知消息、非 Error、TypeError、带其他内部故障形态均保留 500,并替换为无原异常引用/cause/自定义属性的固定 Error。白名单不声称覆盖依赖的所有损坏输入,新增格式须有真实库复现。
|
||||
|
||||
catch 只包两个解析 await,不包表格归一化、toBuffer、preview 或 apply。合法 CSV 的 map 原样保留文本,正常 XLSX 仍使用现库。测试抽取 app.js 原 error-handler 回调作响应/日志核验,不 import app/config 或启动 DB/jobs;合法导入继续跑原真实哈希测试,不用 mock 哈希换绿。
|
||||
|
||||
## 2026-09-17 考勤职责与 D15 优先级更正
|
||||
|
||||
依据用户“考勤功能在企微”的澄清,以及 docs/产品设计规则.md 的主办边界与考勤页规则,日常考勤由企微承办。client/src/pages/AttendancePage.tsx 已明确 OA 只展示摘要、解释、同步状态和审计;/attendance/monthly 是 OA 侧汇总查询,不是日常打卡入口。源码保留入口不能证明生产启用或真实使用。
|
||||
|
||||
下方 D15 的低年份观测继续保留,但退出当前必修/待决策清单,作为非阻塞技术记录。2000–2100 方案未获采纳,不实施新年份限制、不恢复旧 OA 打卡、不扩修待精简工资。今后只有摘要查询出现明确业务需求或实际故障证据时再评估;不能把此项处置扩大为删除企微同步、摘要或审计能力。B34 与 D16 原处置保持。
|
||||
|
||||
## 2026-09-17 三类余项的在用性与限定方案(已完成确认,产品未改)
|
||||
|
||||
本次批准为范围确认及先行规划,采用acceptance-boundaries-20260917/boundary-observations.json的合成观测,不把问题复现算修复通过。未新读真实配置/使用量,所称在用入口表示当前产品/源码保留入口,不证明今天的生产开关或使用频次。
|
||||
|
||||
### B34 损坏账号导入:下一本地优先修复方案
|
||||
|
||||
账号管理CSV/XLSX导入仍为保留能力,不属于ERP或工资待精简分支。routes/users的dry-run/apply共用readUserImportPayload:文件尺寸/扩展名/MIME已验证,但ExcelJS的csv.read与xlsx.load异常未映射。原错误handler对非AppError返回500/SYS_001并记录原err;合成未闭合引号CSV、非ZIP XLSX、截断XLSX在两入口共6例均500,CSV两例原err.message含合成单元格标记。9个路由探针(另含两空表头文件及权限拒绝)全部数据库调用0,接口无标记泄露。此为可解释性和日志边界缺口,不声称真实内容已经泄露。
|
||||
|
||||
限定修改范围:users解析边界、新原因的server/client/固定夹具三方,以及users.import定向回归;不修改全局error handler、所有导入器、上传限额、员工权限或apply事务。拟新增user.import_file_invalid,400/VALID_001、details仅固定file=invalid_format,用户提示重新导出CSV/XLSX;不包含文件名、sheet/cell、原解析异常/cause或数据行。现有missing_headers/empty/row_limit_exceeded/大小错误及其优先级保持。
|
||||
|
||||
实施步骤:先以实际依赖可识别的CSV语法和ZIP/XML格式错误建立白名单及反例,只在内存buffer解析两个await处翻译;未知解析器/程序异常继续500,但换成无原message/cause的固定内部错误后交日志,不能把任意故障伪装成输入错。toBuffer读取故障、权限、事务/数据库/哈希异常不得被这个catch吞掉。可识别异常策略须在写产品前用现有版本补齐,不能仅按任意message包含csv/xlsx猜测,也不全局catch所有Error返回400。
|
||||
|
||||
验收矩阵:dry-run/apply × 未闭合引号CSV/非ZIP/截断XLSX/坏XML;合法带引号换行CSV和真实生成XLSX/日期文本/空值/500与501行保持;原7个文件原因/413来源映射保持;权限拒绝先于解析;未知异常仍500且日志/响应均无合成单元格或原exception,读取失败不改分类;格式失败不开始preview/transaction/员工部门角色/成功审计。合法apply仍跑原真实哈希用例,串行避免旧超时。验证users.import、errors-client固定映射、strict/self-test、node --check、前端typecheck/build与治理。没有新数据库结构、外联或真实导入。
|
||||
|
||||
### D15 极低年份:分开旧代码与保留入口
|
||||
|
||||
parsePayMonth及统一考勤parseMonthRange对0000/0001/0099分别映射1900/1901/1999,0100/1900/2024正常;共享date-only字符串解析保留字面低年份。旧attendance服务buildMonthRange已有2000–2100限制且attendance_v1硬关闭,不存在该低年份入口,不能为验证打开它;未使用shiftMonth也不扩修。工资属于既有retirement-review候选,按用户取舍本轮不补修工资/工资导出。
|
||||
|
||||
统一考勤/attendance/monthly仍有页面/route入口,不能整文件以旧考勤名义排除;此为只读查询年月与边界不一致,保留低优先级决策。推荐后续仅该外部年月采用与旧业务月查询一致的2000–2100明确范围;这是新接受年份规则,须单独确认后才写代码。备选为保留四位公历年份并正确构造UTC界限,需另核0000/真实PG支持与跨世纪闰年,不宜未经决策全局替换Date.UTC。均不改历史年月/日期,不推断生产存在低年份数据。
|
||||
|
||||
### D16 AP反向区间:范围确认后维持现合同
|
||||
|
||||
ApOperationsPage将ledgerDateFrom/To分别传列表与导出,共用financeLedger构造gte/lte。两端为有效日期但from>to时继续200,谓词同时成立无匹配;不交换日期、不忽略其中一端,deleted_at过滤仍保留。73项现有AP列表/导出回归通过;探针只实测共享where构造,不冒称真实PG空集。日期本身非法仍400,pendingCreatedAt反向范围的原400与ledger不是同一合同。
|
||||
|
||||
当前不列为必须修复项。若以后需要输入体验提示,必须同批覆盖页面、列表、CSV/XLSX导出及原因三方,把200改400作为显式需求;不可只在共享where偷偷改变规则。不新建视觉方案、不改权限/金额/写入,也不需真实数据验证本次保持结论。
|
||||
|
||||
## G8按在用路径收口
|
||||
|
||||
按implement顶部B31–B33合同处理57处,17处ERP旧分支按用户最新指示跳过并保留源码/基线。其依据为产品设计规则61/89及企微路线图37;通用outbox有notification.im消费者不整文件跳过。当前权限/状态/编号/开关/认证业务规则保持,只本地合成。所有旧材料保护、独立PENDING,不读真实配置密钥/外联/提交部署或实施借款。
|
||||
|
||||
|
||||
## G7本地错误合同接续
|
||||
|
||||
查询考勤周报八源42处,按implement顶部B29/B30逐操作合同实施;三方固定提示、精确减基线、实际路由/服务负例和合法回归、页面安全消费及保护新候选。legacy考勤硬关闭保持,内部路由用合成门禁桩分层验证;周报项目开关失败前原update尝试保持。独立PENDING,不扩权限/状态规则,原真实数据/外联/提交部署边界不变。
|
||||
|
||||
## G6实现边界
|
||||
|
||||
共享审批原步骤/角色/兜底/人员上下文守卫分别注册原因,动态主管失败沿固定安全提示,不拼角色ID或链内容。流程定义与审批规则schema由调用方显式传原因;原快照、权限、锁、状态、发布/审计和金额规则保持。不可达防御仅静态核对,不通过改规则制造测试覆盖。B28a仅把委托本人范围和有效期筛选从覆盖式object spread改为AND组合,保留每一原谓词及管理权限来源;结构核验显式单列此处,路由内存过滤负例证明普通用户不会得到他人有效委托。
|
||||
|
||||
## Bug Analysis: 委托列表同名OR覆盖
|
||||
|
||||
### 1. Root Cause Category
|
||||
- **Category**: E/D - 隐含对象合并假设与测试缺口。
|
||||
- **Specific Cause**: 期望本人范围OR与有效期OR同时成立,但后置spread按键覆盖前者;原默认includeInactive=false触发。
|
||||
|
||||
### 2. Why Fixes Failed
|
||||
无历史修复证据,不编造失败史。本轮先保留4个真实Fastify/合成内存过滤红例,唯一AND组合修复后8个范围用例及全34项委托用例通过。
|
||||
|
||||
### 3. Prevention Mechanisms
|
||||
| Priority | Mechanism | Specific Action | Status |
|
||||
| --- | --- | --- | --- |
|
||||
| P0 | 结构 | 两个已有谓词放入AND,保留管理权及原日期边界 | DONE |
|
||||
| P0 | 回归 | 默认/false/0与true/1、本人/他人、管理员过滤、开始/结束等时边界 | DONE |
|
||||
| P1 | 规约 | backend-fastify-prisma记录同名OR合并与消费where的测试要求 | DONE |
|
||||
|
||||
### 4. Systematic Expansion
|
||||
本轮只对baseWhere/scopeWhere/permissionWhere传播作源码定位,未做全仓授权审计,不声称不存在其他组合问题。无通用查询框架改造;后续可见性条件变更应保留权限对象并组合筛选。模拟findMany不能无条件返回固定列表来证明数据隔离。
|
||||
|
||||
### 5. Knowledge Capture
|
||||
- [x] 更新现有后端spec、当前design与implement;无新计划系统。
|
||||
- [x] 本仓无src/templates/markdown/spec目录,不生成Trellis工具模板。
|
||||
- [ ] 独立只读内容复核PENDING;遵照用户不提交要求,不执行技能默认commit。
|
||||
|
||||
## G5接续设计
|
||||
|
||||
合同schema由四操作显式传原因,版本/终止/归档/纠错/续订守卫保留status和事务位置。采购预算先写流水后查池、release缺池继续的原语义不改,默认409显式传给新builder;仅无剩余消费者时删除旧导出。测试区分已尝试写入、无后续额度/成功审计和mock事务恢复,不能冒称真实PG回滚。
|
||||
|
||||
资产分类/卡片/索引schema和人员角色原因由调用方明确给出;流转与盘点原状态和循环写入位置保持。采购上传策略仅用既有PurchaseAttachmentPolicyError.reasonCode白名单映射(未知用固定安全兜底),下载构造保留旧message/status/details.reason与必要审计。AST批量迁移需识别shorthand statusCode属性,不能因缺initializer误用默认400;本批通过下载409及原文案路由断言证明。采购金额规范化前原主表update/明细delete和预算前原重算写入不改变。
|
||||
|
||||
## G4差旅实现设计
|
||||
|
||||
申请list/id、create/patch/link-project输入及既有状态/财务维度/预检/流程分支分别注册原因。link-project原parseUuid无定义,三个真实Fastify合成用例先复现非法/绑定/解绑均500,再用parseTravelRequestId修复并回归原404/403/开关守卫;不新增项目关系或状态限制。CJS语法检查不能发现运行时未定义函数,保留这组路由回归作为防复发证据。
|
||||
|
||||
订单/授权/交易导入共享禁用原因,各类schema和空归一化分别解释;标记付款保持精确结算交易匹配,冻结建议仍只记录建议。travelPayments缺池保留409,授权/冲正先ledger再查池,结算原仅ledger不查池/改额度。对账路由与服务旧helper默认409,迁移均显式保持;只有原schema/id错误400,原存在性校验不额外限制启停。原helper全部消费者迁移后删export/import。
|
||||
|
||||
七源结构检查仅排除错误构造/原因参数及已单测的ID解析器修复,原权限/状态/副作用顺序/事务保持。主会话本地证据,独立PENDING。通知、预算、流程参与者只用桩,ERP仅mock DB outbox,不声称真实发送、PG回滚或开关开放。
|
||||
|
||||
## G3基础资料实现设计
|
||||
|
||||
共享schema由调用方显式给操作原因;动态参数经getErrorReason校验,所有原因在服务端、客户端固定映射与断言夹具三方登记。四主数据实体各有id/list/create/patch/空修改原因,跨模块相同公司引用拒绝复用原因;原编码规范化、层级/归档和P2002映射范围保持。日历日期替换保持500项、空数组清空、默认日历绑定与先验后删顺序。
|
||||
|
||||
费用标准保留合并旧范围后校验的PATCH语义,假别保留原空PATCH和嵌套policy更新,模板保留50项、禁用类型原索引详情及软删除幂等。项目14种schema、7类id、5类开关、列表和豁免备注分别明确;收口项原先初始化再验id/body顺序保持并单独合成实证。项目日期仍只有原格式校验,本轮不扩日历规则或真实功能开放。八源AST去除错误构造/原因参数后业务结构一致,只作主会话辅助证据。页面沿既有安全resolver;假别写API无现有页面调用、费用类型仅有读取客户端,不能声称完成这些管理页面。
|
||||
|
||||
## B11–B14实现边界
|
||||
|
||||
预算范围和选池沿用原优先级,控制规则PATCH仍按提交body判断;账号唯一冲突详情继续兼容但客户端不拼数据库字段,密码策略与角色/会话操作不改。部门层级/归档只替换错误构造;员工各schema由调用方显式传入注册原因,分别标识合同、培训、证书和生命周期操作。
|
||||
|
||||
withUploadSizeReason仅包住员工上传request.file与toBuffer,精确捕获FST_REQ_FILE_TOO_LARGE→原400/VALID_001/file=file_too_large,其他异常原样。合同下载构造器使用注册原因后恢复原安全message“合同附件未通过安全校验”,409及阻断审计保留,不泄露文件字节。六源AST结构对照证实原守卫、数据访问、权限和事务未变;这些为主会话本地证据,独立仍PENDING。
|
||||
|
||||
## B10路由原因与全量分组
|
||||
|
||||
预算13分支使用显式budget原因;绩效12原因中parseBody由创建/修改/评分操作显式传入,并通过getErrorReason校验,已有活动周期预检和P2002共用同一原因。移除两个无消费者的legacy builder,不改预算共享服务、schema、状态判断或守卫顺序。页面复用既有resolver;P2002测试只证明异常映射,不证明真实PG并发约束。全部546处按implement顶部互斥文件组持续收敛,详细操作合同在每批实施前补齐。
|
||||
|
||||
## B6/D13/D14/B7–B9连续本地设计
|
||||
|
||||
B6保持上传原生产400合同,分别捕获取得filePart与消费toBuffer时的文件过大异常;7原因不涉及文件名/内容拼接,其他异常原样。D13证实月份00/13已有后置拒绝,只补路由/UTC月界证据;低年份Date.UTC映射另列,并未改可用年份范围。D14在公告原schema候选之后检查本地日期部分与finite Date,避免仅验ISO前缀;不拿UTC日与输入日相等作时区校验,因此跨UTC日期偏移仍合法,原无偏移/24:00滚动兼容保留。
|
||||
|
||||
B7–B9把公告和工资现有拒绝分支按操作注册原因;parseBody所需原因由每个调用方显式传入,删除这两个文件已无消费者的legacy builder;attendance/exports则保留可选原因,防止给其他域贴错提示。原权限、状态判断、数据库查询/锁/事务/金额规范化代码不变。公告创建/更新/归档/签收复用既有安全resolveErrorMessage及toast;工资页面本来已消费resolver,无额外UI改造。P2002冲突只是数据库桩测试,不虚报真实并发/回滚。累计新增36原因,审阅与恢复/生产交付门禁继续分开。
|
||||
|
||||
|
||||
## 2026-09-17 D12/B5实现设计
|
||||
|
||||
D12将HR原多格式转换与日历有效性分开:canonical日期用既有isValidDateOnlyString判定,normalizer同时保留hireDateInvalid,不能将非法null解释为缺失。processProfile在原缺必填/非active守卫之后、resolveDepartment之前整条skipped/invalid_hire_date;对直接注入sourceProfiles的hireDate再校验。合法来源、新建缺省now及现有员工不改hire_date保持;运行/item审计允许,业务实体和主管同步不得消费非法项。
|
||||
|
||||
B5按明确操作选择7原因。合同和在岗共享legacy错误helper还被写入/冲突使用,故只迁移筛选服务具体分支;员工/合同导出外层schema另显式传域原因,经getErrorReason校验后调用business builder。其余导出不传参数,保持旧合同;不按details动态推断、不改变导出/权限/31天规则。原因注册/client/fixture及只减的baseline作为同批审阅输入。
|
||||
|
||||
|
||||
## 2026-09-17 D1–D4执行边界
|
||||
|
||||
沿implement中已落盘的四批日期规划继续,统一复用日历谓词但仅在各已核外部schema串接refine,保留原regex、nullable/optional、权限守卫及业务写入顺序。todos两处dueDate、员工共享筛选及导出、节假日整批items、仪表板与AP导出日期分别验证;导出共用DATE_ONLY_SCHEMA保持旧定义,其他域不能被无意扩修。
|
||||
|
||||
非法节假日必须在解析整批时拒绝,事务/清空/新增/审计均未调用;合法批次仍按原事务写入,不以mock声称真实数据库回滚。AP pending反向区间保留400;ledger反向区间原无拒绝守卫,另待范围规则审阅,不在本批改变。员工/users与/employees共享服务,权限判断原顺序及最小目录DTO保持;日期输入修复不授权读取或修改真实员工资料。
|
||||
|
||||
验收为本地合成Fastify路由与已有回归、语法/合同及治理检查;不会启动真实DB、读取环境配置或触发消息。新结果/候选按新目录保存;上一轮候选与未提交修改继续保留,不把主会话自检计为独立复核。
|
||||
|
||||
## 2026-09-17 B1/B2小批设计
|
||||
|
||||
B1沿既有isValidDateOnlyString窄谓词:在四个高风险外部路由的原字符串regex之后refine,再保留原optional/nullable外层;区间先保证两端都是实际日历日期,再走原顺序约束。周报必须在周一归一化之前验原始输入,在岗按写入/查询各入口追踪。服务层二级消费者只有查明外部来源才补闸,不统一改转换器或批改存量。
|
||||
|
||||
B1每组锁定原HTTP状态、权限、workflow及事务调用次数;无效日期不能进入写入、通知或成功审计。日期函数已有测试复用,并补各真实路由负例,避免只测正则/复制schema。合同/采购等冻结业务只修输入契约,不开入口或改开关。
|
||||
|
||||
B2按现有检查器的实际指纹/上下文分组,不把612次历史计数当作待修bug总数。新迁移采用buildBusinessValidationError,保留status/code/details;动态OCR字段、密码规则和催办时间沿已审窄投影及服务端负载合同,不以注册静态句覆盖动态指导。异常正文、银行数据和未白名单字段不能进入提示。
|
||||
|
||||
回退按单一小批补丁进行,不新增迁移、不改历史数据;原因码、客户端映射、固定文案夹具、对应测试和只减不增的基线处置作为同一交付单元。新发现需要修改审批资格、状态机或付款语义时停止并另审,不藏在提示治理中。到期延期只允许逐项理由/负责人/复验条件经批准后变更,禁止集中改日期。
|
||||
|
||||
### 本轮落点与审查边界
|
||||
|
||||
B1a四路由加合同查询共享服务`contractRegistryFilters`;该服务也接合同导出,属于已证实外部输入,复用同一守卫。B1b两路由加`exports`的PRESENCE_HISTORY_EXPORT_QUERY_SCHEMA,限定在岗导出日期,不改所有导出共用日期schema。`presenceHistory`仍只处理由已校验入口或内部当前日期传入的值;其他导出/待办等日期另列后续消费者,不在本批临时扩修。
|
||||
|
||||
B2当前扫描229注册/316已迁移/612遗留、主链例外0。选取通知列表/渠道管理、员工待办及门户开关提示这一小批,逐固定原因码迁移原调用,不更改通知投递、权限、状态或业务开关;门户未使用的通用validation helper可删除。三方文案与真实路由负例整批校验,仅移除实际消失的AST指纹,原owner/expiresOn逐条保留。通知测试使用现有合成渠道,不调用真实企业微信。待办日期溢出属于另一个输入批次,先登记,不借提示迁移扩大行为。
|
||||
|
||||
## 1. 总体边界
|
||||
|
||||
本任务不把全部 `VALID_001` 重构成新异常体系。保留 HTTP status、顶层 code 和既有 details,在已迁移错误中增加稳定 `details.reasonCode`,用注册表、遗留指纹基线和 focused 测试形成只增不退的 ratchet。
|
||||
|
||||
```text
|
||||
服务端业务事实
|
||||
-> 原因码注册表 / domain validator
|
||||
-> AppError { code, details: { reasonCode, ...legacyDetails } }
|
||||
-> ApiError(保留 requestId)
|
||||
-> 原因码中文映射 / 页面专用投影
|
||||
-> 就近提示 + 动作禁用 + 安全兜底
|
||||
```
|
||||
|
||||
## 2. 原因码注册表
|
||||
|
||||
服务端建立唯一原因码注册表模块,例如 `server/src/constants/errorReasons.js`。每项至少包含:
|
||||
|
||||
```js
|
||||
{
|
||||
code: "payment_batch.legal_entity_required",
|
||||
domain: "payment_batch",
|
||||
audience: "user",
|
||||
defaultMessage: "报销人尚未维护所属公司,请联系管理员补充后再安排付款。",
|
||||
recovery: "contact_admin",
|
||||
}
|
||||
```
|
||||
|
||||
客户端维护显式、可测试的 reasonCode 映射。静态提示可使用注册表默认中文;涉及数量、页面定位或权限差异的提示由窄化 renderer 处理,但必须有默认安全提示。服务端使用常量或经注册表校验的 builder,不散落裸原因码。
|
||||
|
||||
兼容响应继续使用 `VALID_001`,并同时保留 legacy details:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "VALID_001",
|
||||
"message": "参数校验失败",
|
||||
"details": {
|
||||
"reasonCode": "payment_batch.legal_entity_required",
|
||||
"legalEntity": "single_legal_entity_required"
|
||||
}
|
||||
},
|
||||
"requestId": "..."
|
||||
}
|
||||
```
|
||||
|
||||
新 UI 不使用该 message 作为用户文案来源。未知 reasonCode 走安全兜底,并由现有 `ApiError.requestId` 附加排障编号。
|
||||
|
||||
## 3. Parity 与遗留基线
|
||||
|
||||
新增 `scripts/qa/check-error-reason-contract.mjs`,使用仓库已有 parser 解析 JS/TS,而不是按 key 或行号做字符串计数:
|
||||
|
||||
1. 注册表唯一、命名和元数据完整;`audience=user` 必须有客户端映射。
|
||||
2. reason-aware builder 的原因均已注册;客户端无孤儿映射。
|
||||
3. 泛化 `buildValidationError` / `new AppError(...VALID_001...)` 调用若没有 reasonCode,必须命中版本化遗留调用指纹。
|
||||
|
||||
遗留基线放在 QA 合同附近,例如 `scripts/qa/error-reason-legacy-baseline.json`。按业务域/文件组记录 owner、reason、expiresOn 和规范化 AST 节点形状指纹;指纹必须忽略空白、缩进、换行和纯格式化差异,源码文本与行号仅用于报告,不参与身份计算。首批主链路 operation 单列为 zero-exception,命中遗留也失败。self-test 用临时 fixture 验证新增、删除、拼写、结构性指纹变化、纯格式化不变、过期和同 key 跨域。
|
||||
|
||||
这避免两类假门禁:只比数量可被“一增一删”绕过;只比 details key 会把不同业务语义误判为同一覆盖。
|
||||
|
||||
## 4. 首批迁移边界
|
||||
|
||||
首批原因域:
|
||||
|
||||
- `reimbursement.*`:提交、草稿编辑、票据关联/恢复。
|
||||
- `payment_batch.*`:候选/组合 readiness、创建、复核、回单和登记。
|
||||
- `leave.*`:员工提交路径。
|
||||
- `attendance_correction.*`:员工/授权应急提交路径。
|
||||
|
||||
同一业务后果跨入口复用同一码;不同业务后果即使 legacy key 相同也使用不同码。20 处旧字符串先形成 task-local 处置表:客户端 mock、主链路服务测试、内部/持久化摘要、延期域分别处理。迁移测试断言 exact reasonCode、HTTP status、兼容字段和准确中文,不使用模糊 message 正则。
|
||||
|
||||
## 5. 付款 readiness 服务
|
||||
|
||||
抽取无 HTTP 展示依赖的 `resolvePaymentBatchCreationReadiness`。输入包括 entity type、entity IDs、付款渠道、maker ID 和当前配置;输出只含安全原因:
|
||||
|
||||
```ts
|
||||
type PaymentReadiness = {
|
||||
ready: boolean;
|
||||
blockers: Array<{
|
||||
reasonCode: PaymentBatchReasonCode;
|
||||
entityId?: string; // 只用于关联,不直接渲染
|
||||
entityCode?: string;
|
||||
}>;
|
||||
};
|
||||
```
|
||||
|
||||
解析器复用快照、部门 gate、活动占用、付款账户和 reviewer 事实。敏感账户只做存在性、银行机构和可解密判断,响应不带密文、完整账号或原始 employee。
|
||||
|
||||
```text
|
||||
GET candidates
|
||||
-> 单条 resolver
|
||||
-> readiness/blockers 决定可选性和提示
|
||||
|
||||
POST readiness(只读)
|
||||
-> 当前多选集合的组合 resolver
|
||||
-> 跨公司/占用/复核人等组合提示
|
||||
|
||||
POST create
|
||||
-> 事务 + 锁后复用同一 resolver
|
||||
-> ready=false 抛相同 reasonCode
|
||||
-> ready=true 才创建 batch/items/audit/notification
|
||||
```
|
||||
|
||||
候选查询必须批量载入必要关系、占用、付款账户和复核人事实,避免在候选循环中产生 N+1。readiness 不落库、不进入长期缓存;资料补齐后刷新查询即可得到新事实。
|
||||
|
||||
## 6. UI 投影
|
||||
|
||||
依据 `ui-ux-pro-max` 的表单反馈规则:错误就近、提供恢复路径、toast 不作唯一反馈。
|
||||
|
||||
- 正常候选保持紧凑,不显示“资料已齐全”。
|
||||
- 异常候选仍出现在列表中,避免再次形成不可见状态空隙;复选框 disabled,行内展示必要缺项。
|
||||
- 缺员工资料时说明需管理员维护;仅有维护权限者看到对应入口。
|
||||
- 非建行时说明当前银行付款渠道限制,不引导伪填。
|
||||
- 组合 readiness 紧贴主动作,使用 `role=alert`/`aria-live`,按钮以 `aria-describedby` 关联原因。
|
||||
- create 并发失败复用相同映射留在动作附近;toast 只补充“未创建付款安排”。
|
||||
- 未知错误显示可行动兜底及可用 request ID,不回显原始 details。
|
||||
|
||||
## 7. 兼容、隐私与回滚
|
||||
|
||||
- API 是加法变更;旧 code/details 保留,旧客户端继续工作。
|
||||
- 不记录银行卡、密文、完整账号或真实 payload。原因码是否进入脱敏服务端日志延期评估。
|
||||
- 不改变付款状态机、maker-checker、角色、通知对象、回单门禁或 B1/B2。
|
||||
- 无 migration/schema/seed/flag/routing。生产资料补录不属于部署步骤。
|
||||
- 建议按“原因码/parity、首批迁移、付款 readiness/UI”形成逻辑提交;付款提交可独立回滚且无数据库补偿。
|
||||
- 部署另行批准;公网只用合成 fixture 验证。不得自动创建、复核或付款 0014。
|
||||
|
||||
|
||||
## 8. 到期清单的后续分流合同(2026-09-09)
|
||||
|
||||
按已有 scanner 输出的 file/operation/fingerprint/count 与源文件摘要建立逐条台账,文件表仅作索引。未知使用状况记为待复核,不推导无需维护或默认低频;未证明删除/迁移成功的记录不得核销。保留原 expiresOn 与 owner,不把新 reviewDue 当作门禁新期限;拟延期日期和批准记录必须独立且逐模块说明。
|
||||
|
||||
共用 validation builder 的一个指纹可能影响多个业务分支,迁移必须在调用语义层选择原因;不能批量将所有旧错误映射成一个“通用参数错误”或只更新计数。每个获批迁移分支先定位入口与旧 HTTP status/code/details,再增加精确 reasonCode/中文及失败副作用断言。当前只完成清单,不新增迁移范围或任何线上行为。
|
||||
@@ -0,0 +1 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
文件差异内容过多而无法显示
加载差异
@@ -0,0 +1,184 @@
|
||||
# 错误可解释性与付款就绪治理
|
||||
|
||||
## B34 当前验收状态
|
||||
|
||||
用户批准接续后,损坏账号导入的限定修复已完成本地合成验证:已复现白名单格式返回固定400提示,未知解析故障继续500且不记录原解析内容;权限、文件限制、合法导入、日期文本与事务保持。最终68项导入加854项原因合同断言通过,前端typecheck/build及原因strict/self-test通过,详见implement最新回执。此结论不等于独立复核、真实导入或上线;下方“尚未实施”保留原时点,D15非阻塞、D16现合同及17 ERP排除不变。
|
||||
|
||||
## 2026-09-17 用户澄清:考勤由企业微信承办
|
||||
|
||||
用户明确“考勤功能在企微”。按现行产品规则,打卡、请假、补卡、外出、加班由企微承办;OA 保留月度摘要、异常解释、同步状态及审计,不恢复旧 OA 打卡。此前 D15 是 OA 摘要查询的极低年份技术观测,不是企微考勤故障,也不是新建 OA 考勤的需求。
|
||||
|
||||
D15 不列为本轮必须修复或阻塞收尾的项目;原 2000–2100 建议仅为未采纳的技术备选,不再作为等待用户决定的必办项。保留观测和现有代码,不把它记为已修复,也不由此认定所有企微摘要/同步代码均已废弃。B34 账号导入仍为下一本地修复优先项。
|
||||
|
||||
## 2026-09-17 剩余边界确认结果
|
||||
|
||||
W6三类余项已完成本地范围确认,产品源码未更改。损坏账号CSV/XLSX在两入口仍返回500且CSV异常可将合成单元格交给日志,列为B34优先修复方案;具体错误白名单、固定安全提示与未知内部异常分流见design。低年份D15将工资待精简路径排除,统一考勤保留入口只读偏移另待接受年份决策。AP反向ledger区间D16保持现有200及有界查询,不作为必须修复项;非法日期/其他区间原拒绝保持。
|
||||
|
||||
本轮验收为合成行为证据、在用/排除依据与限定实施方案,不把characterization通过记成缺陷已修复。旧17处ERP排除与原人工复审日期不变;不修改原AC勾选、不提交部署或访问真实数据。
|
||||
|
||||
## G8按在用路径收口
|
||||
|
||||
按implement顶部B31–B33合同处理57处,17处ERP旧分支按用户最新指示跳过并保留源码/基线。其依据为产品设计规则61/89及企微路线图37;通用outbox有notification.im消费者不整文件跳过。当前权限/状态/编号/开关/认证业务规则保持,只本地合成。所有旧材料保护、独立PENDING,不读真实配置密钥/外联/提交部署或实施借款。
|
||||
|
||||
|
||||
## G7本地错误合同接续
|
||||
|
||||
查询考勤周报八源42处,按implement顶部B29/B30逐操作合同实施;三方固定提示、精确减基线、实际路由/服务负例和合法回归、页面安全消费及保护新候选。legacy考勤硬关闭保持,内部路由用合成门禁桩分层验证;周报项目开关失败前原update尝试保持。独立PENDING,不扩权限/状态规则,原真实数据/外联/提交部署边界不变。
|
||||
|
||||
## G6验收补充
|
||||
|
||||
共享审批工具、流程定义、审批规则和委托仅迁移原错误合同,保留原status/details、角色/自审批/快照/主管链规则及事务副作用位置。明确不可达防御与本地mock边界,另限定修复委托列表有效期OR覆盖本人范围OR的组合缺陷:两者AND同时生效,恢复原有范围而不新增管理权;须有合成数据红绿路由证据。具体操作与验收以implement为准;独立只读复核PENDING。
|
||||
|
||||
## G5验收补充
|
||||
|
||||
延续120处采购/资产/流转盘点/合同与共享预算错误合同治理,仅新增明确原因和固定安全提示,原状态/权限/冻结/附件安全及业务写入顺序保持。具体子批先行合同与进展以implement顶部为准;仅本地合成,不以扫描数代替分支或真实业务验收。
|
||||
|
||||
## G4差旅验收补充
|
||||
|
||||
B19–B21覆盖申请、订单、授权、交易及共享预算和对账错误合同。保留原400/409/details、审批/付款/预算规则、锁/事务、按条导入跳过与幂等、ERP排队门禁及敏感文案固定映射。另修复申请关联项目误调用未定义parseUuid导致500,复用本文件已有id解析器,原可见/绑定规则不改。缺预算池前原ledger尝试、工作流拒绝前原风险处理继续明确记账,不虚报零写入或真实回滚。
|
||||
|
||||
## G3基础资料验收补充
|
||||
|
||||
B15–B18覆盖公司/成本中心/单据分类/供应商、日历、费用标准/类型、假别、模板及项目逐操作错误合同。仅补稳定原因与固定安全提示,保持原400/409/details、权限、开关、状态、金额/日期schema、默认值/null和事务审计。项目收口项的原先行惰性初始化例外明确记录:拒绝后不修改目标项、不记成功审计,不承诺所有拒绝零写入。旧详情中的公司代码及无效费用类型列表不用于拼UI文案。仅合成测试,具体合同与验收状态见implement顶部。
|
||||
|
||||
## B11–B14连续本地验收
|
||||
|
||||
覆盖预算范围/选池与控制规则、员工账号/部门、员工资料/生命周期/合同培训证书及头像/合同附件错误解释。保留旧HTTP、VALID_001、详情字段与权限/冻结/事务/业务规则,三方原因及可恢复提示同批。员工文件读取只捕获既有生产映射的FST_REQ_FILE_TOO_LARGE并补原因,原文件限额/格式/内容检查和下载阻断安全message/审计保持。原目录无调用helper清理与不可达日期防御分支单独记录,测试只用合成资料和离线桩,详细合同以implement顶部为准。
|
||||
|
||||
## B10及剩余546处治理
|
||||
|
||||
按implement顶部8组总表连续处理同类本地错误合同。B10限定预算/绩效路由原拒绝条件,保留管理员权限、经理/本人冻结、预算范围/额度和事务状态;只补25个明确原因及安全恢复提示。覆盖原status/details、无后续写入/成功审计、正常与权限回归,三方文案和严格基线同批验证。共享预算服务仍单列未完成,不能称整个预算域清零。
|
||||
|
||||
## B6/D13/D14/B7接续验收
|
||||
|
||||
连续完成账号导入文件7原因、月份后置守卫补证/具体提示、公告三日期字段合法性与公告操作原因/现有页面错误反馈,并收齐工资维护现有校验原因。共36原因,业务拒绝条件不变。原status/details、导入事务/预览审计、工资生成发放规则、公告时区/缺省/签收保护保持;非法上传或公告时间不进入业务写入。月份00/13已有校验不能重复宣称修复,低年份Date.UTC偏移另列决策。精确合同与状态以implement最新入口为准,不扩大到真实业务或借款实施。
|
||||
|
||||
## 本轮D12/B5验收补充
|
||||
|
||||
继续执行已批准的本地日期与错误治理:HR入职日期缺失保留默认,提供但非法必须整条跳过并保留安全审计,在部门/账号/角色/身份/主管写入之前拒绝;已有员工不新增入职日更新。员工目录、合同筛选(含对应导出外层输入)及在岗历史范围共7原因,兼容原status/details与默认范围。以本轮implement顶部为当前限定合同;旧“D12尚未实施”为历史时点,完成状态以本轮回执为准。仅合成数据与离线桩;独立/发布不由主会话本地验证抵扣。
|
||||
|
||||
|
||||
## 2026-09-17 连续本地治理范围(当前合同)
|
||||
|
||||
用户已批准按后期规划连续推进。继D1–D4后,实施D5用户创建/修改/CSV/XLSX入职日、D6员工资料/生命周期/档案、D7 AP直接列表、D8余项盘点、D9仪表板直接读、D10薪资/预算/绩效、D11考勤修正/请假和同步请求日期。仅本地输入校验,保留原权限、开关、状态机、额度/区间/默认日期和nullable/optional;旧attendance_v1固定关闭不被解冻。CSV须保留合法日期及文本标识原值,非法apply整批无业务写入,dry-run原审计保留。
|
||||
|
||||
B3/B4限于dashboard/AP查询/开关及账号创建/修改/工号不可改/空修改/导入错误行9原因;旧VALID_001、status/details保持,客户端具体安全文本、固定夹具和真实路由负例同批。剩余豁免只删消失指纹,原owner/2026-10-05不变。
|
||||
|
||||
验收按D5–D9/B3/B4最终17文件520项及后续D10/D11的9文件61项分列,两组不冒称全仓/独立/真实DB或公网。前端typecheck/build通过;完整记录/初跑失败/精确命令归implement及新证据目录。D12外部HR多格式日期须先分清缺失默认与非法跳过,尚未实施;datetime/月份、AP反向区间改变、历史数据修订和借款实现不在本批。旧批次/冻结材料保留,提交发布另按门禁。
|
||||
|
||||
|
||||
## 2026-09-17 D1–D4本地接续范围
|
||||
|
||||
用户在D1–D4规划落盘后要求继续推进,本轮仅落实待办dueDate、员工目录及导出的hireDate筛选、节假日批量日期、仪表板/AP导出date-only字段。无效日历日期须在写入/业务导出查询前拒绝,原nullable/optional、权限、重复/归档冲突及区间语义保持;CSV/XLSX共同验证。完整结果见implement顶部,未来09-25人工复审与剩余错误豁免仍开放。
|
||||
|
||||
不扩大共享parseDateOnlyString转换、员工资料写入/导入、审计datetime、工资月份或AP台账反向区间规则;不修改客户端/迁移/生产。B1/B2原候选保留,本次新输入另冻供独立审查,不将旧450项验证冒称覆盖新输入。
|
||||
|
||||
## 2026-09-17 后续治理范围(本地实施已批准,已发布批次不重做)
|
||||
|
||||
按09-08优先级表承接B1/B2。B1先覆盖contractsRegistry、purchaseRequests、travelOrders、travelReconciliation的外部日期,再覆盖weeklyReports/presence;只加输入日历守卫,不开放冻结模块、不改审批/付款规则、历史数据或旧parseDateOnlyString转换约定。内部派生日期逐调用点追上游资格,不因引用旧解析器就整文件替换。
|
||||
|
||||
B2先用现有AST门禁盘点当前豁免及用户可达操作,再处理确实未迁移的常用路径;已发布paymentAccounts/invoicePool/auth/workflow提示不重复实施。每项必须同时有服务端原因码、兼容details、客户端具体文案及动态字段/无副作用断言;保留逐条批处理失败原合同,不靠宽泛正则或删基线隐藏问题。
|
||||
|
||||
新增小批验收:非法日历输入在事务/写入前拒绝,闰日/月末/null/省略及原区间/周起点语义保持;新原因码三方文本一致,动态字段投影仍安全,主链路零新增例外;受影响真实路由/客户端定向测试通过并经相应只读审查。09-25复审、09-30必要单项延期提案、10-02查漏、10-05原到期门禁不变,责任人shunli;本轮未创建定时任务、不延期。
|
||||
|
||||
用户已于本日批准按梳理继续,本节既有B1/B2小批进入本地实施;新增schema/业务规则、整库历史修订、生产写入和发布不在范围。与08-23受保护操作等待解耦,不要求完整灾备全部通过才能做本地治理。
|
||||
|
||||
|
||||
## 2026-09-09 追加阶段
|
||||
|
||||
用户已批准综合任务安排的本地实施。复用本 task 管理 10-05 到期豁免分流,不改变原功能验收。当前交付是 73 文件/673 指纹全量核对与分流台账(implement.md §13);未迁移原因码、未修改基线日期,不把 file 级分类冒充逐调用业务裁决。新分支迁移沿原 status/code/details 兼容与精确测试合同;须先完成既有两笔隔离提交,不能在原脏树叠第三笔产品代码。延期、提交、推送、部署各守明确授权。
|
||||
|
||||
|
||||
|
||||
## Goal
|
||||
|
||||
把“系统知道为什么不能继续、真人只看到参数校验失败”的缺陷从逐页补文案改成可持续的错误合同,并以付款批次为第一个完整样板:财务在点击前就知道付款资料是否齐全、缺什么、由谁补;点击后的服务端二次校验与页面提示必须来自同一份实时判断。
|
||||
|
||||
## Background
|
||||
|
||||
- 2026-09-05,真实单据 `0014` 在生产付款页已能进入待处理队列,但财务选择银行转账并点击“创建并提交复核”后只看到“参数校验失败”。只读诊断确认请求未创建付款批次;报销人缺所属公司、开户银行和银行卡号,公司侧已有有效建行付款账户,经理/CEO 复核人存在。
|
||||
- 服务端创建前已检查来源状态、公司归属、收款账户、公司付款账户、活动批次占用和复核人;客户端未覆盖付款原因,因此回退到通用技术文案。
|
||||
- 这是十一天内第三次“参数校验失败”阻断真人主流程。此前 B2 已验证“一份判断同时驱动展示、点击拦截和 mutation 二次拦截”能防漂移;本任务把该模式推广到付款就绪。
|
||||
- 当前文本基线:服务端同一通用校验文案 365 处,`buildValidationError(` 518 次,测试目录中该字符串 20 次。数量用于确定渐进迁移边界,不代表独立业务原因数量。
|
||||
- `details key` 不能作为原因合同:同一个 `legalEntity`、`status` 或 `review` 在不同业务域含义不同。稳定合同必须是带业务域的原因码,例如 `payment_batch.legal_entity_required`。
|
||||
- 生产资料补录和真实付款继续由授权人员操作;本任务不得读取、记录或修改真实银行卡号,不把伪填建行资料作为恢复办法。
|
||||
|
||||
## Scope
|
||||
|
||||
本 task 包含三项互相支撑但可独立回滚的交付:稳定业务原因码及增量 parity 门禁、首批真人主链路错误迁移、付款批次实时 readiness 与就近反馈。它不建设统一待办,也不扩展银行付款能力。
|
||||
|
||||
## Requirements
|
||||
|
||||
### R1 稳定原因码与渐进 parity 门禁
|
||||
|
||||
1. 新增服务端业务错误原因注册表。每个原因至少记录稳定 `reasonCode`、业务域、普通用户是否可达、默认安全中文提示/恢复方向;原因码采用 `<domain>.<reason>`,不得复用任意 `details key` 冒充合同。
|
||||
2. 原有 HTTP status、顶层 `error.code` 和兼容 `details` 保持;已迁移错误在 `details.reasonCode` 增加稳定原因码。旧客户端可继续依赖既有字段,新客户端优先消费原因码。
|
||||
3. 新增 parity 检查:已注册用户原因必须有客户端安全映射;服务端使用的原因必须已注册;新增或修改通用校验不得绕过原因码;客户端不得有孤儿/拼写漂移;未知原因走安全兜底且不展示原始 details、内部路径或 UUID。
|
||||
4. 存量通用错误使用版本化遗留基线渐进收敛。例外按业务域/文件组记录原因、负责人、到期日和行号无关的调用指纹;新增指纹默认失败。不得以整目录永久忽略、只比较数量或模糊正则代替指纹门禁。
|
||||
5. 首批真人主链路不得进入例外:报销提交/编辑/票据关联,付款创建/复核/登记,请假提交和考勤修正提交。范围内每个用户可达校验分支必须有注册原因码、准确中文提示和测试。
|
||||
6. 遗留例外是迁移债,不是管理页永久展示技术文案的许可。到期后门禁必须失败;续期需要新理由和明确期限。
|
||||
|
||||
### R2 用户可行动的错误反馈
|
||||
|
||||
1. `VALID_001` 未映射时不得再把服务端的“参数校验失败”直接展示给普通用户。兜底必须说明操作未完成、建议核对页面提示或联系管理员,并附现有 request ID;没有 request ID 时不展示空编号。
|
||||
2. 具体提示必须回答“哪里不满足、下一步怎么恢复”,并位于相关字段、条目或动作附近。页面顶部错误和 toast 只作补充。
|
||||
3. 错误不得只靠红色表达;动态错误使用可访问告警语义。禁用动作的原因必须在按钮附近持续可见,并通过 `aria-describedby` 或等价语义关联。
|
||||
4. 20 处现有测试字符串逐处处置,不用宽泛正则消除失败:客户端 4 处模拟响应改为原因码 fixture;首批主链路改断言 reasonCode、兼容 details 和 HTTP status;非本批路径明确对应遗留例外和到期日;持久化失败摘要/批处理 reason 单独判断兼容性。
|
||||
|
||||
### R3 付款批次实时 readiness
|
||||
|
||||
1. 抽取唯一服务端付款就绪解析器,返回 `{ ready, blockers }`。blocker 使用 `payment_batch.*` 原因码和最小安全定位信息,不返回完整银行卡、密文或原始员工对象。
|
||||
2. readiness 至少覆盖:来源状态/已付款、付款能力部门门禁、活动批次占用、单一公司归属、收款人银行资料、公司付款账户及解密可用性、非制单人的合格经理/CEO复核人。
|
||||
3. 候选列表对单条候选实时计算 readiness;缺资料的记录仍可被发现,但不可选择,并就近显示缺项与恢复责任。财务无员工维护权限时只提示联系管理员,不暴露无权入口。
|
||||
4. 多选付款必须用同一解析器计算组合 readiness,覆盖跨公司、并发占用和复核人等组合条件;不能因为每条单独就绪就推断组合一定就绪。
|
||||
5. 创建接口在事务、必要锁和最新数据下再次调用同一解析器并 fail closed。候选、组合预检和创建不得各写一套判断;并发变化返回同一原因码。
|
||||
6. readiness 每次按当前事实派生,不新增数据库字段、不落库、不长期缓存。资料或账户变化后,下次查询自然反映最新结果。
|
||||
7. 银行转账只按真实资料判断。开户行不是建行时不得建议伪填;是否支持跨行付款属于独立产品能力。
|
||||
|
||||
### R4 付款页面反馈
|
||||
|
||||
1. 正常候选不增加解释性噪音;有 blocker 时在候选行展示精确缺项,复选框不可用且原因可被键盘和读屏取得。
|
||||
2. 已选组合 readiness 位于主动作紧邻上方;阻断时主动作禁用,提示与服务端二次拦截来自同一组 reasonCode 投影。
|
||||
3. 正常银行付款 fixture 保持可选择、可创建并提交复核;新增门禁不得误伤资料与复核人完整的单据。
|
||||
4. PC 是批量付款主路径;移动端不新增复杂组批能力,但已有移动付款路径不得显示原始技术错误或回归。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [x] AC1:存在可机器读取的原因码注册表;同一 details key 在两个业务域使用不同 reasonCode,parity 分别验证,证明不是按 key 虚假覆盖。
|
||||
- [x] AC2:未注册原因、缺客户端映射、拼错 reasonCode、新增无原因码调用、遗留指纹变化、例外过期六类 self-test 均非零退出;正常注册与有效遗留通过。
|
||||
- [x] AC3:报销提交/编辑/票据、付款创建/复核/登记、请假提交、考勤修正提交的用户可达错误为零例外;报告按域输出注册、已迁移、遗留和过期数量。
|
||||
- [x] AC4:未知 `VALID_001` 在 PC/移动显示安全可行动兜底;有 request ID 时展示编号,无编号时无空占位;“参数校验失败”、原始 details、UUID、接口路径不出现在 UI。
|
||||
- [x] AC5:20 处既有测试字符串有逐项处置清单;主链路断言具体原因码/中文,非本批项对应有效例外,无宽泛正则掩盖差异。
|
||||
- [x] AC6:付款单条与组合 readiness 覆盖正常、状态异常、活动批次、缺公司、缺/非建行收款资料、缺/不可解密公司账户、跨公司、无复核人;准确返回原因码,正常 fixture `ready=true`。
|
||||
- [x] AC7:候选、组合预检和创建事务调用同一 readiness 实现;并发变化时创建再次阻断且不生成 batch、item、成功 audit 或通知。
|
||||
- [x] AC8:正常候选无 readiness 噪音;异常候选不可选择且缺项就近可读;组合原因紧贴禁用主动作,toast 非唯一反馈,键盘/读屏语义通过。
|
||||
- [x] AC9:员工资料或公司账户变化后下一次 readiness 立即变化;schema、migration 和持久化 readiness 字段为零。
|
||||
- [x] AC10:用受控 fixture 复现 0014 三类缺项,分别提示所属公司、开户银行/银行卡和渠道限制;不使用或修改真实银行卡资料。
|
||||
- [x] AC11:相关服务端、客户端单元/Playwright、typecheck/build、Prisma validate、UI strict/self-test、Trellis governance、敏感扫描和 `git diff --check` 全部通过。
|
||||
- [x] AC12(部署后):`/ready`、bundle marker、公网文案扫描通过;合成 API/页面证明 readiness 与原因码解析生效。真实资料补录和 0014 重试由授权人员完成,未取得真实证据时不得冒充 PASS。2026-09-05 经用户追加授权,以公网受控管理员对 0014 的真实缺项负向核验确认候选禁用、就近原因和创建 409;未补录资料、未创建成功批次、未执行付款,详见 implement.md 第 11 节。
|
||||
|
||||
## Test Plan
|
||||
|
||||
- 原因码合同:运行 parity strict 检查及 self-test,覆盖注册表唯一性、同一 details key 跨域、未注册原因、缺客户端映射、孤儿/拼写漂移、新增无原因码调用、遗留指纹变化、例外过期,以及首批主链路试图加入例外时 fail closed。
|
||||
- 首批主链路:对报销提交/编辑/票据关联、付款创建/复核/登记、请假提交、考勤修正提交运行 focused 服务端测试;逐分支断言 HTTP status、稳定 `reasonCode`、兼容 details 和准确中文映射,并验证主链路遗留例外为零。
|
||||
- 付款 readiness:用受控 fixture 覆盖正常、状态异常、活动批次占用、缺所属公司、缺开户银行/银行卡、非建行、缺或不可解密公司账户、跨公司、无合格复核人;分别验证单条和组合投影,并以正常 fixture 证明可选择、可创建和提交复核不被误伤。
|
||||
- 事务与实时性:模拟候选读取后事实变化,确认创建事务重新校验、失败时不产生 batch/item/成功 audit/notification;修改受控员工资料或公司账户后重新查询,确认 readiness 即时变化且无持久化字段或缓存依赖。
|
||||
- 客户端与可访问性:逐项处置现有 20 处“参数校验失败”测试命中;断言具体原因就近显示、禁用按钮关联 `aria-describedby` 或等价语义、toast 非唯一反馈、未知原因不泄露 details/UUID/路径,有 request ID 时显示排障编号、无编号时不留空占位;不得以宽泛正则替代精确断言。
|
||||
- 工程门禁:运行相关 server/client 单元测试与 Playwright、`npm run prisma:validate`、前端 typecheck/build、UI strict/self-test、Trellis governance、敏感信息扫描和 `git diff --check`,并确认 schema/migration/seed/flag/routing 与生产数据修改均为零。
|
||||
- 部署后验收:在另行批准部署后核对 `/ready`、bundle marker 和公网文案扫描;仅用合成 API/页面样本验证三类 0014 缺项、正常付款路径及 B2/maker-checker 回归。真实银行卡资料、0014 建批/复核/登记必须由授权人员操作;缺少真实链路证据的项目明确记为 BLOCKED 或待自然样本验证,不以合成测试冒充 PASS。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 统一首页待办、通知推导和角色行动项模型;等待真实付款链路记录后另行规划。
|
||||
- 一次性迁移全部 365 处通用文案或 518 个调用文本;非首批路径只建立可到期遗留基线。
|
||||
- 支持跨行付款、银行直连、自动付款,或改变 maker-checker、付款角色、复核规则。
|
||||
- 自动补录或读取生产员工公司、开户银行、银行卡号和公司账户。
|
||||
- 修改业务状态机,新增 schema/migration/seed/flag/routing。
|
||||
- 把完整 details、payload、UUID、账号或内部路径写入日志、任务材料或普通页面。
|
||||
|
||||
## Risks and Deferred Items
|
||||
|
||||
- 静态扫描只证明合同登记;focused 分支测试证明真实返回,二者缺一不可。
|
||||
- 单条与组合 readiness 语义不同;只做前者仍留下跨公司等点击后失败路径,因此组合预检是必交项。
|
||||
- request ID 可帮助定位,但当前 AppError details 不进服务端日志。是否增加脱敏 reasonCode 日志另行评估,本任务不记录原始 details。
|
||||
- 0014 只证明资料未维护,不证明员工没有建行卡;真实开户行由本人和授权管理员确认。
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"id": "error-explainability-payment-readiness",
|
||||
"name": "error-explainability-payment-readiness",
|
||||
"title": "错误可解释性与付款就绪治理",
|
||||
"description": "建立稳定业务错误原因码与渐进 parity 门禁,并以付款批次实时 readiness 消除点击后才暴露的资料阻断。",
|
||||
"status": "completed",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P0",
|
||||
"creator": "shunli",
|
||||
"assignee": "shunli",
|
||||
"createdAt": "2026-09-05",
|
||||
"completedAt": "2026-09-26",
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": "a83791263833547fdab7ba6910f190fcccd5e34b",
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [
|
||||
"server/src/routes/paymentBatches.js",
|
||||
"server/src/utils/AppError.js",
|
||||
"client/src/api/errorMessages.ts",
|
||||
"client/src/lib/resolveErrorMessage.ts",
|
||||
"client/src/pages/PaymentBatchesPage.tsx",
|
||||
"scripts/qa"
|
||||
],
|
||||
"notes": "2026-09-17当前:G8保留路径错误合同已收敛,520入口处理503、排除ERP17;1093最终合成与构建证据保持、独立PENDING。后续本轮只确认B34损坏导入、D15低年份和D16 AP反向区间;9导入探针DB零调用,6损坏文件仍500/CSV日志含合成标记,修复方案已落design但未实施;工资待精简不补、统一考勤年份规则待定、AP原语义保持且73回归通过。旧D12待实施/589余额属于历史记录,不再作为当前状态。\nD10/D11接续:6源日期schema,9文件61/61;旧考勤保持409关闭。D12仍待独立输入策略,前批17文件520结果有效。\n2026-09-17连续本地:D5-D9/CSV日期时区修复及9原因,17文件520通过、前端typecheck/build通过;589遗留/568指纹,独立PENDING,未提交发布。新日期D10-D12见implement。\n2026-09-17继续推进已落盘D1–D4:待办dueDate、员工目录/导出hireDate、节假日批量及仪表板/AP导出日历校验共4个源文件本地完成,11文件192项定向测试及10文件语法通过。原B1/B2的450项/typecheck/build为上一输入结果,不计本轮。AST仍240注册/327迁移/598遗留、577条基线entries、主链例外0,2026-10-05到期保持。官方current仍本task/in_progress;新候选独立复核PENDING,未提交/推送/部署,K1/K2及借款实施未执行。最新入口implement顶部,保留历史commit锚点。 2026-09-26 与主线合并:主线此前独立完成的\"首批4个\"迁移(ap_operations/todo/portal)已被本分支更完整的版本取代(命名不同但语义一致),794条新增reasonCode、baseline清零,二者不重复保留。",
|
||||
"meta": {}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户