## 2026-10-07 SR-A / SR-B 收尾与提交授权 用户明确批准“先收尾 SR-A/B,本地提交;S4 另批”。本次将下方 15 项实现、测试及文档作为一个本地提交收口,沿用已完成的运行时验证,收尾只更新记录并重验任务治理及差异格式。未推送、未部署、未查询生产。当前 inline 模式下独立复核仍待完成;界面留在 S8,真实回单待验,不能单独部署启用。整体任务保持进行中,不归档;以下“未提交”和 HEAD 描述为实施验证时点的记录。 ## 2026-10-07 SR-A / SR-B 本地实施(用户批准;未提交、未推送、未部署) - [x] 新增恢复轮次、不可变送审/复核字段、决定事件、材料修订号及数据库保护(增量迁移 `20261008020000_loan_release_recoveries`)。既有银行终态与依据不改,已释放/已结清分配保护不放宽。 - [x] 新增发起、送审、独立复核、撤回、状态查询接口;终态事实登记只在最新轮次为补证中时开放。`confirmed_failed` 的恢复使用完整逐提交证据,不覆盖原失败核验引用。 - [x] 最终取消消费最新批准;发起过恢复后不回退原取消路径。材料/候选变更拒绝,失效轮次可取代重提;重复取消请求只返回原结果,不重复释放。 - [x] 数据库材料触发器覆盖导出、提交、清单、终态证据/事实、归属、回单、核验和人工录入,后台 OCR 也推进修订号;候选形成锁出借人,取消与对账接口遵守同一锁顺序。 - [x] 新恢复接口只返回业务标识和状态;存储快照使用标识及摘要,不存解密账号。数据库 JSONB 会调整键序,摘要实现已改为递归按键排序;真实数据库往返测试已覆盖。 - [x] 全流程 HTTP 用例新增独立 fixture,涵盖两种原终态、同一交易换回单、待定事实了结、补登提交、自审、离职、过期重提、物理文件摘要、等待期、回滚与幂等,以及最终释放对证据/提交/OCR落库/其他候选的两种确定性交错。 - [x] 主会话完成本轮差异的只读检查;7 个变异在隔离源码副本中全部被测试抓住,未改工作区被测源码。最后迁移/约束加固后,重新执行含浏览器的隔离回归,78 迁移、HTTP 72、浏览器 7、数据库约束 9 组全部通过,容器清理 PASS。 最终验证:78 个迁移、HTTP 72 组、既有浏览器 7 组、数据库约束 9 组通过(均为隔离容器、合成数据);UI 规则、错误码合同、敏感扫描、前端类型检查及构建通过。服务端全量首跑 4470 通过、6 失败、1 跳过;6 个失败均为 BIFF8 Python 依赖缺失,按仓库锁定 requirements 在临时 venv 补齐后,涉及两个文件的 146 项全部通过,合并覆盖为 4476 项通过、1 项原有跳过,不声称重新跑过一遍完整套件。 变异证据(7/7):移除恢复轮次门禁、旧结论取消旁路拦截、快照新鲜度、恢复发起人独立性、完整释放条件、物理文件摘要、取消重试请求身份。快照/完整条件/物理摘要/轮次门禁/重试身份移除后出现本应拒绝却返回 200 的响应;旧结论旁路与自审移除后,数据库仍阻止非法操作,但返回 500 而非约定的 409/403,反例抓住了错误响应,**不能表述为这两处变异已经绕过数据库并错误释放**。测试结束校验被变异的工作区源码摘要未变,副本和各次隔离容器已清理。 数据库加固还覆盖:新增轮次的初始字段必须为空、序号/前轮与原银行依据一致;修订号不能回退或删除;送审快照不能在取代时顺便篡改;直接释放但未消费最新恢复批准,提交事务会失败。主会话检查范围为恢复状态机、六个接口、取消消费者、材料触发器、独立性与快照、物理证据读取、迁移和前后端错误码;不替代独立复核。 复现命令(`PAYMENT_ORDER_PYTHON_BIN` 指向按 `server/requirements/payment-order-biff8.txt` 安装的测试 venv): - `RUN_ISOLATED_LOAN_DB_TEST=1 RUN_ISOLATED_LOAN_BROWSER=1 node scripts/qa/test-company-loan-db.cjs`。 - `cd server && npm run prisma:validate && npm run prisma:generate`;`npm test`;依赖补齐后的定向命令为 `npm test -- tests/unit/routes/paymentBatches.reimbursement.test.js tests/unit/services/paymentOrderXls.test.js`。 - `cd client && npm run typecheck && npm run build`;`node scripts/qa/check-error-reason-contract.mjs`、`node scripts/qa/check-ui-design-rules.mjs`、`node scripts/qa/check-sensitive-content.mjs`。 工作区:共 15 项未提交(含 1 个新迁移、1 个新服务和 1 个新 HTTP fixture),HEAD 仍为 `14aee82d`;本轮没有提交、推送或部署。文档注册审计退出 0,但保留原有 22 个未登记文件告警;任务/治理/流程合同与 `git diff --check` 通过。 边界:SR-C 界面随 S8,本轮浏览器 7 组是既有流程回归,**不是新恢复界面验收**。S0、真实建行样本、S4–S8 与独立复核仍未完成;未查生产。受 inline 限制,本轮主会话直接实施与检查,没有另派独立 reviewer,不报告“独立复核通过”。应用不得单独部署启用。本轮未执行生产迁移或回填,未恢复/重置任何既有数据库;QA 只创建并清理本次拥有的隔离容器。 ## 2026-10-07 SR 补证后恢复设计接续(仅设计,未实施) 用户同意下一步先设计补证后恢复。本轮沿既有任务完成 design 顶部 SR1–SR6、PRD AC17–AC19;不执行 S4–S8,不修改资金代码或迁移,不查询生产、不提交推送部署。S3 已本地提交 `14aee82d`;下方 S3“未提交”等文字保留为历史时点。 本轮清单: - [x] 核对 S3 终态、终态事实登记及最终取消入口,确定补证被 `unknown` 限制卡住;设计保留终态、另建恢复轮次。 - [x] 写明适用范围、逐事实与整轮独立复核、材料失效、最终释放、并发、回滚和 S6/S8 边界。 - [x] 同步 PRD 的恢复验收条件(未勾选通过)。 - [x] 主会话按 `trellis-check` 完成文档一致性自查;任务 validate、Trellis 治理(含敏感信息扫描)、流程合同 baseline、`git diff --check` 通过。文档注册审计退出 0,报告 22 个未登记 docs 文件的告警;本轮未新增或修改 docs 文件,不扩展处理。未跑数据库、HTTP、浏览器或变异测试,未进行独立复核。 - [ ] 方案审阅及后续代码实施授权;本轮无资金代码实现或运行时通过结论。 方案批准后的执行切片(本轮不执行): | 切片 | 内容 | 依赖与验收 | |---|---|---| | SR-A 数据与补证 | 增量迁移、恢复轮次/送审/决定、材料修订号;只对有效恢复轮次开放终态补证;保护原终态 | S3;AC17;迁移约束、补证往返、多轮取代、历史记录不可改 | | SR-B 复核与释放 | 全量证据快照、逐事实与整轮权限、最终取消消费批准;覆盖相关写入口锁序 | SR-A;AC18/AC19;HTTP 正反例、失败回滚、并发、关键资金守卫变异 | | SR-C 界面与收口 | 接入 S8 详情,PC/手机补证→独立复核→取消;旧记录与新资格并列 | SR-B 与 S8;不得因本地后端完成提前部署;整体测试与只读复核另报 | 定向测试矩阵: - 两种原终态分别走“旧证据失效→发起恢复→上传新证据→逐事实复核→送审→独立复核→取消”,本金不减少,占用仅最后释放。 - 同一流水号重新上传/重新 OCR、清单新增再撤回、归属候选新增、批准后证据作废;旧批准拒绝,重新补证复核可恢复。撤回或驳回恢复不能走原取消旁路。 - 补登遗漏的第二次提交,少任一终态即拒绝;终态只能了结同指令处理中回单,成功事实始终阻断;Q6、未知文件、历史汇总、编号不符均不能代替证据。 - 刚导出时确认与最终取消均拒绝;等待期满才放行;无导出沿现有规则,不为补证另设等待期。 - 自审、多角色自审、旧上传/录入人换身份参与复核、当前人员离职被拒;原审批人/出借员工事后离职不拦按冻结快照登记事实。 - 最终释放分别与证据作废、OCR 核验落库、提交变化、同出借人新候选形成按两种顺序确定性交错;不得靠概率跑圈。释放先行后的新银行事实交后续对账,不宣称已处理。 - 最终事务在分配更新、批次取消、消费批准、审计处注入失败均全回滚;重复请求不重复释放;已释放/结清不可重开,恢复任何阶段不可导出/执行付款。 验证安排:设计阶段仅跑文档/治理校验与 `git diff --check`;代码阶段才跑隔离数据库/HTTP/浏览器及变异,按影响范围回归。inline 主会话审查不冒充独立只读复核。没有已验证的通用新工程规则,本轮方案先留在任务,不提升为模块既定规约。 ## 2026-10-07 S3 本地实施记录(用户批准本地实施、针对性验证与只读复核,并要求纳入三条补充要求;未提交、未推送、未部署、未查询生产) 迁移 `20261008010000_loan_bank_terminal_facts`: - `loan_bank_terminal_evidences`:银行终态证据(银行书面回复、网银指令查询官方 PDF 等)**单独成表**,与付款回单分开。它不进入 OCR,上传不改变付款状态,不计入回单核验数量和作废回单判定。证据只能作废一次;作废后,依赖它的终态事实在同一事务内被取代。付款回单无法改成这一类型,因此不能借更换类型来解除成功或处理中回单的阻断。 - `loan_bank_terminal_facts`:每次银行提交至多一条待复核或已通过的终态事实,分两类—— - `termination_evidence`:终态为已拒绝、已撤销或已失败; - `failure_receipt`:严格判定的失败回单,且回单流水号必须等于该提交登记的指令号。 `resolves_attachment_ids` 用于列出由这条终态事实了结的处理中回单。这些回单必须是本批次付款的单页处理中回单,且流水号等于该提交的指令号;其他提交的终态事实不能代替。终态事实只增不改,复核人须独立。 - 还款状态新增 `confirmed_not_paid`:终态,必须带依据,可取消释放。完整性函数和历史保护函数原样重建,只加入这个状态。 规则: - 银行指令号登记时规范化(NFKC、去空白、大写)保存,且同一指令号不能同时登记在两个借款批次。 - 释放条件 `assertNotPaidReleasable`,以下全部满足才可释放: - 无历史汇总; - 提交清单已复核且至今未变; - 每次有效提交都有已复核、当前仍成立的终态事实; - 每条导出记录都被某次提交关联; - 本批次每份付款回单要么被终态事实覆盖,要么是能证明为明确失败或他笔付款的作废回单; - 距最后一次导出已满内部等待期(默认 3 天,可配置)。 - 经独立复核人确认后,状态转为 `confirmed_not_paid`。 - 内部等待期适用于全部释放路径:确认未付款、单次失败确认,并在最终取消时重验(2026-10-07 复核补:单次失败路径原先漏了这一项)。 - **最终取消时在同一事务内重验**:`confirmed_not_paid` 重跑上述全部条件,`confirmed_failed` 重跑单次失败路径的全部条件。取消、上传回单、登记提交都要先锁批次,因此三者串行执行。 - 在失败或未付款结论之后上传的晚到回单,仍会被记录(状态不变),并因此阻断释放;释放之后才出现的新证据,留给晚到结果对账流程处理。 - 单次失败路径同时补上导出关联:有导出记录时,提交必须关联该导出(`loan.export_unlinked`)。 - 新增 8 个原因码,三处都已登记;新增接口包括证据的上传与作废、终态事实的登记与复核、确认未付款(复核人操作)。 页面:仍未实施,留待 S8。**不得单独部署启用。** 验证与复核: - 首轮针对性验证:HTTP 49 组、浏览器 7 组、77 迁移;11 个资金守卫变异均变红;server 4471 等通过。 - 同模型只读复核:BLOCK,三项(前两项经复核人副本探针实测),均已修复: - B1 已登记银行提交但状态仍为 `not_sent` 时,可单人直接取消释放:登记提交时同一事务内转为 `unknown`;取消路径的 `not_sent` 分支另加防线,只要存在任何提交(含已撤回)、历史汇总或终态证据就拒绝。 - B2 `failure_receipt` 终态事实绕过同金额失败归属、未做交易唯一性检查,同一笔失败交易可能分别让两个批次释放: - 失败回单分支复用单次失败路径的检查(不得被认领为付款、密钥一致); - 存在同金额候选时,须有已复核、只覆盖该次提交的失败归属。归属新增 `failure_scope`(batch/submission),唯一性改为“批次+类型+覆盖提交”; - 新增只增不改的 `loan_failure_evidence_uses`:一笔失败交易只能作为一个批次的依据,单次失败路径和终态事实路径都在此登记,复用返回 `loan.failure_evidence_reused`。 - B3 终态证据无法查看:新增 `GET …/loan-terminal-evidences/:id/file`,财务或合格的独立复核人可读,须填写理由并写审计,返回前校验 SHA-256,不缓存。 - 同轮非阻断修复: - 结论已定或批次已释放后,导出、执行由 500 改为明确的 409; - 释放后不得作废证据; - 同一批次内指令号也须唯一。 - 第二轮同模型只读复核:BLOCK 一项(副本探针实测),B1、B3 修复成立。 - **N1**:单次失败路径不比对失败回单流水号与本批次指令号;只登记了提交的批次也不算同额候选,于是 A 可凭 B 指令的失败回单确认失败并释放。已修: - 单次失败路径(确认与最终取消均调用 `assertFailureFacts`)及批次级失败归属,都要求失败回单流水号等于唯一已确认提交的指令号(指令号跨批次唯一); - 同额候选新增“存在任何提交登记(含撤回)”。 由于有了指令号绑定,跨批次复用失败回单在归属阶段就被拦下,`loan_failure_evidence_uses` 登记表退为纵深防御(测试断言 A 已登记用量)。 - 同轮修复的非阻断项: - 归属唯一索引与查重加入 `failure_scope`,批次级与提交级可并存,并加 CHECK:提交级必须是失败类、只覆盖一次提交; - 单次失败路径按覆盖提交精确查找批次级归属; - uses 表纳入回单密钥一致性检查; - 证据查看理由改由请求头 `x-access-reason`(URL 编码)传递,不进入访问日志。 - 新增反例:其他批次指令的失败回单走单次路径被拒,且“只登记提交”的批次算作候选;批次级与提交级失败归属并存。 - 第三轮同模型只读复核(N1 修复):PASS_WITH_NOTES,无阻断;四条路径(单次失败、批次级与提交级失败归属、failure_receipt 终态事实)绑定一致。按备注补两处纵深: - 指令号跨批次唯一改为不论状态:撤回后也不能在其他批次重新登记; - 同一份银行书面证据(按 SHA-256)不能上传到两个批次。 记录: - 候选范围扩大(只登记提交也算)的代价是同额历史批次让后续批次持续需要归属确认,方向安全,不放宽; - **回单“流水号/凭证号”与网银指令号是否同一编号、两者如何对应,须用真实建行回单在 S0 核实**。若不同,受影响的是需要绑定的路径——失败回单(单次失败路径、失败归属、`failure_receipt` 终态事实)以及处理中回单的了结,这些路径会被阻断(安全但不可用);只凭银行书面终态证据(`termination_evidence`)、本批次又没有需要了结的处理中回单时,不要求两个编号相等,不受影响。归属不能靠财务照抄回单号来证明;绑定只是机器校验,实际证明仍依赖银行证据、同额候选归属和独立复核。 - 部署前注意(存量):生产若已有在 S1 之前确认失败、尚未取消的借款批次,按新规则取消时会重跑 S1 条件(单次已复核提交、指令号绑定等),可能需要补登提交并复核;生产是否存在此类数据待 S0 核实。 - 记录在案(未改): - `confirmed_not_paid` 之后若证据作废、出现晚到回单或新提交,批次保持占用(方向安全)。其中“钱确实没付、只需补证后重新复核”的情况,会被“只有 `unknown` 状态才能登记终态事实”拦住;S6 只处理晚到成功,覆盖不了这种情况。**这是尚未设计的恢复缺口**,需另行设计恢复路径,不由 S6 负责; - 等待期默认 3 天,可通过配置 `loanReleaseWaitDays` 调整,尚未接入环境变量;只有手工提交、没有任何导出时,等待期不生效(按设计“距最后一次导出”计算)。 ## 2026-10-07 S1、S2 本地实施记录(用户 2026-10-06 批准本地实施、针对性验证与只读复核;未提交、未推送、未部署;未做 S0 生产查询) S1(迁移 `20261007010000_loan_bank_submissions`): - 新表 `payment_order_exports`:借款批次每次导出写一条(序号、导出人、文件 SHA-256、客户方流水号、金额),只增不改。 - 新表 `loan_legacy_export_summaries`:迁移时回填存量借款批次已知导出次数,写明未知项(逐次明细、文件摘要、银行提交对应关系)。它不是一次真实导出或提交;存在时确认失败一律 409 `loan.submission_history_unverified`。 - 新表 `loan_bank_submissions`:财务登记实际银行提交(网银导入须关联本批次导出记录),只能撤回一次,不能改。 - 新表 `loan_bank_submission_attestations`:财务确认“现有有效提交即全部”,独立复核人须当前有资格,且不是确认人、批次创建人、提交人、出借员工、任一导出人或提交登记人;清单变化后旧确认失效,重新确认时同事务取代。 - 确认失败:只计未作废附件(须恰为所确认的失败回单);作废附件曾被识别为成功或处理中、曾匹配、或有未驳回的人工录入,一律 409 `loan.voided_receipt_unresolved`;临时拦截(S3 前)——存在历史汇总、多于一条导出记录或多于一次有效提交、提交清单未经复核或已变化,均拒绝;改按付款后规则(出借员工离职不阻断,确认人按当前资格)。 S2(迁移 `20261007020000_loan_failure_attribution`): - 归属确认新增 `kind`(settlement/failure)与 `covered_submission_ids`;每批次每类至多一条待复核或已通过;依据类型新增“回单载明本批次银行指令号”。 - 存在同金额候选时,确认失败须有已复核、绑定失败回单证据与已确认提交清单的失败归属,否则 409 `loan.receipt_attribution_required`;失败归属登记前须先有已复核的提交清单。结算归属的查询全部限定 settlement 类,两类互不占位。 接口:`POST /payment-batches/:id/loan-bank-submissions`、`…/:submissionId/withdraw`、`…/loan-submission-attestation`、`…/:attestationId/review`;归属接口新增 `kind`、`attachmentId`;批次详情返回 `bankSubmissions`。新增 7 个原因码,三处登记。 页面:本步未做提交登记、清单复核和失败归属的界面(S8 页面整合)。**S1 收紧了确认失败,界面补齐前不得单独部署启用。** 验证与复核: - 首轮针对性验证:HTTP 39 组、浏览器 7 组、76 迁移 PASS;9 个资金守卫变异均变红(其中“去掉清单复核要求”首轮未变红,因缺“已登记未复核”反例,补后变红)。 - 同模型只读复核:BLOCK,两项,均经副本实验复现。已修: - B1 作废回单判定过宽(作废时尚未 OCR、状态不可读、状态歧义都会放行):改为“无法证明就拦截”。作废附件只有在当前版本识别为明确失败,或可读且确定不是本笔付款(金额/账户与本批次不符、无处理中或歧义标记)时才忽略;没有核验记录、未识别、状态不明、匹配过或有未驳回人工录入,一律 409。代价:无法识别的误传文件也会阻断,须以可读证据处理(留待 S3 作废复核或线下补证)。 - B2 清单批准后“登记再撤回”会让旧批准重新生效:清单确认新增 `all_submission_ids`,绑定全部提交行(含已撤回)及全部导出,复核后的任何登记、撤回、导出都使批准失效,须重新确认并复核。 - 同时补:确认失败人与失败归属复核人另排除全部导出人、提交登记人与清单确认人;清单复核人另排除已撤回提交的登记人;失败归属数据库层限定恰一条核验记录。 - 修复后:HTTP 40 组、浏览器 7 组、76 迁移 PASS;修复对应的 5 个变异均变红(“忽略歧义状态标记”首轮未变红,补“标记失败但带处理中”反例后变红);server 4463、prisma validate、client typecheck/build、UI strict、错误码合同、敏感扫描、diff 检查通过。 - 第二轮同模型只读复核:PASS_WITH_NOTES,无阻断,B1、B2 修复成立。按其意见加固:作废回单要判为“确定不是本笔”,须匹配结果明确不符、金额大于 0,且付款与收款账号不能都与本批次一致(同账号仅金额不同可能是本笔误读,继续阻断);作废回单逐页核对页数完整;补数据库层反例(清单确认的全部提交、导出集合不可改,已撤回提交不能恢复)。“同账号放行”变异变红。最终:HTTP 40 组、浏览器 7 组、76 迁移,server 4463 等全部通过。 - **既有问题(第二轮复核发现,自 09-06 即存在,方向为拦截;已按下条口径修复)**:真实 OCR 只要页面带任何问题标记就整体判为 `needs_review`,失败回单必带 `transaction_failed`,而 `failedReceiptFact` 要求 `recognized`。因此用真实 OCR 时“确认失败”永远返回 409,作废失败回单的放行分支也是死代码。测试夹具伪造了真实识别器不会产出的“已识别且带失败标记”结果,正向用例没有覆盖真实路径。修正需定义失败回单的识别口径(如仅允许唯一问题为 `transaction_failed`),属资金规则,待用户决定;在此之前生产中任何银行失败都无法在系统内确认。 - 失败回单识别口径(用户 2026-10-07 同意并入 S1/S2,口径为 4 种失败措辞): - 归一化新增 `transactionStatusRaw`(银行原始状态措辞),随核验结果存储;匹配逻辑不变,报销与成功核销不受影响(相关共享单测 237 项通过)。 - 不改顶层识别状态。失败事实另用严格判定 `isClearBankFailure`:单页且页数完整;状态为失败且原始措辞属于“交易失败、转账失败、付款失败、支付失败”;唯一问题标记为 `transaction_failed`;金额、币种、双方账号、流水号齐全;再经与冻结快照匹配。它只用于确认失败,不能用于成功核销,也不绕过提交清单、失败归属与独立复核。“已撤销”“已冲正”“已退汇”不接受,分别留给 S3 指令终态与后续退款对账流程。作废回单中的失败页也按同一判定,否则继续阻断。 - 测试改走真实处理链:只替换云端 `BankSlipOCR` 响应,从合成银行字段经 PDF 解析、`recognizePaymentReceipt`、`normalizeBankSlip`、核验存储、匹配与认领。仅两个纵深防御用例显式使用合成归一化结果(作废路径“失败但带处理中标记”、确认路径“失败但另带账号歧义标记”),二者真实归一化无法产出。新增用例:“转账失败”可确认;“已撤销/已冲正/已退汇”、缺流水号、两页回单、金额不符、带额外问题标记均拒绝;作废的“已撤销”回单继续阻断。 - 变异:接受任意失败措辞、要求顶层 recognized、作废失败页不按严格判定三者变红;“忽略多余问题标记”“跳过字段完整性”未变红——下游 `matchBankSlip` 对任何剩余问题或缺失字段都会判不匹配,二者为纵深防御,测试无法单独区分。 - 结果:HTTP 41 组、浏览器 7 组、76 迁移,server 4463、client typecheck/build、UI strict、错误码合同、敏感扫描、diff、治理检查均通过。真实建行回单接受性仍待验。 - 只读复核(同模型):BLOCK 一项——同页两个状态字段(如“交易失败”与“已撤销”,都归一化为失败)不被判歧义,原始措辞只取首个字段,按 OCR 字段顺序可绕过白名单(复核实验证实)。已修:仅当所有状态字段原文完全相同时才记录 `transactionStatusRaw`,否则为空即拒绝;`transactionStatus` 与问题标记不变,报销与成功匹配不受影响。补用例:两种字段顺序的“失败+已撤销”均拒绝、作废的“失败+已撤销”回单继续阻断、“付款失败”“支付失败”正向用例。其余检查(原文可靠性、严格判定、成功路径未放宽、测试走真实链)复核成立。 - 复核其余非阻断(留待 S3/S8):导出记录未被手工提交关联时仍可确认失败(S3 须落实每条导出都关联已终止提交或人工确认未提交);失败归属状态与提交登记、清单复核无界面;部分反例未覆盖(导出失败时导出记录回滚、回填 SQL 在有存量时的效果、报销导出不写导出记录)。 ## 2026-10-06 对账方案实施拆分(依据 design 第 3 版;待用户批准,未实施) 通用规则: - 每步只做新增型迁移,均涉及资金规则,完成后必须只读复核。 - 每步可单独验证、单独提交,但**不代表可以单独部署启用**。部署时机另行批准,提交须单独确认。 - 验证按改动范围安排:相关的数据库、HTTP、权限与并发回归,加上针对资金守卫的变异测试;改到共享付款路径时扩大回归;阶段完成后再跑完整前后端测试。 - 完整的释放条件在 S3 之前尚未实现,所以 S1、S2 不得放宽任何释放结果,只能修正误判并保留拦截(见 S1 第 3 条)。 | 步骤 | 内容 | 对应 | 依赖 | |---|---|---|---| | S0 前提核实(不写代码) | ① 生产有无真实还款与存量批次(只读查询须用户当轮授权);② 是否至少有 2 名与单据无关、当前有资格的经理或总经理;③ 建设银行能否出具“指令查询”官方 PDF,含查询无结果的情况(用户线下确认)。三项均不默认为已满足;不阻塞本地合成开发,但②③决定 S4 能否启用,①为上线前必须完成的存量核实 | AC16、AC12 | — | | S1 导出与提交记录、确认失败修正 | 1. 新增制单导出记录表(序号、时间、导出人、文件摘要、客户方流水号、金额、快照摘要),每次导出写入。
2. 新增银行提交尝试登记(财务登记,关联导出记录与银行指令号),提交清单须经独立复核。
3. 确认失败:只计未作废附件,但作废的成功或处理中回单仍阻断;**同时保留拦截**——批次存在多于一条导出记录、提交清单未经复核、或清单中不止一次提交时,一律拒绝确认失败,留待 S3 的逐次终态规则处理。
4. 确认失败改按付款后规则:核对冻结快照,不要求出借员工在职,当前操作人按当前资格。
5. 存量:保留已知的 `payment_order_export_count`,新增“历史导出汇总”标明逐次明细、文件与银行提交对应关系待核实;该汇总不是一次真实导出或提交,存在它的批次在确认失败与释放时按“提交未明”拦截 | R2、R4、AC9、AC16 | — | | S2 失败归属 | 归属确认新增 `failure` 类,须写明覆盖的银行指令并绑定失败回单证据;存在同金额候选时,确认失败须有已复核的失败归属,否则保持占用;S1 第 3 条的拦截继续有效 | R3、AC10 | S1 | | S3 银行终态确认与释放 | 新增 `terminated` 类与 `confirmed_not_paid` 状态(含触发器);释放条件:已复核提交清单中每一次提交都有覆盖它的终态或失败证据,每条导出记录都关联已终止的提交(或有 S4 的人工确认),且无未解决的成功或处理中事实;之后取代 S1 第 3 条的临时拦截;释放后禁止再导出,页面提示原制单文件不得再导入网银 | R1(银行确认)、AC11 | S1、S2 | | S4 人工确认未提交(Q6) | 新增 `not_submitted` 类与 `confirmed_not_submitted` 状态;全部证据加两名不同的独立复核人;记录与页面标为人工确认;人员不足或材料缺失时继续占用 | R1(人工例外)、AC12 | S3;能否启用取决于 S0 ②③ | | S5 冻结原因与解冻 | 新增冻结原因表(类型、来源、状态、关闭依据);冻结拦截该出借人的新申请,以及其他在途申请的复核与导出,放行事实登记;误报原因经独立复核关闭;全部原因关闭才解冻 | AC13 | —(S6 的前置) | | S6 晚到成功补记 | 晚到事实只增不改、标记原结论被推翻;登记即产生冻结原因;按冻结快照与历史审批核对;逐笔先处理占用冲突,再按差额结清,余额生成待追回原因;补记还款不生成付款批次、不可导出;覆盖已释放与已确认失败未释放两种情况 | R5、AC14 | S3、S5 | | S7 追回与解冻 | 凭到账回单经独立复核登记追回,支持部分追回,全额后关闭对应原因;本期不支持冲抵 | AC15 | S6 | | S8 收口 | 页面整合与手机端走查;恢复手册补充;完整前后端回归;把 AC9–AC16 的验证结果与剩余缺口回填到 PRD 与本文件 | 全部 | S1–S7 | ## 2026-10-06 C 回单批次归属保守拦截(用户批准实施;本地合成,未提交、未部署) 规则:同一出借人、同金额的其他借款批次只要曾导出制单或上传回单(含确认失败后已取消的),本批次的匹配回单就不能证明归属。 - 最终拦截在 `settleLoanRepayment`(`assertReceiptAttributed`):执行事务内 `claimVerifiedReceipts` 已为本项生成交易指纹认领,OCR 匹配与已通过的人工回单复核都经过此处;只有绑定同一交易指纹、且覆盖当前全部候选批次的已复核归属确认才能放行,否则 409 `loan.receipt_attribution_required`,本金与占用不变。 - 确认银行失败:存在候选批次即 409,不释放占用(失败回单暂无归属确认路径,留待对账流程设计)。 - 归属确认与人工回单复核分离(新表 `loan_receipt_attributions`,迁移 `20261006010000_loan_receipt_attribution`):财务登记依据类型(客户方流水号、附言含批次号、银行书面查询结果、其他候选均已对应其他交易或确认未付;不含“时间吻合”)+ 依据说明 + 排除其他候选的理由;绑定 `claimVerifiedReceipts(readOnly)` 计划认领的交易指纹和当时候选集合。独立复核人须当前有资格,且不是登记人、制单人、提交人或出借人关联员工;批准时回单证据或候选集合变化即拒绝。出现新候选后原批准失效。DB:每批次至多一条待复核/已通过(部分唯一索引)、复核人≠登记人、已复核记录与提案字段不可改、禁止删除。 - 页面:还款详情显示候选批次与归属状态,财务登记、经理/总经理独立复核;说明“时间吻合只能作辅助说明”。 - 代价:此后同一出借人同金额的正常还款(如固定金额分期)都需走归属确认。精确关联(附言写入批次号、OCR 提取客户方流水号/附言)待获准的真实建行回单样本确认字段后再做。 验证: - `RUN_ISOLATED_LOAN_DB_TEST=1 RUN_ISOLATED_LOAN_BROWSER=1 node scripts/qa/test-company-loan-db.cjs`:74 迁移,HTTP 27 组、浏览器 5 组、DB 约束全部 PASS。原两个复现用例改为回归断言:错误回单执行 409 且本金/占用不变;C2 经 OCR 与经人工回单复核均被拦。新增:正确回单在有候选时同样需归属确认、确认后核销成功;重复登记 409;“时间吻合”类型 400;登记人兼经理不能自审、驳回后仍拦;新候选出现使批准失效;歧义失败回单不能释放;无候选时不需也不接受归属确认;已复核记录 DB 层不可改/删。 - 5 个变异(去掉核销拦截、候选排除已取消批次、去掉失败拦截、覆盖校验恒真、允许登记人复核)均变红,源码已恢复。 - server 4456 通过;prisma validate、client typecheck/build、UI strict、错误码合同通过。 - 首轮同模型只读复核:BLOCK——已批准的归属一旦因新候选或换回单失效,既不能重新登记(exists)、也不能改(触发器)、又因已导出不能取消,占用永久卡死并阻塞出借人维护(复核人副本实测成立)。已修:新增终态 `superseded`(及 `superseded_at`),重新登记时同一事务内把失效的待复核/已通过记录标为已取代;触发器只放行 proposed→approved/rejected/superseded 与 approved→superseded,复核字段不可改。同轮按非阻断意见补:复核人另排除导出制单人与所认领回单的上传人;`receipt-readiness` 在需归属确认时返回 `ready:false, receiptAttributionRequired:true`;状态返回 `stale`(回单或候选已变化);页面在失效时允许重新登记、财务按钮要求 `loan.manage`,并写明同额分期每期都需确认、存在同额候选时失败回单不能释放额度须线下对账。新增回归:失效批准被重新登记取代后核销成功;换回单后旧批准不能放行、导出人兼经理不能复核、重新登记后核销成功;已通过不能改为驳回、已取代不能复活。3 个变异(不取代、复核不排除导出人、就绪不检查)均变红。 - 第二轮同模型只读复核:PASS_WITH_NOTES,死局已解除,无阻断。按其意见加固:复核人另排除同一交易所有回单的上传人及人工回单提案人;驳回不再依赖回单(无回单时待复核记录可关闭);无已核验回单时登记返回 `loan.receipt_attribution_unavailable`,状态返回 `receiptAvailable`,页面不显示无效的登记按钮;批次详情中的归属展示在回单重建异常(如密钥不一致)时降级而非 500;触发器禁止未复核记录写入复核字段;取代审计记录原因(交易变化/候选变化)。新增回归:人工回单提案人不能复核归属、独立人员批准后核销;回单作废后待复核记录可驳回、重新登记返回 unavailable。 - 后续项(第二轮非阻断 5):存在同额候选且银行确实失败时系统内无释放路径,需设计线下对账结论回写(如复用归属复核确认失败),与 unknown 解除、作废附件计数、晚到结果一并处理。 - 复核其余非阻断(未处理,记录):已执行的历史同额批次永远是候选,等额分期从第二期起每期需确认,且一旦银行真实失败将无法确认失败、释放占用(与“失败归属/对账流程”一并后续设计);部分唯一索引、CHECK、触发器不在 Prisma schema 中,今后 `migrate dev`/diff 可能误报漂移(推测,仓库已有 r46 先例);`ON DELETE RESTRICT` 使带归属记录的批次/员工无法物理删除(当前无此路径)。 - 第三轮补齐(用户转述的复核意见指出前述回执遗漏的三处): - 证据绑定:归属记录新增 `verification_ids`、`manual_proposal_ids`(迁移内同表,提案后不可改),批准与核销均要求与当前计划认领的证据集合一致;同一交易重新扫描或重新人工录入即失效,取代审计原因记为 `receipt_evidence_changed`。核销处在执行事务内以只读方式重建计划认领比对。 - 并发窗口:借款批次回单上传在批次锁后取出借人锁(批次→出借人,与既有链一致),与核销的候选检查串行。确定性测试:独立连接持出借人锁,两种排队顺序分别验证“核销在先→200、随后上传成功”“上传在先→核销 409”。去掉上传锁的变异使排队断言确定性变红。 - 浏览器:PC 端两个独立登录会话完成财务登记→经理独立复核→新增同额候选后显示“须重新登记并复核”→重新登记→再次复核→核销 200;登记人看不到复核按钮、复核人看不到登记按钮。测试环境整页刷新会丢会话,改用每步新会话。 - 验证:HTTP 32 组、浏览器 7 组、74 迁移全部 PASS;去掉证据绑定、去掉上传出借人锁两个变异均变红;server 4456、prisma validate、client typecheck/build、UI strict、错误码合同、敏感扫描、diff 检查通过。 - 未覆盖:手机端未操作归属弹窗(与 PC 共用组件,仅 PC 浏览器覆盖);真实回单字段;独立复核仍为同模型。 ## 2026-10-05 复核阻断 B1 修复与回单归属复现(用户批准 A/B/D/恢复手册 + C 复现调研;本地合成,未提交、未部署) 背景:同模型只读复核(页面与剩余资金流程)结论 BLOCK:在途还款期间做出借人身份/账户维护会使 identity_version 变化,之后登记付款、取消、确认失败全部被拒,已付款项永久无法登记;导出后原审批人或出借员工离职同样卡死。另报回单批次归属未校验。 实施: - A(`services/companyLoans.js` `assertLenderNotInFlight`,`routes/companyLoans.js` 两个维护接口):出借人锁内只要存在 `reserved` 分配即 409 `loan.lender_in_flight`。新建还款先锁出借人再占用,故与维护互斥;导出/上传不新增占用,不需改上传锁。出借人列表新增 `hasInFlightRepayment`,页面禁用两按钮并提示;账户弹窗误导文案已改。原因码已登记三处(server registry、client 映射、内容断言夹具)。 - B(`services/companyLoanPayments.js` `postPayment`):回单 OCR 认领、人工回单参与人、核销三处按审批时资格认定——不再复核原审批人当前在职/角色、出借员工当前在职及主数据启用;仍校验身份已核实、身份/账户版本与提交时一致、付款快照收款资料一致、`reviewed_by/reviewed_at` 存在且审批人不是制单人/提交人/出借人关联员工(这三者之间可重合)。审批时资格依据:复核路由当时已用 `activeReviewer` 校验当前角色后写入 `reviewed_by/reviewed_at`。新建、复核、导出制单、确认银行失败保持当前资格校验;当前操作人仍须有当前权限与独立性。 - D:`scripts/qa/company-loan-http-fixture.cjs` 原“在途改身份/改账户”两段按新规则重写(改用新出借人,原出借人因负例循环留有 unknown 占用、按设计不可维护),新增:在途(导出前后)维护被拒、取消/结清后可维护;维护与新建并发 3 轮不留陈旧版本占用;导出后原审批人与出借员工离职,经 OCR 与经人工复核两条路径均从上传回单走到核销成功;付款前导出仍要求审批人当前有资格。浏览器脚本新增 PC/手机在途时两按钮禁用。 - 恢复手册:`docs/trialrun/OPS7运维交接Runbook.md` §5 增加资金类数据恢复后先暂停付款、对照银行流水补齐、核对余额与在途占用再开放。 验证(Docker 隔离 PostgreSQL,`--network none`,合成数据;需 `PAYMENT_ORDER_PYTHON_BIN` 指向 BIFF8 venv): - `RUN_ISOLATED_LOAN_DB_TEST=1 RUN_ISOLATED_LOAN_BROWSER=1 node scripts/qa/test-company-loan-db.cjs`:73 迁移、9 组 DB 约束、HTTP 21 组、浏览器 5 组全部 PASS,清理 PASS。 - 4 个源码变异(OCR/核销/人工复核改回当前资格、去掉在途拦截)均使测试变红,源码已恢复并逐字比对。 - server `npm test` 226 文件 4452 通过;`prisma:validate`、client `typecheck`/`build`、UI strict、错误码合同、文档审计(0 error)、敏感扫描、`git diff --check` 通过。 - 未覆盖:独立复核仍为同模型;真实银行/OCR 样本;生产存量(待核实)。 C 复现结果(合成全流程,测试只记录结果不设守卫): - 同一出借人两笔 7.00 在途,P 的成功回单传到 Q:`matched`,Q 执行 200 核销成功——**错误核销成立**。 - 旧 6.00 批次确认失败并取消后新建同额批次,旧批次晚到的成功回单传到新批次:`matched`,执行 200 核销成功——**错误核销成立**。 - 调研:BIFF8 制单每行已有唯一客户流水号 `批次号-R00n`;借款附言固定为“归还借款本金”(报销附言含单号);OCR 只提取金额、币种、双方账号、状态和银行流水号,不提取客户流水号/附言;建行回单是否保留二者无仓库证据,需获准的真实回单样本确认。修法待用户确认,未实施。 同模型只读复核(同日,独立上下文):本轮 A、B 修复范围 PASS_WITH_NOTES,无阻断;**借款功能整体尚未通过完整验收**(C 错误核销已复现,仍阻断真实还款)。A 互斥成立(reserved 只经 `prepareLoanRepayment` 在出借人锁后创建;幂等重放不新建;迁移触发器禁止 settled/released 回退);B 未放宽过头(`reviewed_by` 全仓唯一写入点在复核路由且已过 `activeReviewer`;出借人无归档写入;停用主数据不降低伪造回单门槛)。按其第 4、5 条补强: - 并发测试改为确定性交错:独立连接持出借人行锁,两请求按指定顺序排队后释放;新建在先 → 维护 409 `loan.lender_in_flight`,维护在先 → 两者 200 且新建采用新版本;两种顺序均无陈旧占用。“检查挪到加锁前”变异确定性变红。 - 付款后独立性反例:把已匹配回单批次的 `reviewed_by` 改为制单人或出借员工后执行均 403,恢复后正常核销;“去掉 `assertApprovedIndependently`”变异变红。 复核另记残余(未处理,计入下列阻塞):人工回单复核人在复核后、执行前离职会使执行被拒(与报销共用,推测可作废重传绕过,未验证);确认银行失败路径在出借员工离职后仍卡死,叠加 A 会长期冻结该出借人维护;付款后关闭提交人部门的付款批次灰度开关会拦执行(重新打开即可恢复)。 仍阻止真实还款验收:C 修复;unknown 状态人工解除、作废附件计数、晚到结果对账流程;B 未覆盖确认银行失败路径在出借员工离职后的卡死;AC5 真实样本;独立复核。 ## 2026-09-18 共享付款回归与交接补充 09-06本地受管重验已覆盖报销主管/财务审批、财务同页进度、批次独立复核、回单人工更正/独立复核、付款核销及AP/票据归档两条主链;完整r6为3通过/1入口矩阵失败,矩阵另在r7通过。此证据支持共享付款旧来源回归,不代替本task真实银行样本、独立资金链审阅或公网验收。当前官方current在09-06,本task仍in_progress;上批review-candidate-r1保护保持。独立问题及真实批次/银行/K1/K2清单见retained-gates-closeout-20260917的independent-and-external-readiness.json,均未进行真实查询或操作。 ## 2026-09-17 最终本地回执(当前入口) T1–T4本地实现与合成闭环完成,官方current保持本task,状态in_progress。证据根为`artifacts/qa-layout/payment-feedback-loan-slim-20260917`;最终`final-loan-browser`退出0:空库72迁移、9组真实PostgreSQL约束/两连接并发、16组正式登录Fastify/Prisma/PG HTTP场景、3组桌面/手机/员工拒绝浏览器检查全部通过;仅本轮容器/浏览器/服务/临时目录清理PASS。最终桌面、手机截图已查看,沿原有样式且银行字段脱敏;手机详情仍在移动入口。 报销原地进度`progress-green-r2`15/15;`loan-unit-r3`5文件212/212,ERP退出后的付款路由另在`erp-regression-r2`128/128通过。`final-client-build`typecheck/Vite/PWA、`final-prisma`、`final-module-load`通过。ERP共享回归按r1/r2已通过文件及r3修正后的63/63分别引用,不将分轮结果相加当全量。strict原因码850注册/886使用/legacy0/findings=[]。旧Browserslist/punycode提示和22个历史未登记文档不扩治。 ### 验收支持与开放项 | 验收 | 当前证据与结论 | | --- | --- | | AC1 | 正式财务登录、历史两笔借入、凭据唯一、四类材料、余额确认及系统外已还证据通过。 | | AC2 | 两借款一付款、部分还本、精确金额、跨来源限制、超额拒绝、两连接占用和同requestKey并发幂等通过。 | | AC3 | 显式财务权限、经理/CEO独立审批、排制单/提交/收款人、无人可批与身份/账户版本变动拒绝通过。 | | AC4 | 审批/BIFF8导出不减本金,在途不释放;安全取消、独立确认失败、成功原子claim/核销及真实数据库审计失败回滚通过。 | | AC5 | 合成自动worker/双人手工回单、双方账户/币种/金额/pending负例、跨借款/报销交易去重通过;真实银行/OCR样本接受性仍待验,完整AC保留开放。 | | AC6 | 原借款分配、余额截止状态、独立会计交接与材料权限通过;不把无OA记录当无银行还款。 | | AC7 | 付款/制单/回单及ERP触达业务回归通过,PC/手机正式登录同链与普通员工403通过,默认银行信息脱敏。 | | AC8 | 迁移/锁图/回退影响已落盘;独立只读复核PENDING,08-23实际保管/恢复事实与银行样本/迁移发布条件开放。 | 主会话只读自审核对了显式角色、账户/身份版本、创建lender→loan锁序、既有batch→receipt→lender→loan核销锁序、loan错误整体抛出回滚、unknown不释放及ERP共享边界;没有把此自审称作独立复核。待办姓名区分可处理人与站内提醒对象,仅`wecom_app_sent`成功记录可描述个人发送,多接收人anchor不推断全部送达;真实批次姓名/企微发送事实未查。 最终`closeout-governance/process/docs`与两个task validate通过;文档仅原22项登记warning。保护核验`protection-final.json`:HEAD/index未动,22个目录6447个旧材料SHA与精确文件集合全部原样;177个旧差异151个逐字不变,26个在本批授权路径叠加修改。ERP退出留下的两处尾空格已修,最终diff和敏感回执另存。本批独立审阅入口为`review-candidate-r1`,仅按baseline快照计算本轮增量,当前源码快照、删除清单与定向证据分开;manifest外部完整性回执不自引用。独立状态PENDING。未读取真实配置/密钥/备份,未连接生产/ARM,未重跑旧恢复,未提交/推送/部署/真实通知或付款。下方阶段过程保持历史原文,不再代表当前未实现状态。 ## 2026-09-17 T3/T4接续回执 T3及前端台账/付款分配/材料/会计交接已落地。`loan-payment-http-r3`:72迁移、9组约束、12组真实认证HTTP通过;`loan-unit-r3`:付款/制单/回单/通知5文件212项通过。`loan-browser-r2`桌面和手机走到还款详情并留截图,末项员工拒绝页断言错用地址导致整轮FAIL;已改为实际`/403`,不计该轮完整通过。新增跨借款/报销交易去重、金额/币种/双方账户/在途负例与同键并发,重跑中。 审批姓名区分当前可处理人和站内通知对象;企微发送只认`wecom_app_sent`成功,多接收人anchor记录不推出全部送达。不读真实delivery payload或配置。旧日期/恢复状态为历史规划记录,以本顶部实际回执为准。独立只读review PENDING;真实银行接受性、录入/付款/发布未执行。 ## 2026-09-17 当前实施回执(取代下方旧 planning/未实施描述) 官方current已start并回读本task。T1增量schema、迁移、延迟聚合约束已落地;独占PostgreSQL无网络/无宿主端口/只用合成库。初始化socket路径已修正,失败轮次原样保留。`loan-db-prototype-r5` 全部72迁移和9组约束通过,包括实际双连接锁等待与超额拒绝;容器清理通过。 T2台账/加密出借人/身份确认/原凭据唯一/材料上传下载/期初余额确认已实现。`loan-ledger-http` 真实密码登录、正式auth插件及Fastify/Prisma/PG验证5组接口场景通过,同时重跑9组DB检查。普通员工、经理、system_admin及仅admin不能管理借款;期初余额少于原本金须补系统外已还证据;审计失败由数据库触发,业务写整体回滚。Prisma validate/generate通过,generate使用本树既有链接依赖目录;不安装新依赖。 T3正在接入现有付款消费者:专属还款申请、多借款一付款、占用/独立复核、回单worker/人工例外、原子claim和本金核销;尚未完成本切片验证。T4前端和完整验收待执行。AC不提前勾选,独立只读复核PENDING,真实银行样本、发布、实际录入/付款仍未授权。 # 实施顺序(仅规划,尚未开始) ## 2026-09-17 执行优先级更新 用户要求尽快完成既有借款方案。先完成09-04两处真人反馈修复,随后官方start本task,本地T1约束/并发原型→T2台账与证据→T3本金分配及既有付款来源全链适配→T4合成闭环和旧报销回归连续推进。范围按原8项AC,不把文档齐全当产品完成。原“仅规划/不实施”的优先级由本节替代;真实操作与独立/发布门禁仍有效。 只使用运行独占的本地PostgreSQL和合成加密材料,禁外部通知/OCR/银行调用,不连接生产/ARM或读取真实配置密钥备份。无现成真实身份/付款事实时保持未确认,不用admin兜底。inline下独立只读复核PENDING,主会话不得冒称独立通过;未独立审查的新资金链不发布。 ## 2026-09-17 T1本地技术准备回执(最新入口) 已按09-08后期规划细化design第8–10节:四核心表+专属LoanEvidence、既有PaymentBatch增量、金额/唯一/FK/删除保护、余额公式、权限/接口/并发矩阵。当前execute的来源锁早于receipt advisory,不能直接复用为借款锁序;已明确新来源分派和所有写路径的顺序。文档提出取消后新申请保留历史、unknown银行结果不释放/重付,原8项AC未勾选。 - [x] T1a字段/约束/锁图/消费者与测试合同草案,源码引用已核。 - [ ] T1b获得进入条件后,以最小合成schema证明CHECK/部分唯一/延迟触发器/FK和两连接并发;尚未创建schema、迁移或数据库。 - [ ] T1c独立只读审阅具体方案与原型,不把主会话对照源码计独立通过。 - [ ] T2/T3/T4仍未开始;原恢复风险和产品实施准入保持,当前planning不变。 ## 准入 本task为09-08协调表的C阶段,不是其子任务。当前仍planning;本轮官方current在09-05执行本地治理,未切入本task。创建与规划补充不授权借款业务实现。先审阅本PRD/design,核08-23关键恢复状态和09-05到期治理结果;受保护操作等待不要求22项历史task全绿,但实际密钥不可用/敏感恢复失败没有处置时不直接扩大付款数据范围。 ## 顺序与验证 - [ ] 取得本task方案实施批准,用官方task.py start切换并回读;检查执行树、AGENTS、相关backend/approval/receipt/security/frontend spec及未提交差异,记录只允许本批改动的路径。 - [ ] 清点所有PaymentBatchEntityType消费者,设计最小Prisma模型/增量迁移、唯一约束、FK和权限矩阵;确认制单/复核/登记锁序与旧报销兼容,不引入通用工作流引擎。 - [ ] 实现出借人/借款登记、证据与余额确认,先做无权限、身份不明、重复/历史登记和可用额度负例,再做正向。 - [ ] 实现一申请一笔付款及多借款分配,复用批次独立复核;补同笔借款并发、取消/失败/未知在途和幂等断言,不能只用顺序mock证明防超付。 - [ ] 显式接入用途/备注、快照/来源重验、回单队列范围/匹配/人工复核/全局交易去重;未支持分支拒绝,错金额/账号/失败交易没有人工旁路。 - [ ] 接入既有风格的台账/还款列表与详情及会计交接记录,保持财务/审批人/普通员工可见范围和PC/手机同功能。 - [ ] 在合成独立库运行真实路由、登录浏览器和DB同链;新业务反例与原报销/差旅、动态错误合同回归分别记录,不使用真实公司借款样本或真实付款。 - [ ] 执行`cd server && npm run prisma:validate`、相关`node --check`及新增Vitest;执行`cd client && npm run typecheck && npm run build`及定向Playwright;新增测试文件及精确命令在实施时登记,当前不声称存在或已跑。 - [ ] 执行原因码、Trellis/process/docs/敏感扫描及`git diff --check`;冻结候选并取得真实外部只读内容复核,主会话检查不冒充独立验收。 - [ ] 新迁移/真实样本OCR、提交/推送、发布、真实资料导入及真实付款分别按具体范围取得批准;部署后只读验收通过才能告知公网可用。 ## 停止与交接 收款人自审、超额占用、在途可重复付款、旧来源回归失败、秘密/真实资料进入日志或不可回退的迁移方案均阻断候选。找不到合格审批人时明确业务阻断,不通过改角色或admin兜底完成样例。业务少/无自然付款不制造交易测试;需要真实样本时先单独列授权范围。 08-23和09-05若新增重大风险,先回09-08协调;本task不顺手改生产密钥/恢复工具或替其他task清理。原始PRD验收保持未勾选,正式实施结果、测试、独立审查和发布分节记录。K0已完成本地验证,K1/K2仍无实际保管/真实解密证据;新会话先核09-08协调入口,不因文件齐全或K0通过就先开发借款模块。 ## 2026-09-17 规划补充与开发前审阅包 用户要求对未完成工作先补规划;本轮只更新本task计划,不新增枚举/表/接口/UI,不读取真实借款资料。K0的30项合成结果不能替代保管事实;09-05本地日期/错误治理候选也未部署。恢复风险处置、方案实施审阅及独立复核依然是进入条件。 - [x] 复核当前枚举只有reimbursement/travel_order,以及readiness、回单验证、人工复核和OCR worker对reimbursement的明确限制;记录下方消费者分组,不借新增来源解冻travel_order。 - [x] 补迁移/锁序的待审技术切片和验收出口,前端沿既有布局,不新设计视觉体系。 - [ ] 技术定稿T1:提出四类核心表及专属借款证据关系的字段/索引/FK/版本设计;按当前PaymentBatch/ReceiptClaim实际锁图审查,先以最小合成schema验证约束及并发,再实现接口。 - [ ] T2:出借人/原借入登记及财务确认,只用合成资料;不自动产生付款或新增真实收款。 - [ ] T3:新来源显式支持/拒绝矩阵、额度占用/幂等/状态与回单闭环;逐消费者负例后再接页面,不凭新增enum编译成功宣称支持。 - [ ] T4:真实认证的本地路由/数据库/浏览器全链及旧报销/差旅回归,形成独立审阅候选;新来源OCR真实样本和生产录入仍另批。 这四切片复用原8项AC,不降低审批人独立性、并发不超付、在途保持占用、全局交易去重和审计原子性。日期/错误债务后续批次、恢复事实与借款开发分别交付,不要求22个历史task全部结案,但也不默认接受未知密钥风险。