借款对账 SR-A/B:补证恢复与复核后释放(09-17-company-loan-principal-repayment)
保留原银行终态及依据,以恢复轮次绑定材料、候选和独立性;最终取消重验并原子消费批准、释放占用和记录审计。新增增量迁移、HTTP 回归及数据库保护。 验证:78 个迁移、HTTP 72 组、既有浏览器 7 组、数据库约束 9 组通过;7 个变异均被抓住。服务端首跑 4470 通过、6 失败、1 跳过,补齐 BIFF8 测试依赖后相关 146 项通过,未重跑完整套件。 限制:inline 主会话自查不等于独立复核,独立复核待完成;界面未完成,不能单独部署;真实回单待验。新恢复界面留待 S8,S4 另批,整体借款功能尚未完成验收。本次仅本地提交,不推送、不部署、不查询生产。
这个提交包含在:
@@ -1,3 +1,63 @@
|
||||
## 2026-10-07 补证后恢复方案(SR,第 1 版,用户已批准本地实施)
|
||||
|
||||
本方案先完成设计,随后用户明确回复“批准”,授权 SR-A、SR-B 本地实施与验证;SR-C 随 S8,提交、推送与部署未授权。S3 已本地提交 `14aee82d`;下文历史设计及实施记录保留其原时点。本方案补充 3.2 的释放流程,不把普通补证归入 S6 的晚到成功。
|
||||
|
||||
### SR1 问题与边界
|
||||
|
||||
源码依据:`loanBankTerminalFacts.js` 的 `proposeTerminalFact`、`confirmNotPaid` 只接受 `unknown`;作废证据会取代关联事实。`companyLoanPayments.js` 的 `cancelLoanRepayment` 重验当前证据;`guard_loan_repayment_history` 禁止回写既有终态及其依据。因此,已确认未付款但未释放时,旧证据失效后即使取得新的有效终态证据,也无法完成重新登记与释放。
|
||||
|
||||
适用:批次仍为 `reviewed`/`failed`,原银行结论为 `confirmed_not_paid` 或 `confirmed_failed`,所有本金分配仍为 `reserved`。包括补换银行书面证据、同一交易换回单或重新识别、补登遗漏提交、候选批次变化导致归属复核失效。正常 `unknown` 仍走 S3;原有结论与依据仍有效时沿原取消流程,不要求额外恢复复核。
|
||||
|
||||
不适用:已取消释放、已核销、任一分配不再占用、已出现本笔成功事实。成功事实留待 S6;疑似成功或无法识别时可记录补证需求,但不得通过释放复核,继续占用,不把作废当作否定银行事实。处理中回单只能由同一指令的有效终态事实了结。本期不开放 Q6 人工未提交恢复、不降低 S0 存量核实或 S3 证据门槛。真实已付后退款、冲正、退汇仍不等于未付款。
|
||||
|
||||
### SR2 历史结论与当前释放资格分开
|
||||
|
||||
- 原 `bank_result_state`、`bank_result_ref`、审批与分配记录不回写,不把终态改回 `unknown`;新增恢复记录引用原结论及此前恢复轮次。补证不说明原未付款判断必然错误,页面表述为“原结论保留,释放依据待补充”。
|
||||
- 新增恢复轮次(拟表 `loan_release_recoveries`)与审计事件。每轮不可改的内容包括批次、原结论/依据、前轮、发起人、原因;送审时冻结的清单、事实、证据与候选快照另形成不可改的送审记录。
|
||||
- 轮次状态:`collecting`(补证中)→ `proposed`(待复核)→ `approved`/`rejected`;经办可撤回未批准轮次为 `withdrawn`。资料变化可使待复核或已批准轮次为 `superseded`;成功释放为 `consumed`。受控状态与决定事件同事务写入;不可删除,不可修改既有送审字段、复核意见或把已关闭轮次复活。
|
||||
- 每批次至多一轮补证中、待复核或已批准记录。需再次恢复时新建轮次;过期轮次的取代与新轮次创建同事务完成。请求键保证重试不生成重复轮次。
|
||||
- **一旦发起过恢复,最终释放只能依据最新一轮有效批准**。驳回、撤回、资料变回原样、旧批准仍在数据库中,都不能重新启用原结论的释放权限。批准本身不释放额度,仍由财务执行最终取消。
|
||||
- 不生成付款批次或补记付款,不恢复导出、执行付款、已释放占用;本金在补证、送审、复核期间都不变。S5 的出借人冻结原因如已存在,不能被本流程关闭。
|
||||
|
||||
### SR3 补证、送审与独立复核
|
||||
|
||||
1. 当前持 `loan.manage` 的财务发起,说明失效原因;服务端验证适用范围并记录原结论。不得用管理员权限跳过。
|
||||
2. 在有效恢复轮次中,允许终态批次登记新终态事实;只对该入口放开原 `unknown` 限制。证据上传、作废、提交清单登记与复核仍沿 S1/S3 的事实规则;失效事实按既有规则取代,不覆盖旧事实。新登记的事实逐条独立复核。
|
||||
3. 补登提交后必须重做完整清单复核,并为每次有效提交举证。撤回登记仅是材料纠错,不代表银行撤销;新增再撤回也算清单变化。不能通过撤回真实提交消除已知银行事实。每条导出仍须关联已终止提交,历史汇总继续阻断;没有提交的导出留给 S4。
|
||||
4. `confirmed_failed` 的恢复也升级为 S3 的逐提交终态证据集合,不能重写原失败核验 ID。原证据仍可读且有效时可引用;换回单、重新识别后必须引用新核验记录。失败归属仍按提交及当前全部同额候选独立复核。
|
||||
5. 财务送审时,服务端重跑 S3 全部释放条件并冻结完整证据快照,不接受客户端自行宣称“完整”或自报有效版本。
|
||||
6. 当前合格的经理/总经理独立复核。排除本轮发起/送审人、所有相关证据上传人、回单人工录入人、终态事实登记人,以及本批次制单、提交、出借员工、导出、银行提交登记与清单确认经办人。取人员关系时包含旧记录、作废与撤回记录,不能借换材料消除经办身份。原审批人可参与,但必须满足当前资格与上述独立性;不因其是原审批人而自动放行。
|
||||
7. 批准时重新取当前材料和候选,比较快照并重跑全部条件;驳回或证据不足继续占用。原审批人和出借员工的在职/角色、主数据当前启用状态不重验,按历史审批与原冻结快照核对;当前操作人始终核验当前权限。
|
||||
8. 最终取消必须引用这轮批准;核对当前操作人取消权限,再次重验快照、释放条件与分配状态。释放、批次取消、轮次消费和审计一次事务提交,任一步失败全部回滚。已完成的同请求重试返回原结果,不重复释放。
|
||||
|
||||
沿用 S3:逐提交覆盖、逐导出关联、提交清单有效、终态证据有效、失败交易唯一性、必要的失败归属、无未解决成功/处理中事实、无历史汇总、距最后导出满内部等待期。对账单、截图、等待期或两个人确认均不能单独放行。未付款的新证据不要求再机械等待 3 天,但仍必须满足最后一次真实导出的等待期。编号对应关系仍待 S0,不靠人工照抄回单号补足银行证明。
|
||||
|
||||
### SR4 快照失效与并发
|
||||
|
||||
送审快照包含:原结论与依据;原付款快照标识;全部导出;全部提交(含撤回)及清单复核记录;逐提交终态事实与复核记录;银行证据 ID、摘要和作废状态;全部付款回单的 ID、摘要、OCR 版本、核验记录、人工录入/复核记录及作废状态;归属批准及全部候选集合;分配 ID/金额/占用状态。证据只要改变,旧批准就不能沿用,即使银行流水号相同。
|
||||
|
||||
使用服务端单调递增的材料修订号并保存上述快照;材料新增、作废、重识别、人工录入及材料复核均推进修订号,防止“改完又改回”复活旧批准。恢复轮次自身的送审、批准和消费决定不改变材料修订号,避免批准使自己失效。候选变化同时重查实际集合,不只依赖目标批次自己的修订号。证据送审与批准之后的缺失、失效、存储读取错误或摘要不符,均不得放行。
|
||||
|
||||
锁与检查须覆盖所有写入者,而非仅恢复接口:同批次最终释放与证据作废、付款回单上传/核验落库、提交登记/撤回、清单/事实/归属复核串行;同出借人的候选形成与候选检查也串行。沿既有锁相对顺序:批次 → 回单交易 advisory lock(需用时)→ 出借人 → 按 ID 排序借款行,不引入反向加锁。编码前核对所有受影响入口及后台 OCR 写入的实际锁序;多批次场景不在持有出借人锁后反向锁其他批次。
|
||||
|
||||
- 变化先发生:旧送审/批准失效,取消拒绝,本金和占用不变;取代旧轮次后补证重新送审。
|
||||
- 最终释放先发生:只消费一次批准并释放一次;之后证据不允许改写已关闭记录。后来银行事实须走独立对账流程,本设计不能证明未来不会出现成功,不声称串行化消除晚到风险。
|
||||
- 独立性与权限在送审/批准及最终动作所需环节重查;经办人集合变化使旧送审失效。旧逐事实复核人事后离职本身不抹掉当时有效的批准,新的恢复复核人必须当前合格。
|
||||
|
||||
### SR5 数据、接口与页面安排(设计约定;实现状态见 implement)
|
||||
|
||||
预计新增一个增量迁移:恢复轮次/不可变送审与决定记录、材料修订号、唯一索引及历史保护约束;不得放宽原银行终态或已释放分配的保护。存量不自动补造恢复批准、不自动释放;默认未发起恢复,保留 S3 原门禁。回滚前若已有恢复记录,不能退回只按旧结论释放的代码;停止发布并保留数据,另审兼容方案。
|
||||
|
||||
拟接口位于 `/payment-batches/:id/loan-release-recoveries`:发起、送审、独立复核、撤回、查询。沿现有附件/事实/清单接口补证,最终仍走批次取消接口并传恢复轮次与幂等请求标识。终态材料写入口须验证当前轮次,不提供通用“重开批次”。拟新增原因类别:恢复必需、证据已变化、仍有银行事实未解决、无合格复核人;复用已有原因码优先,新增时同步前后端错误码合同。
|
||||
|
||||
S8 还款详情增加“补充释放依据”:并列显示原结论与当前补证/复核/可释放状态、逐提交缺口、失效原因、操作者与证据查看入口。财务与复核人动作分开,服务器仍强制鉴权;详情不能把“批准”显示成“已释放”。PC/手机使用同一组件并实测全流程,敏感字段默认脱敏。界面与对应后端齐备、完成 S0/真实样本/整体验收前不得部署启用。
|
||||
|
||||
### SR6 验收与后续决策
|
||||
|
||||
对应 PRD AC17–AC19,覆盖两种原终态、重复补证、重扫同一流水号、补登第二次提交、多次送审、候选变化、自审/离职、事务回滚、并发交错及禁止重付。关键资金检查做变异测试;必须从真实 HTTP 的上传/核验与复核入口走到取消释放,不能直接调用释放函数代替。只替换云 OCR 响应,使用隔离 PostgreSQL 与合成材料。
|
||||
|
||||
批准的核心选择是“原终态不变,新增恢复轮次决定释放资格”;它覆盖 S3 后的补证恢复,不含 S4–S8 的实施。当前代码及验证进展见 implement 顶部;inline 模式不得将主会话自查写成独立复核。
|
||||
|
||||
## 2026-09-17 实施细化
|
||||
|
||||
## 2026-10-06 失败回单归属与银行结果对账方案(第 3 版,待用户审阅,未实施)
|
||||
|
||||
@@ -1,3 +1,63 @@
|
||||
## 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`:
|
||||
|
||||
@@ -64,6 +64,10 @@
|
||||
- [ ] AC15(追回,3.5):凭到账证据经独立复核登记,支持部分追回;仅登记不解冻;本期不支持冲抵。
|
||||
- [ ] AC16(存量):历史批次保留已知的导出次数,新增“历史导出汇总”标明已知与待核实信息;它不是一次真实导出或银行提交,不能据此放行额度;上线前须核实生产存量(S0)。
|
||||
|
||||
- [ ] AC17(补证恢复,SR1–SR3;方案已批准,后端验证见 implement):已确认失败或未付款且本金仍全部占用时,可补充有效证据并重新独立复核;原结论与依据不可改,旧证据/复核可追溯;恢复不得重开付款、导出或改变本金,不适用于已释放/已结清、成功事实或 Q6 人工未提交。
|
||||
- [ ] AC18(恢复批准有效性,SR2–SR4;后端验证见 implement):材料、核验版本、提交清单、归属或同额候选变化使旧恢复批准失效;新建再撤回、换回同一流水号、撤回/驳回恢复均不能复活旧批准或回退原释放依据;补证后能重新送审,不永久卡死;当前复核人合格且与全部相关经办身份独立。
|
||||
- [ ] AC19(最终恢复释放,SR3–SR5;后端验证见 implement):确认与最终取消均满足 S3 全部条件及等待期;最终事务重验最新恢复批准与证据,释放、取消、消费批准、审计原子且幂等;与证据/提交/核验/候选变化确定性交错时不错误释放;成功事实转对账、未知继续占用。PC/手机完整操作与真实银行接受性分别验收。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 不处理利息、工资/分红、员工向公司借备用金、资本金、债转股、机构借款、外币、退款或债务冲销。
|
||||
|
||||
在新工单中引用
屏蔽一个用户