文件
hyb-oa/.trellis/tasks/09-17-company-loan-principal-repayment/implement.md
T
wangsli和Claude Opus 5.5 db919dc6f6 记录出借人线上确认发布结果与办理顺序(09-17-company-loan-principal-repayment)
- 补记 4a5cd8f2 门禁、部署与生产 83/83 迁移证据;本次未做快照按用户决定记录
- 更新 PRD、implement 与《试运行与自动化验证手册》的办理顺序;真实业务验收及两处历史失败仍开放

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 18:22:49 +08:00

1197 行
197 KiB
Markdown
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
## 2026-10-10 N5-C 已发布至生产(4a5cd8f2,83/83 迁移)
出借人在线确认及站内通知直达已随 `4a5cd8f2b3e04da24551ddf1ee99b4167aa76710` 发布。本次按发布会话转交结果补记,只核对本地 Git、已有候选验证和部署日志,没有重新连接生产或办理真实借款。父任务继续 `in_progress`;下方各轮“未提交、未发布、待门禁”等表述保留其历史时点,以本节为最新发布状态。
### 本地核实的发布证据
- 补记前工作区干净,HEAD 与本地 `origin/main` 均为上述提交;提交说明引用本任务。
- `artifacts/qa-flow/release-4a5cd8f2-20261010/verify-candidate.log`:最终候选验证 `status=PASS`、`localChecksPassed=true`、`deploymentEligible=true`、`issues=[]`、退出 0;服务端全量 4670 项通过、1 项跳过,浏览器 372 项通过。`artifacts/release-gate/release-4a5cd8f2-20261010/release-result.json` 同样为 PASS、可部署。本节转录既有最终提交回执,没有重跑门禁,不以入口调整前的 216 项代替该候选验证。
- 同目录 `deploy.log`:部署前聚合体检 `PASS=13 FAIL=0`,来源提交一致,`branch=main`、`published=true`、`remoteVerified=true`;待应用迁移仅为 `20261010010000_loan_lender_acknowledgements`。应用构建切换、external deps smoke、runtime smoke 及公网前端资源扫描通过,扫描 `buildMarker=PASS`、`findings=0`。最终“应用发布与备份合同刷新完整通过”、deploy 模式 PASS,退出 0。
- `artifacts/production-preflight-20261010-172051/{pre,post}/`:部署前旧应用 Prisma 为 82 个迁移、结构已最新,候选差集为上述 1 个;部署后 Prisma 为 `83 migrations found`、`Database schema is up to date`,复核 `pending=none`。前后 `rollbackWindow=OPEN`,仅表示当次检查时点,不代表已实际演练回退;旧应用不理解在线替代材料的兼容边界仍按设计保留。
- 部署日志明确跳过登录后的 live smoke,原因为未提供完整凭据。OCR 等 external deps smoke 只验证配置契约,不代表真实识别或真实借还款链路已验收。
### 发布会话转交结果与证据边界
- 用户回报已推送部署、SSH 未中断;公网 `/ready` 为 `ok:true`、版本 `4a5cd8f2b3e0`,`/health` 为 200;首页、`/login`、`/mobile`、电脑/手机公司借款页、`/notifications` 均为 200,前端主脚本加载正常。新出借人确认接口未登录返回 401。上述公网路由明细沿用发布会话回报,本次未重新请求公网;可达和未登录拦截不等于登录后的本人确认流程通过。
- 快照:按用户转交记录,此次未做腾讯云手工快照;本会话此前的建议为迁移前做快照,未在本会话执行或核实云侧快照。该记录不将跳过快照的决定归为本会话授权。
### 真实办理交接与未决项
1. 财务在“公司借款 → 出借人确认”对两笔借款发起声明,系统仅给对应出借人生成站内通知。
2. 马经理用本人账号点击通知,逐项核对原件、金额、日期后确认;有误则退回财务。出借人确认与公司代表身份分别办理。
3. 财务取得并上传代账“其他应付款—马经理”的明细账/余额核对材料,与代账核对后填写引用并确认期初余额。未还本金少于原本金时,系统外已还本金依据仍必需。用户表示当前待取得材料为代账明细账;本次未独立读取真实附件或余额,不据此断言其他材料均已齐全。
4. 财务登记公司代表授权及范围,由马经理以公司代表身份确认。完成 N5 后,再按已确定的真实金额、分配和日期办理 N6 首笔还款。
登录后的上述流程尚未在生产实际验收,N5/N6 及相关真实银行验收继续开放。追回到账与员工授权翻页两处历史失败根因仍未定,保留原失败证据和另行确定性排查安排;本次未创建或实施新的排查任务。借入登记默认值继续只记录、暂不修改。
本次仅补发布记录及手册状态,未修改业务代码、重跑业务测试或再次发布;文档补记尚未提交。任务上下文、流程基线、Trellis 治理、敏感内容及差异检查通过;文档登记 0 错误,保留既有 22 份未登记文档的 1 条告警。回执见同一发布证据目录的 `*-record.log`。本次没有新增可复用工程合同,不扩写 spec。
## 2026-10-10 N5-C 发布前入口调整(历史本地验收记录,后续已发布见上节)
用户复核提出普通员工常驻入口无必要,并给出“只对已关联出借人的员工显示”或“发起后通知直达”两种方案、委托本会话取舍。本次选择第二种,沿已批准的本人确认功能收敛入口,复用现有 OA 站内通知。范围包含通知创建和声明定位,不能只删导航;不新增通用待办、外部消息或迁移。
- [x] E1:恢复财务/公司代表常驻导航边界,本人路由权限保留;声明发起事务只给对应本人创建一条站内通知。
- [x] E2:电脑/手机通知链接直接打开对应声明,使用现有按账号隔离的详情与取消请求逻辑,不依赖列表首屏。
- [x] E3:定向通知幂等/事务回滚/本人可见、导航及电脑手机通知点击验证,补只读复核,更新手册/spec。
- 发布安排:建议本次生产结构迁移前做腾讯云手工快照,实际快照及发布操作待明确批准;发布候选须只允许 `20261010010000_loan_lender_acknowledgements` 这 1 个待应用迁移,发布后核对 83/83。迁移除新增三表外,还包含历史不可修改/范围完整性约束以及挂到既有借款、出借人、原件表的来源失效触发器;没有历史余额回填,不能简写为“只新增三张表”。当前生产未访问。
- 两处既有待查:追回到账和员工授权翻页失败根因仍未定,保留失败证据与确定性复现要求,本次不混入根因排查或宣称修复。后续按独立排查范围安排;原完整 r4 的 216 项结果仍为入口调整前证据,不能直接充当修改后回执。
- 本次仍无提交、推送、部署、生产写入或外部消息授权。
- 首轮入口定向 `entry-browser-r1.log`:83 迁移、17 组 HTTP 均通过;浏览器已从通知打开声明弹窗,随后原登录 helper 还要求通过可访问角色查询找到弹窗后面的“公司借款”标题,Radix Dialog 正确屏蔽背景后该断言失败。仅将通知直达分支改为断言当前“出借人借款声明”弹窗标题,财务普通登录仍检查页面标题;失败日志保留,随后 `entry-browser-r2.log` 的 17 组 HTTP、16 组电脑/手机操作和 9 组数据库检查通过。
- 本轮只读复核发现 URL 声明 ID 被发起模式遮挡:打开声明、关闭、再打开发起表单后,浏览器历史返回声明 URL 时仍显示发起。改为非空 URL ID 优先显示详情,并清除发起草稿/确认说明/勾选/错误、取消旧请求。新增电脑/手机同 SPA 场景:非空出借人、已选一笔和说明的草稿 → A → B → 浏览器后退 A → 重开发起,断言明细及草稿清理。复核方补查产品与测试、核对最终 r5 日志,结论 `REVIEWED_NO_BLOCKER`;复核方未改文件、未写库,测试运行结果沿用主会话回执,不冒称独立重跑。
- `entry-browser-r3.log`:83 迁移、17 组 HTTP 通过,浏览器登录时的通知列表断言失败,未计通过。测试原谓词只匹配 `/api/notifications` 路径,而顶部栏同时请求未读计数列表;该次未采查询参数。`entry-browser-r4.log` 保留原谓词并增加 query/items/mode 的合成诊断,稳定复现捕获 `?page=1&pageSize=1&unreadOnly=1`、只有一条结果的顶部计数响应,确认为测试等待对象歧义。现严格匹配通知页 GET/200、type、page=1/pageSize=20/unreadOnly=0,保留原目标 ID、真实点击及 URL/弹窗断言;未改业务、未增加重试/超时。r3/r4 失败日志和合成截图保留。
- 最终 `entry-browser-r5.log`:新进程使用最终业务代码和 `client-build-entry-r2.log` 构建,退出 0;83 迁移、17 组 HTTP、18 组电脑/手机操作、9 组数据库检查均通过,测试自有资源清理通过。不累计 r2/r5 重复项目。覆盖通知收件人/幂等/并发/失败回滚、无外部派发、普通员工无常驻入口、实际通知点击定位、上述同 SPA 历史切换、原件下载/本人确认/退回、代账材料门槛、历史失效通知/续办、同身份刷新及跨账号请求取消。
- `unit-entry-r1.log`:导航 12、权限 14、通知接口 19,合计 45 项通过;最终前端类型检查/构建、服务及 fixture 语法、错误理由和 UI 规则检查通过。任务上下文、流程基线、Trellis 治理、敏感内容及差异检查通过;文档登记 0 错误、保留既有 22 份未登记文档的 1 条告警。手册及 backend spec 已同步站内通知与 URL 选择合同。
- 本轮只做入口范围定向验证,没有重跑完整借款回归或最终发布门禁。此前完整 r4 的 216 项只能作为入口调整前证据。下一阶段待用户明确授权本地提交,再对最终提交运行完整发布门禁;生产快照、推送、部署及仅 1 个生产迁移仍需各自明确批准。真实 N5/N6、默认值暂停项及历史失败根因待查继续保留。
## 2026-10-10 N5-C 出借人在线确认(入口调整前本地实现与验证完成)
用户已明确批准收窄方案,复用本任务 AC40–AC44。基线为 `2063ff1e`,开始时已有 `prd.md`/`implement.md` 的发布补记及待办未提交,予以保留。仅本功能恢复实施,默认余额/日期待办仍暂停;无提交、推送、部署、生产写入及对外消息授权。
- [x] C0:核对材料消费者、借款/身份/附件锁序、本人访问边界,更新 PRD/设计;确认需新增专用声明数据,而非复用公司代表授权。
- [x] C1:增量迁移、不可变快照/决定、单向失效及服务端本人权限/事务/幂等。
- [x] C2:财务发起与出借人确认/退回界面、受限访问及原件查看,保留纸质路径。
- [x] C3:接通余额确认和还款材料判断;隔离 HTTP/数据库并发、电脑/手机及纸质回归。
- [x] C4:Prisma、后端语法/定向测试、前端类型/构建、错误码/治理检查;独立只读复核并修复阻断项。
- [x] C5:更新证据与交接,说明本地验证和生产发布边界,不自动提交或部署。
### 当前实现与验证记录(本地,最终完整回归 r4 通过)
- 新增专用出借人声明、借款快照及单次决定三表。本人账号与财务经办分离,声明与公司代表授权分离;快照/决定不可改删,任一来源变化使整组永久失效。服务、触发器及 UI 同时支持“已确认余额且有失效声明历史”的续办,禁止借此改写借款或原余额确认;纯纸质已确认借款不开放首次线上声明。
- 余额确认与后续还款材料消费者接受纸质协议或有效在线声明二选一,其他材料要求不变。新增第 83 个迁移仅在合成隔离数据库执行;生产仍为 `2063ff1e`/82 个迁移。
- 独立只读复核:`review_lender_ack` 首轮发现余额确认只锁借款造成并发失效遗漏、原件下载 JSON 类型缺失,两项均修复;第二轮无阻断(浏览器待验)。随后主会话发现已确认余额后的声明续办缺口,复核方确认,按上述最小历史范围修复;最终续办复核为 `REVIEWED_NO_BLOCKER`,最终 `browser-r3.log` 已补齐电脑/手机续办与实际导航验收。复核方未改代码、未写数据库、未读取真实材料。
- HTTP `http-r3.log`:15 组专项和 9 组既有数据库约束通过,含身份/同组原件并发失效的实际锁等待、事务审计失败回滚、相反决定并发、原件/真实 employee-refresh 后重发、退回重发、部分组续办、原借款整行不变、旧声明不复活、公司授权仍需重办。83 迁移全部应用成功,隔离容器无网络/持久卷。
- 浏览器最终 `browser-r3.log`:新进程使用最终业务代码与 `client-build-r4.log` 构建,15 组 HTTP、电脑/手机合计 14 组操作及 9 组既有数据库约束全部通过。实际从电脑导航/手机“我的”进入,原件下载 200、本人核对/确认、代账材料拒绝后上传并确认余额、退回重发、已确认余额后的声明续办、同身份令牌刷新、同 SPA 切换账号后旧请求取消且无重发均覆盖。早一轮 `browser-r2.log` 的 10 组仅为中间证据,不与最终 14 组累计。
- 最终入口补查:普通员工直达页可用,但旧导航的财务角色筛选仍隐藏入口。补齐服务端 workspace role gate、客户端 NavLinks 显示/后备项及手机“我的”链接,例外仅限公司借款及 `loan.acknowledge_own`。最终只读导航复核无阻断;`unit-navigation-r2.log` 的 12 项通过,明确不授予 `loan.manage`,付款/应付入口继续隐藏。早期完整回归启动早于本次导航修复;最终 `full-loan-r4.log` 使用修复后的代码,实际导航点击另由最终专项 `browser-r3.log` 覆盖,不把分轮证据混称一次全量。
- 单测:`unit-ack-r2.log` 新声明材料/续办 28 项;`unit-related.log` 权限、导航和公司代表授权 64 项通过(导航后续 12 项重验,不重复计数);错误理由 `unit-errors.log` 923 项通过。合计覆盖 1015 项,其中本功能新单测 28 项。前端最终 `client-build-r4.log` 类型检查与构建通过;Prisma validate、错误码合同、UI 规则、语法及差异检查通过。此后仅改测试断言/采证和文档,不重复构建未变的前后端业务代码。
- 最终完整借款回归 `full-loan-r4.log`:退出 0,83 迁移通过,去重后 216 项(HTTP 150、浏览器 57、数据库约束 9),测试自有资源清理通过。45 项原借款浏览器汇总包含关联方 18 和员工 8,不能再次累加;本功能在完整轮次为 HTTP 15、电脑/手机浏览器 12。专项 `browser-r3.log` 的 14 项比完整轮次多电脑/手机实际导航各一项,作为补充证据列出,不和完整 216 重复累加。
- 失败保留:`http-r1.log` 未指定已有 BIFF8 Python 导致导出不可用,修正测试环境后 `http-r2/r3` 通过;`browser-r1.log` 新弹窗没有显式关闭按钮,补现有 DialogFooter 按钮后重跑通过;原余额弹窗按既有 Escape 方式退出。实现期间错误码检查曾拒绝动态工厂,已改为显式登记的错误工厂,后续两次合同检查通过。没有放宽业务断言或增加重试掩盖失败。
- 完整回归首轮 `full-loan-r1.log` 在既有“登记追回到账”浏览器步骤失败,空 alert 日志不足以确定根因,不宣称旧问题已修复。测试原来按当时选项数量取最后一项,现改为捕获上传响应中的具体 evidenceId、等待该选项并断言选中,同时增加提交前无效控件与失败截图/按钮状态采证;不改业务、不增加重试或超时。旧普通员工整页 403 验收改为仅本人声明可见、台账入口和财务数据请求均不存在,服务端台账 403 仍保留。上述测试调整已由复核方只读检查,无放宽权限/材料断言,但不能据此证明首轮失败根因。
- 完整回归 `full-loan-r2.log` 仅记录迁移、员工 HTTP 和 S4 阶段后进程被终止,退出码 143,无完整结果,终止原因未定,不计通过。
- 完整回归 `full-loan-r3.log` 在关联方电脑浏览器的普通技术员工 `waitForURL(/403/)` 处超时。失败采证 `artifacts/qa-layout/payment-feedback-loan-slim-20260917/browser-REBg2n/failed-desktop-2.json` 显示员工已在公司借款页、仅看到本人声明,根因是旧“普通员工整页 403”断言尚有一处漏改。只调整 `company-loan-related-browser.cjs`:本人声明空列表可见、无财务/授权操作及 tablist,登录前开始监测并断言零台账/出借人/还款/公司授权接口请求;保留技术员工无还款通知和公司授权停止、服务端越权 403 检查。复核方补查确认未削弱财务/公司授权隔离,无阻断项;完整 `full-loan-r4.log` 随后通过。本轮为不同的确定性测试合同过期,不据此关闭首轮追回到账或既有员工授权翻页根因待查项。
### 收尾与交接边界
- 本功能 AC40–AC44 为本地合成验收完成,父任务仍为 `in_progress`。真实 N5/N6、既有翻页问题和暂停的登记默认值待办仍开放;首轮追回到账失败原因为未定,r4 通过不代表已查清。
- 操作顺序已写入现有《试运行与自动化验证手册》:财务发起 → 出借人本人核对原件并确认/退回 → 财务补齐代账材料及必要的已还本金依据、确认期初余额 → 单独办理公司代表授权。只替代协议类材料,不自动确认余额或批准付款。
- 收尾任务上下文、流程基线、Trellis 治理、敏感内容、文档登记及差异检查通过;文档登记仍为 0 错误和既有 22 份未登记文档的一条告警,不扩展治理范围。回执位于本证据目录的 `*-closeout*.log`。
- 未运行全服务端测试套件或最终发布门禁;本轮结果不能代替后续最终提交的发布候选验证。没有提交、推送、部署、生产迁移或真实业务写入;新增第 83 个迁移仅本地验证,发布仍需单独授权,生产仍为已发布的 `2063ff1e`/82 迁移。
证据目录:`artifacts/qa-flow/loan-lender-ack-20261010/`。复现命令(`PAYMENT_ORDER_PYTHON_BIN` 使用本机已备好的锁定 BIFF8 环境,不提交真实路径/凭据):
```sh
cd server && npm run prisma:validate
npm test -- tests/unit/services/loanLenderAcknowledgement.test.js
npm test -- tests/unit/services/loanApprovalPolicy.test.js tests/unit/constants/permissions.test.js tests/unit/workspaceSettings.navigation.test.js tests/unit/permissions.entity.test.js
cd ../client && npm run build
```
根目录专项:`RUN_ISOLATED_LOAN_DB_TEST=1 RUN_ISOLATED_LOAN_ACK_ONLY=1 node scripts/qa/test-company-loan-db.cjs`,电脑/手机另加 `RUN_ISOLATED_LOAN_BROWSER=1`;完整借款回归移除 `RUN_ISOLATED_LOAN_ACK_ONLY`。不使用真实用户、回单、云 OCR 或生产连接。
## 2026-10-10 真实办理卡点:历史借款缺少协议和余额核对附件(历史反馈,后续方案见上节)
用户回报财务已完成录入,随后在“借款材料与余额确认”页面反馈所需材料没有。截图显示原借入凭据已有附件,“协议或借款确认书”“余额核对材料”“系统外已还本金依据”栏目未见附件。本次未访问生产,不保存截图中的原始文件名或银行信息;该记录是用户办理反馈,不宣称已独立验收真实台账。
- 当前规则核实:确认期初余额必须有协议/确认书、原借入凭据、余额核对材料三类有效附件;仅在未还本金少于原始本金时才额外要求系统外已还本金依据。不能把页面列出四种上传入口解释为所有借款都必须上传四份材料。
- 实际卡点:已有银行回单,但缺少协议/确认书及余额核对附件,现行流程无法完成余额确认,后续公司代表授权范围也无法选择尚未确认余额的借款。N5 为“用户回报已录入,余额及授权尚待完成”,不再笼统记为尚未录入。
- 待讨论的改进方向:为无历史协议的真实借款提供当下形成的借款事实与余额确认记录;可评估一份记录同时覆盖借款性质、原件引用、截至日余额和核对依据,或在 OA 内形成等效的具名确认与审计。不要求补造当年协议或把银行入账回单视为未还本金证明。代账核对是否已发生、如何留存引用以及与公司代表确认的分工,须在方案中明确,不能直接将缺件校验删除。
- 状态:沿用用户“先记录问题,先不要修改”的指令。本轮只补任务记录,不改产品规则、不执行真实确认、不补写虚构材料,待用户决定后续处理方式。
## 2026-10-10 待改进:借入登记默认值(仅记录,暂不实施)
用户在登记页面提出:“登记时应该默认未还金额为全额,日期为当日”,随后明确要求“先记录问题,先不要修改”。本次只读检查了现有入口,没有修改业务代码或测试脚本,也没有运行业务测试。
- 当前问题:截图所示“上传回单登记借入”的“核对日未还本金”和“余额核对截止日”没有默认值,需要重复填写;原手工“登记借入”入口也没有这两项默认值。
- 期望行为:未还本金默认等于本笔原始本金全额;余额核对截止日默认登记当天,按项目北京时间口径。两项仍可人工修改。
- 日期范围:此处“当日”指余额核对截止日,不替换回单上的实际到账日期。
- 后续实施需保持:人工修改的余额和截止日不被后续识别覆盖;换回单或重新登记时避免沿用上一笔余额;默认值不代表余额已核实,保存后的“余额待核实”和原有确认流程继续保留。
- 状态:仅登记待办,暂不修改产品;收到用户明确恢复实施的指令后再处理。两个登记入口的一致性及针对性验证届时一并核对。
## 2026-10-10 发布后的后续工作(待执行清单)
本次按用户要求梳理,复用当前任务,不新建计划系统。产品当前版本为 `2063ff1e`;下表是工作安排,不代表已执行真实录入、付款、技术修复、提交、清理或归档。发布记录及本清单仍未提交,父任务保持 `in_progress`。
| 顺序 | 工作与负责人 | 启动条件及完成标准 |
| --- | --- | --- |
| 1:业务主线 N5 | 财务登记真实台账,马经理确认公司代表授权 | 财务从员工中选择并创建/复用出借人,分别上传两份历史借入回单;核对公司、双方姓名/账号、金额、到账日期、流水号及出借人建议,补未还本金与截止日,完成两项确认。原件随借款保存,随后补协议、余额核对材料及代账引用,确认期初余额;登记已有公司代表权及覆盖范围,由马经理确认。完成标准为两笔台账与原件、余额依据及有效授权均可追溯,不新增虚假现金流。真实录入由有权人员办理,代理代录另按授权执行。 |
| 2:技术排查,可与 N5 并行 | 开发确定性复现授权对话框翻页超时 | 复用本任务,先形成局部排查方案。隔离环境构造超过 30 个符合列表条件的出借人,明确目标位于第二页或以后;电脑/手机均断言实际翻页、请求和选项渲染完成,再选择目标并完成授权。留存失败响应、时序及脱敏截图,区分等待竞争、服务端响应和界面问题。仅修改等待方式或未触发该分支的通过不能结案;若实际办理遇到,提升优先级。 |
| 3:业务主线 N6 | 财务申请、网银提交及代账交接;马经理按公司代表身份确认 | N5 完成后,按真实付款安排明确本次金额、逐借款分配及日期;申请 → 确认 → 导出 → 实际网银提交并登记提交详情 → 正式付款回单核验/必要人工确认 → 核销 → 代账交接。以本次已付本金和可定位的银行交易为验收依据,不从余额推定全额还款,不为测试制造付款。扫描付款回单按付款路径的人工依据与确认规则办理。 |
| 4:技术优先项 | 开发评估将回单重检的文件读取/PDF 解析移到全局锁外 | 沿 N3 已记录的 P3 优先顺序设计;锁内保留原件摘要、版本、权限及全部状态重验。用重检与认领/人工核验/执行并发、附件作废/换版等反例证明不使用过期结果,再独立只读复核。工作线程限时 5 秒不是整个持锁时长的上界;不能只凭耗时变短判定修复完成。 |
| 5:技术近期项 | 开发验证员工来源版本的误报,再评估数据库唯一约束 | 来源指纹包含员工 `updated_at`,登录会更新认证字段;先验证“财务预览后员工登录再保存”的冲突,不泛称每次登录必然提示资料变化。修正时须同时保留姓名、公司、状态和银行资料真实变更的拦截。唯一性当前由代码检查与员工行锁保护、缺少员工和公司组合的数据库唯一约束;新增约束前明确归档/空员工语义并检查存量,不直接加迁移或清理真实记录。 |
| 6:线上验收补证 | 运维准备账号与安全凭据来源,财务/马经理补借款角色验收 | 现有通用 live smoke 需要管理员、员工两类账号;凭据通过受控本地环境或既有秘密配置提供,不写聊天和任务记录。先确认检查范围与授权,再执行登录后只读页面/权限检查。通用 smoke 不覆盖本次借款登记及公司代表确认,后者随 N5/N6 留证。真实云 OCR 单列授权和验收;带 OCR 的准备脚本会上传材料,不能当纯只读 smoke 执行。 |
| 7:较低优先级改进 | 开发与财务明确旧记录重检、记账日期、字段提示规则 | 旧记录缺少原云端限制字段,重检不能重建未保存证据,先明确策略再实施;记账日期下限先区分正常还款与历史补记,不直接统一硬卡审批日;第五轮 N1 可统一 OCR 与本地无效编号的提示,但保持整段校验、多页关联和冲突拦截不变。 |
| 8:文档收尾 | 开发提交发布记录及本次清单 | 内容与检查已具备,可在收到明确本地提交授权后单独提交;提交说明引用当前 task。此次梳理不自动提交,也不再次部署。 |
| 9:下轮完整门禁前 | 开发盘点磁盘,用户确认删除范围 | 本次只读统计:`artifacts/` 约 8.87 GiB,所在磁盘剩余约 9.71 GiB。先列候选目录、大小、可再生依据及被证据引用情况;优先评估可再生构建/缓存,不因“旧轮次”就删除。保留发布/回滚依据、有效回执、复核报告、探针、关键失败证据和原件;删除另获明确授权。 |
| 10:维护事项 | 逐个任务的负责人核对后归档 | 当前非归档 task 共 25 个:22 个 `in_progress`、3 个 `planning`,不是 24 个进行中。逐个核对交付、真实业务验收、未决项及记录,再列归档候选;时间久或代码已部署均不代表任务完成。本借款任务当前不归档,其他任务不在本轮批量更改。 |
验收口径:首笔正常成功还款只能补齐实际覆盖的银行提交、付款核验、核销及交接证据,不能一次关闭 AC5 或 AC9–AC19 的全部分支。失败归属、未付款释放、晚到成功、追回及补证恢复继续按各自条件验收;AC12 人工确认未提交仅适用于双独立复核模式,不适用于当前关联模式。不得为覆盖这些分支制造真实异常交易。
翻页问题继续标记“根因未定”。本次未核实生产出借人数量;即使目标当前在第一页,也只能说明这次未触发翻页,不能据此证明线上无影响。N5 可按既有流程由财务推进,实际遇阻时停在对应步骤留证,不绕过余额或授权确认。
本次为任务安排与证据边界澄清,无产品变更或新的已验证工程合同;不扩写 spec,不重跑全套业务测试。
## 2026-10-10 N5-P 已发布至生产(2063ff1e)
“上传回单登记借入”已随 `2063ff1e9336b8559ddd506f8f3fd754c1108327` 发布。本次仅补记发布结果:核对本地 Git 与已有日志,没有重新连接生产、调用云 OCR、写入真实业务数据或执行部署。父任务继续保持 `in_progress`;下方“待提交”“未发布”等内容保留各轮历史时点,以本节为最新状态。
### 本地核实的发布证据
- 补记前工作区干净,HEAD 与本地 `origin/main` 均为 `2063ff1e9336b8559ddd506f8f3fd754c1108327`。部署日志记录相同来源提交、`branch=main`、`published=true`、`remoteVerified=true`。
- `artifacts/qa-flow/release-2063ff1e-20261010/verify-candidate.log`:候选验证结果 `status=PASS`、`localChecksPassed=true`、`deploymentEligible=true`、`issues=[]`、退出码 0;含静态检查、完整本地门禁及 372 项浏览器测试通过。本节转录已有验证结果,没有重跑这些测试。
- 同目录 `deploy.log`:部署前聚合体检 `PASS=13 FAIL=0`;应用构建与切换、external deps smoke、runtime smoke 通过;公网前端资源扫描 `buildMarker=PASS`、`findings=0`。最终为“应用发布与备份合同刷新完整通过”、deploy 模式 PASS、退出码 0。
- `artifacts/production-preflight-20261010-112903/{pre,post}/`:部署前后迁移核对均 `pending=none`,Prisma 均发现 82 个迁移且数据库结构为最新;当次回滚窗口均为 `OPEN`。该状态仅代表发布检查时点。
- 部署日志明确跳过登录后的 live smoke,原因是未提供完整凭据。external deps smoke 中 OCR 项仅验证配置齐全,不代表真实云 OCR 识别已验收。
### 发布会话转交结果
用户回报:`origin/main` 从 `45737ccb` 推送至 `2063ff1e`,部署一次跑通、SSH 未断、前后复核均 13/13;公网 `/ready` 返回 `ok:true`、版本 `2063ff1e9`,首页、`/login`、`/mobile`、`/payment-batches`、电脑和手机公司借款入口均返回 200,前端主脚本正常加载;新识别接口未登录返回 401。
以上公网路由和部署后 13/13 明细沿用发布会话回报,本次未重新请求公网。路由可达、版本检查和未登录拦截不等于登录后的真实业务闭环通过。
### 财务交接与仍开放事项
- 财务在“公司借款”选择“上传回单登记借入”,上传 PDF 后逐项对照原件核对预填值及出借人建议,尤其姓名、账号和流水号;补填未还本金、核对截止日并勾选两项确认后保存。借款与原件一起保存,状态为“余额待核实”。
- 后续仍需补协议、余额核对材料及代账引用,确认余额,再登记公司代表授权并由马经理确认。上线不代表真实台账、授权或首笔还款已经办理;AC5 及 N5/N6 真实业务验收保持开放,真实写入与付款按各自授权执行。
- 两份真实回单已在本机解析验证,姓名、账号、流水号尚未逐值独立比对;真实云 OCR 未验收。保存前人工核对不能省略。
- 员工授权翻页超时根因未定。r8–r11 虽通过,但未确定性触发原失败分支,不能据此断言已修复、仅为测试脚本问题或已证明不影响线上。
- 第五轮独立复核的非阻断观察 N1(OCR 无效编号提示为 `missing`,本地为 `invalid`)保留,不影响既有拦截结论。
### 本次补记验证
仅修改本任务 `prd.md` 与 `implement.md`,未改产品代码。任务上下文校验、Trellis 治理、流程基线与 `git diff --check` 通过;文档登记审计为 0 错误、1 条既有警告(22 份未登记文档),本轮未修改 `docs/`。未重跑业务测试。补记尚未提交,不改变已部署产品版本或父任务状态。
## 2026-10-10 N5-P 第五轮独立复核通过(发布前历史记录)
第五轮复核(`independent-review-r5-20261010.md`)结论为 PASS_WITH_NOTES:此前要求修改的问题均可关闭,没有阻断项。复核方独立验证:
- 相关单测 100 项通过;
- 前几轮的 27 个探针,以及新增的 14 项关联与边界检查通过;
- 两份正式回单在本机复测通过,云端调用 0。
非阻断观察 N1:OCR 读出无效流水号或凭证号时,值会被拒绝,但字段提示显示为 `missing`(未识别);本地读出同类无效值时显示为 `invalid`。两种情况都不会预填错误值,也不会绕过多页拦截。本轮不改代码,下节“无效编号记 invalid”的说法仅适用于本地文字层。
AC39 的独立复核部分在该时点已完成。当时下面几项仍需另行处理或单独授权(最新进展见顶部发布记录):
- 提交、最终候选完整门禁、推送和部署;
- 真实回单上的姓名、账号、流水号逐值核对,由财务保存前对照原件完成;
- 员工授权翻页超时(根因未定)。
## 2026-10-10 N5-P 第四轮复核修复(第五轮复核已通过)
第四轮复核(`independent-review-r4-20261010.md`)结论为 CHANGES_REQUESTED,剩 2 处,都涉及多页文件能否确认为同一笔交易。
- R4-1 跨页关联:
- 每页分别记录带类型的编号(`pageIds`)。两页共享同类型、同值的编号才算关联;同一页上的流水号和凭证号视为属于同一笔交易。全部页面必须连成一组(`unlinkedPages`),否则拦截为 `pages_unverified`。
- OCR 读出的页按同一规则加入。已知编号冲突仍判为 `multiple_transactions` 并拦截。
- 文字相同但编号类型不同(一个是流水号、一个是凭证号),不算关联。
- R4-2 编号整段校验:`parseReference` 要求整段匹配,不再截取前缀参与比较。本地文字层读到带未知后缀、超长或相同前缀不同后缀的编号时,记为 `invalid`;OCR 读出的编号也做整段校验,无效值被拒绝,但提示为 `missing`(见第五轮 N1)。
验证:
- 复核方三轮探针共 27 个,用当前代码全部符合预期:第四轮 10 个,第三轮 8 个,第二轮 9 个。
- 单测:借入回单 71 项(新增 8 项)。
- 变异:新增 3 个,连同 2 个重跑的,共 5 个全部捕获。旧的“页面覆盖”两项变异所针对的代码已被关联逻辑取代、锚点已不存在,已从清单删除。
- `browser-r7.log`:HTTP 9 项、浏览器 8 项、数据库 9 项通过。
- `regression-r11.log`:完整回归通过,检查项相加 248,去重 189。
- 两份真实样本:编号改为整段校验后,流水号仍正常提取,9 个字段齐全,无拦截,云端调用 0,原件不变。
仍开放:
- 员工授权翻页超时根因未定。
- 待第五轮独立复核。
- 未提交、未推送、未部署。
## 2026-10-10 N5-P 第三轮复核修复(未提交;后续修复见上节)
第三轮复核(`independent-review-r3-20261010.md`)结论为 CHANGES_REQUESTED,剩 2 项,均属 RR1;RR2、RR3、RR4 已由复核方关闭。
- R3-1:一页只有读到能通过解析的流水号或凭证号,才算属于本笔交易。文字层与 OCR 使用同一判定标准:无效值、OCR 返回空,以及只有金额相同,都不能解除“多页无法核实”的限制。单页扫描件仍可人工补填。
- R3-2:内部保留本地读到的全部流水号和凭证号(`identifiers`),跨来源时按同类编号逐一比较。仅凭证号不同(包括流水号相同的情况)也判为多笔交易。表单预填仍优先使用流水号,这只是显示顺序,不影响比较。
验证:
- 复核方第三轮 8 个探针、第二轮 9 个探针,用当前代码重跑全部符合预期(拦截项已拦截、对照项正常放行)。
- 单测:借入回单 63 项(新增 6 项);回单分类与 OCR 测试仍通过。
- 变异:新增 4 个单元变异全部捕获。“文字层只有金额的页面”首轮未捕获,原因是缺少可读的只有金额页面;在生成器中加入“无流水号”选项并补测后已捕获。
- `browser-r6.log`:HTTP 9 项、浏览器 8 项、数据库 9 项通过。
- `regression-r10.log`:完整回归通过,检查项相加 248、去重 189。
- 两份真实样本:9 个字段全部提取,无拦截,云端调用 0,原件不变。
仍开放:员工授权翻页超时根因未定(r8–r10 均通过,但没有确定性触发失败分支);待第四轮独立复核;未提交、未推送、未部署。
## 2026-10-10 N5-P 第二轮复核修复(未提交;后续修复见上节)
第二轮复核(`independent-review-r2-20261010.md`)结论为 CHANGES_REQUESTED,共 4 类问题,本节记录修复结果。
- RR1 混合页与跨来源交易:
- 按页记录是否读到本页自己的金额、流水号或凭证号;没读到的页单独送一次 OCR(仍受总时限约束、不重试)。
- 多页文件仍有页面无法核实时,记 `pages_unverified` 并拦截;单页扫描件仍可人工补录。
- OCR 读到的金额或同类编号与本地不同,记 `multiple_transactions` 并拦截。
- RR2 乱序说明:凭证限制同时检查原始存储顺序与按位置重建的阅读顺序,结果取并集。共享的付款分类代码不变。
- RR3 打印日期:顶行无标签日期规则跳过紧跟在“日期/时间”类标签后的日期;`parseDate` 改为整段校验,可带时刻,也接受 8 位数字日期。上一节写“到账日期同样处理”时,这一项其实尚未完成,以本节为准。
- RR4 前端版本:对话框冻结选择出借人时的身份版本和账户版本。列表刷新后版本变化,会清除两个确认勾选并提示重新核对;保存使用冻结的版本。
验证(证据目录同上):
- 复核方的 9 个解析探针在修复后全部得到正确结果(会拦截的已拦截,日期留空或标为无效)。
- 单测:借入回单 57 项,加回单分类与 OCR 共 86 项通过。
- 变异:新增 6 个单元变异全部捕获(`mutations-summary-*.json`)。
- 浏览器 `browser-r5.log` 共 8 项,新增电脑与手机各 1 项:断网后恢复触发列表重新获取,勾选被清除;重新核对后保存,提交的是新版本,数据库中借款 1 笔。
- 完整回归 `regression-r9.log` 通过,检查项相加 248、去重 189。
- 两份真实样本用当前代码复测:9 个字段全部提取,无拦截,云端调用 0,原件摘要不变。
仍开放:
- 员工授权翻页超时根因未定。r8、r9 均通过,但都没有确定性触发失败分支。该项属于原有员工场景,不在 N5-P 改动范围内,保留为开放项。
- 待第三轮独立复核。
- 未提交、未推送、未部署。
## 2026-10-10 N5-P 复核修复与真实版式适配(未提交;后续修复见上节)
独立复核(`artifacts/qa-flow/loan-incoming-prefill-20261009/independent-review-20261010.md`)结论为 CHANGES_REQUESTED,4 项 P2 均已复现。本节记录修复结果;下面首轮实现记录中的统计和基线写法有误,以本节为准。
### 更正
- 实施基线是 `45737ccb`,不是首轮写的 `c1034bbe`。
- 首轮称 r5 共 247 项,实际是各层检查数组直接相加,含重复,去重后为 188 项。r5 也没有运行新入口的浏览器场景,那 6 项来自单独的 `browser-r2.log`。
### 复核问题修复
- R1 多笔交易:金额、流水号、凭证号任一出现不同值,即判为多笔交易,本地与 OCR 一致处理,人工补号也无法解除。同一交易跨页重复仍允许。
- R2 外币:本地发现非人民币时,在调用 OCR 前就拦截;OCR 币种与本地不一致记为 `currency_conflict` 并拦截,不再把已知币种清空成“未知”。
- R3 OCR 时限:每页发送前检查共同截止时刻,超时后不再发送后续页。
- R4 金额:整段值必须是一个合法的人民币金额,千分位错误或超过两位小数记为 `invalid`,不再截断成另一个金额。到账日期同样处理。
- AC37 来源变更:保存时携带所选出借人的身份版本和账户版本,识别后出借人被修改即返回 `loan.version_changed`。
### 真实建行版式适配
经用户授权,本机只读运行脱敏结构探查:已知标签保留,数字改为 9、字母改为 A、其他汉字改为“某”。不调用云端、不写库、不保存文件,原件摘要前后一致。两份借入回单是“单位客户专用回单”表格版式:PDF 文字顺序与阅读顺序不同,付款人、收款人是竖排栏头,日期在顶行且没有标签,金额分大写和小写,右侧竖排联次说明中也含“收款人”。
据此新增以下处理(`PARSER_VERSION` 改为 2):
- PDF 工作线程按需返回文字位置(付款回单分类不使用,结果不变);按纵坐标归行、行内按横坐标排序;竖排文字不并入横向行。
- 顶行日期规则;`(小写)` 金额标签。
- 付款人、收款人栏头须恰为该词且付款人在左。
新增同版式的合成生成器 `syntheticCcbIncomingPdf`,内容全部虚构。
最终代码下两份真实样本:金额、到账日期、流水号、币种、双方名称及账号全部提取,方向为入账,无拦截项,云端调用 0。具体数值是否正确,仍由财务保存前对照原件核对。
### 验证
- 单测 46 项(较首轮新增 24 项);回单分类相关测试仍通过。
- 隔离 HTTP 9 组,新增建行版式识别、主体建议与保存;浏览器电脑/手机 6 组(`browser-r4.log`)。
- 变异 18 个全部捕获(HTTP 12 个、单元 6 个,`mutations-summary.json`)。其中“行内按横坐标排序”首次未捕获,原因是合成文字同一行的基线完全相同,补充基线偏移用例后已捕获。
- 借款完整回归 `regression-r8.log` 通过,检查项去重后 189 项(相加为 248)。
- r6、r7 均在员工出借人浏览器场景的手机端翻页处超时:等待响应在点击完成前超时,未处理的异常导致进程退出,未留截图。r8 改为点击与等待一起处理并设 30 秒点击时限后通过,但当次没有触发失败分支,无法确认是修复生效还是恰好不需翻页,**根因未定**。
- 工作区另有一处测试调整:原对账浏览器场景固定 `timezoneId: 'UTC'`(见首轮记录)。
### 仍开放
- 需要再次独立只读复核本节改动(AC39)。
- 真实样本只验证了字段能提取出来,没有核对数值。真实云端 OCR 未调用。
- 未提交、未推送、未部署。
## 2026-10-10 N5-P 本地实现与验证完成(首轮,未提交;统计与基线见上节更正)
用户先听取“暂缓”建议后明确要求实施,选择**完整方案**并指定由 Claude 会话实施。基线为本地 `c1034bbe`(线上 `45737ccb`),已执行 `task.py start`。本节记录实际结果;下方原计划保留规划时点。
### 实现
- 服务端:新增 `loanIncomingReceipt.js`。它复用受限 PDF 文字工作线程(从 `inspectReceiptDocument` 抽出 `extractReceiptTexts`,付款回单分类语义不变),按白名单标签逐行读取金额、记账/交易日期、流水号/凭证号、币种、双方名称与账号;同一字段出现不同值时留空并标为“歧义”。多页同一交易可合并,多笔交易、非最终、失败/处理中、非人民币一律拦截。本地缺必填字段时,才调用一次现有腾讯 BankSlipOCR:每页最多一次、总时限 20 秒、不重试,结果只补空缺,不覆盖本地值,也不能解除限制。
- 预填上下文用 AES-GCM 字段加密封装,绑定用途、经办人、文件 SHA-256、解析版本和 30 分钟有效期;只经请求体传递,响应 `no-store`,账号只返回遮罩值。
- 新接口:`POST /company-loans/incoming-receipt/recognize` 只做识别,不写任何数据;`POST /company-loans/from-incoming-receipt` 先在事务外写入原件,再在同一事务内锁出借人、创建借款、创建 `incoming` 原件并写两条审计,失败或幂等重试时删除本次新写的对象。保存时重验收款主体:公司支出或收款方为其他主体的回单拒绝保存;审计只记录字段来源和被更正的字段名。
- 同一出借人的 `incoming` 原件按摘要唯一:新入口与原有附件上传都检查,原上传路径改为先锁出借人、再锁借款,与还款创建的锁序一致。
- 前端:新增“上传回单登记借入”入口和 `LoanIncomingReceiptDialog`,复用现有组件。迟到的识别结果不覆盖人工修改或新选的文件;切换账号、卸载时中止请求;原“登记借入”手工入口保持不变。新增 4 个错误码,三处已同步登记。无新增迁移,仍为 82 项。
### 验证(证据目录 `artifacts/qa-flow/loan-incoming-prefill-20261009/`)
- 单元测试:新增 22 项;相关付款回单、报销路由及授权策略合计 349 项通过(BIFF8 需指定 `PAYMENT_ORDER_PYTHON_BIN`,不设时有 2 项报环境不可用)。Prisma 校验、前端类型检查与构建、错误码合同、UI 规则均通过。
- 隔离 PG HTTP 8 组:识别不落数据、保存后余额待核实且带原件、重试与请求键、跨入口原件重复、上下文绑定(他人、换文件、篡改、过期)、受限/支出/他方收款拦截、无 OCR 时人工补录、审计失败整体回滚并删除对象、并发与新旧入口竞争只成功一个。
- 浏览器电脑/手机共 6 组(`browser-r2.log`):预填、人工更正、同账号令牌过期只重试一次后成功、受限文件拦截、迟到结果不覆盖新文件、真实切换账号后迟到 401 被中止且不以新身份重发。
- 变异 10 个全部被测试抓到(`mutations-summary*.json`)。首轮“公司支出”未被抓到:原用例同时触发了“收款主体不符”,已改为只写付款方后单独验证。
- 借款完整回归 `regression-r5.log`:247 项检查全部通过,含 HTTP 116 组、浏览器 45 组。r1–r4 的失败保留:r1–r3 是原有对账浏览器场景用 UTC 时间填表、浏览器却沿用本机 CST,北京时间 0–8 点运行必然失败,已在该场景显式固定 `timezoneId: 'UTC'`(r3 的补丁实际未生效,r4 才生效);r4 是新场景多建的出借人挤动了员工场景的分页,已把借入回单场景移到完整运行最后。未改任何业务断言。
- 既有测试素材调整:同一出借人多笔借款原先上传同一份 `incoming` 测试 PDF,现在每笔各自生成唯一内容,其他材料类型不变。
### 未完成与边界
- **独立复核未做**:实施与自检出自同一会话,不能算独立复核(AC39 保持未勾选),需另行只读复核。
- **真实建行版式未验证**:解析只在合成的“标签 值”同行版式上验证过。真实借入回单若采用标签与数值不同行的表格版式,本地可能读不出字段:OCR 未启用时转人工填写,启用时会调用云端。两份真实借入回单的本地只读试解析,或真实材料的云端识别,都需另行授权。
- 未提交、未推送、未部署;未调用真实 OCR,也未访问生产。
## 2026-10-09 N5-P 原借入回单识别预填执行计划(规划时点)
### 当前阶段与授权
用户已要求规划,复用本任务,当前仅修改 PRD/design/implement。2026-10-09 在 `main`、本地基线 `45737ccb` 核对 `task.py current --source` 为 none;规划阶段不调用 start,不手写运行时指针。父任务的 `in_progress` 代表历史已批准工作,不代表 N5-P 实施已批准。用户转交上一会话的部署结果已在 PRD Current Status 标记来源,本轮未连接生产重验。
无原生 update_plan,以下为本阶段执行清单。inline 模式由主会话实现和检查,不派 implement/check 子代理;稳定 spec 直接按需加载,不把临时计划、日志或本文件登记进 jsonl。
### 顺序与验收映射
- [x] P0 规划:核对入口、文件策略、PDF 工作者、银行 OCR 字段、数据模型与隐私规则;形成 PRD P1–P6 / AC32–AC39、design P-A–P-E 和本清单。保留原阶段结果;实施批准仍待用户给出。
- [x] P1 启动:收到本方案实施批准后,官方 `python3 .trellis/scripts/task.py start 09-17-company-loan-principal-repayment`,读回 current 与 phase,再加载 trellis-before-dev。记录批准范围、实际基线及执行位置;若届时 N5 已人工登记,不迁移或重建既有数据。
- [x] P2 解析与预填(AC32、34、35):在受限文字提取上加借入字段白名单、金额/日期/引用歧义处理及相对公司方向判断;补扫描 PDF 的受控 OCR 适配及关闭/失败降级。复用底层,保留旧付款凭证分类和归一化结果。完成正常、非最终/失败/支出、多交易、格式/字节限制、OCR 零调用/有界调用的单元反例。
- [x] P3 保存合同(AC33、36、37、38):添加无业务持久化识别接口与带同一原件的原子登记接口;实现专用加密上下文、身份/文件/时效绑定、最终主体重验、请求键及摘要去重、旧上传竞争和失败补偿。审计与业务同事务;保存不确认余额。扩展现有真实隔离 HTTP/PG fixture,证明两种顺序、故障回滚和旧路径兼容。
- [x] P4 电脑手机入口(AC32、33、35、37):沿原弹窗复用组件实现上传、识别预填、人工更正和一次保存;保留手工登记。覆盖换文件、取消、失败重试、手改保护、来源缺项、迟到401换账号及同身份重试。用户只需选择一次文件,保存后原件已在该笔材料中。
- [ ] P5 整体验证与只读复核(AC38、39):运行最小完整检查集和原借款专项回归,按变化范围覆盖共享付款解析。权限与保存流程变化需要独立只读复核;本会话 inline 限制下不派检查代理,准备精确交审范围并标为待外部独立复核,不能沿用 AC28–AC31 的复核结论。有可用且合规的独立只读会话后接收实际结果。
- [ ] P6 文档与交接:按实际证据更新各 AC、PRD 状态及本清单;经 trellis-update-spec 判断后补既有借款/附件规约,不提前把提案写成已生效事实。报告本地实现、独立复核、实样/OCR及公网状态。提交、推送、部署、真实业务与真实材料云识别分别按明确授权办理。
### 预计修改范围
- Backend:`server/src/routes/companyLoans.js`、`server/src/services/companyLoans.js`,新增借入识别/保存专用服务;必要时对 `paymentReceiptDocument.js` / `paymentReceiptDocumentWorker.js` / `paymentReceiptOcr.js` 做最小底层提取复用。现有 `paymentDocumentReady` 的付款方向、成功及核销规则不改变。错误理由新增时同步注册、客户端映射及既有合同测试。
- Frontend:`client/src/pages/CompanyLoansPage.tsx`、`client/src/api/companyLoans.ts`,按可读性抽出与借入登记直接相关的弹窗组件;不重构整页或员工档案。
- Tests:现有 `scripts/qa/test-company-loan-db.cjs`、HTTP/browser fixture 接入新增合成场景;共享解析测试与新借入服务测试按实际职责分文件。新增代码文件名在实施时固定,本计划不预称其已经存在。
- 不改 schema/migrations、生产配置、付款状态机、公司授权规则或既有员工资料。若证据证明必须改这些边界,先补风险/兼容设计并取得范围批准。
### 最小验证集(实施后执行)
1. 后端改动 `node --check`;`cd server && npm run prisma:validate`;运行新增借入服务测试及已有 `tests/unit/services/paymentReceiptDocument.test.js`、`paymentReceiptOcr.test.js`,若碰共享归一化再覆盖对应消费者。使用项目 Vitest 实際脚本,不能以一份针对性测试冒称全量通过。
2. `cd client && npm run typecheck && npm run build`;错误理由/UI合同沿现有 `check-error-reason-contract.mjs`、`check-ui-design-rules.mjs` 按影响执行。
3. `RUN_ISOLATED_LOAN_DB_TEST=1 RUN_ISOLATED_LOAN_BROWSER=1 node scripts/qa/test-company-loan-db.cjs`:仅新建一次性数据库、合成身份/回单,沿现有受控 Python/浏览器缓存环境;保留原借款/员工/关联方场景。执行前确认适用环境,禁止指向本地业务库或生产库;清理只针对本轮 owner。
4. 必须有确定性交错:重复保存、同请求不同文件、相同原件不同请求、识别后出借人资料变更、旧上传与新保存、审计失败/存储失败。读取原件哈希、借款/附件/审计数量及权限结果,不只断言 HTTP 200。必要的权限/绑定守卫做少量定向变异,环境失败不算捕获。
5. 浏览器电脑/手机各实际完成上传预填、人工修正、保存后附件与待核实余额;无 OCR 路径可完成手工登记。覆盖多笔/非最终拒绝、迟到响应与换账号取消,且保存未触发余额确认/授权/付款。合成 PDF 和 provider 替身明确标记,不调用真实云端或保留真实银行资料。
6. 任务文档检查:`python3 .trellis/scripts/task.py validate 09-17-company-loan-principal-repayment`、`node scripts/qa/check-trellis-governance.mjs`、`node scripts/qa/check-process-contract.mjs --baseline --json`、`node scripts/qa/audit-docs.mjs --check-registry`、`node scripts/qa/check-sensitive-content.mjs`、`git diff --check`。未改历史 Issue CSV,不新建 CSV 执行合同。
### 规划交付检查
2026-10-09 规划文档检查:任务 validate、Trellis 治理、流程合同 baseline、文档索引、敏感内容扫描及 `git diff --check` 均通过。文档索引仍有既有 22 份未登记文件的 1 条汇总警告;inline 可选的 implement/check jsonl 缺失按规则跳过,不宣称注入已配置。新增 P1–P6、AC32–AC39 与设计/清单已收敛核对,现有历史验收和开放项保留;只有本阶段实施批准待取得。没有运行产品测试、调用真实 OCR 或实施/部署;不把本节计划命令当作已执行证据。
## 2026-10-09 N5 员工出借人选择调整(本地实现与验证完成,未提交)
用户提出从现有员工选择出借人并复用资料,避免重复手录。已只读核对员工主档、敏感银行卡维护接口、借款登记/身份/账户接口及电脑手机共用页面;实现基线为本地 `c1034bbe`,线上仍为 `beb9f02c`。用户已明确确认方案,本轮接续本地实现及针对性验证;不连接生产、不代录真实数据,提交、推送和部署不在本轮授权内。
实施顺序:
1. 增加受现有财务和银行卡权限保护的员工资料预览及关联动作;服务端读取姓名、银行和加密账号,版本、重复及并发检查与审计同事务处理。
2. 把员工出借人入口改为选择与确认,移除该路径重复手录;已有登记复用,缺资料指向原员工维护入口;需要使用更新后的员工资料时显式核对并沿既有在途/版本规则刷新。使用既有组件,不引入新视觉体系。
3. 以合成数据完成 AC28–AC31 的正常与拒绝场景、并发和桌面/手机办理流程;资金守卫做必要的针对性变异,并检查旧付款快照及两人关联审批规则保持。
4. 做任务与相关前后端检查、只读复核,按实际能力报告独立复核状态。完成后汇报本地差异及验证,再按授权提交;推送、生产查询、部署和真实台账写入仍各自批准。新候选发布时重新取得完整门禁,不沿用 `beb9f02c` 回执。
范围限于现有员工资料复用与相关借款入口;不改当前报销待办、回单核验口径或生产批次状态。原非员工入口保留,技术员工不参与审批。优先复用现有表;若需要新迁移或存量合并,先补具体影响与批准,不顺手执行。
### 已实现内容
- 新增员工来源预览、关联和显式刷新服务及三个接口;受财务角色、`loan.manage` 和银行卡权限保护。只返回遮罩摘要;客户端不能另传姓名或账号。服务端读源、核对公司与版本,关联真实员工并加密保存借款侧资料及审计,不创建员工、不生成借款或付款。
- 同公司同员工的唯一匹配登记复用;历史重复、归档、旧入口绕过及预览后来源变化均拒绝。复用和创建都保存当前经办人的请求键绑定,防止同一键跨员工或公司使用。已有出借人先锁出借人,再排序锁员工;员工使用 `FOR NO KEY UPDATE`,兼容审计外键的 `KEY SHARE`。
- 员工资料不一致时要求显式“使用当前员工资料”,有在途占用不能刷新。刷新重验身份/账户/来源版本,同时推进身份与账户版本、留存核对审计并使旧公司代表授权失效;原本金及历史付款快照不改。员工关联记录不能再走手工收款账号 PATCH。
- 电脑、手机共用原组件样式:默认员工选择、公司明确核对、遮罩资料、缺项提示及有权限时的维护入口;非员工登记单列保留。资料查询按身份/员工/公司隔离并可取消;两个新写请求在卸载或切换身份时取消,避免迟到 401 以新账号重发。此保护不宣称已覆盖所有旧页面写请求。
- 本轮无新增迁移,仍为 82 项。旧测试为同一员工反复建立同公司出借人,现改为每个独立场景使用独立的合成公司;原业务断言保留。测试错误包装改为正式服务的 `requestId/error` 结构,保留原拒绝断言并验证实际页面错误提示。
### 独立只读复核与修复
本次复用了财务与界面两名只读复核代理,均不改文件、不重跑测试、不连接生产;本轮结论不借用 N3 的历史复核。两者接收修复与专项回执后均为 **REVIEWED_NO_BLOCKER**。
| 发现 | 修复及见证 |
| --- | --- |
| 财务 P2:复用未绑定请求键,旧键可能用于另一个员工 | 创建/复用的审计均保存来源及请求键,按经办人串行;顺序、并发与移除绑定的反例通过。 |
| 财务 P2:员工 `FOR UPDATE` 与审计员工外键形成锁循环 | 改为 `FOR NO KEY UPDATE`;实际 HTTP 关联和刷新经数据库 gate 确定性交错,两请求均完成;恢复旧锁时观测 PostgreSQL 死锁计数增长。 |
| 界面 P1:仅隔离回调不能阻止旧 POST 在切换身份后因 401 被重发 | 两个写动作透传并在卸载/身份变化时终止 `AbortSignal`;同一浏览器文档中真实退出/登录另一财务,延迟旧 401,验证取消、无重发、无错误写入/审计,同时验证同身份自动刷新仍成功。 |
### 验证回执
证据根目录:`artifacts/qa-flow/loan-employee-source-20261009/`,均为本地合成数据。
- `mutations-r6.log`:82 迁移、10 组员工 HTTP、9 个针对性变异、资源清理全部 PASS。变异覆盖银行卡权限、来源版本、旧身份重复入口、员工串行锁、外键锁兼容、在途占用、出借人版本、复用请求键及必要审计;普通超时或环境失败不能算捕获。
- `browser-r3.log`:10 组员工 HTTP 和 8 组电脑/手机浏览器场景 PASS,包括历史借入、余额核对、财务登记授权及指定经理确认;关联/刷新同身份 401 恢复、跨身份迟到请求取消均实际执行。截图在 `browser-LWICsl/`;横向溢出检查和主会话截图走查通过。
- `unit-r1.log`:本轮针对授权策略和错误消息合同的 2 文件、948 项通过;其输入未改变,后续复用。`frontend-build-r5.log` 的类型检查及构建、Prisma 校验、错误码合同、UI 规则和差异检查通过。未运行本次服务端全量或完整发布门禁。
- 完整借款 HTTP/浏览器回归:`regression-r2.log`、`regression-r2-process.json` 和去重汇总 `regression-r2-summary.json` 为 PASS,退出 0;82 迁移、原有 116 组 HTTP 加新增 10 组(共 126 组)、45 组浏览器、9 组基础数据库检查及资源清理通过。45 组已包含关联模式的 18 组和新入口的 8 组,不重复累加。首轮收到 SIGTERM(退出 143),没有最终回执,不能算通过;信号来源未证实,原日志和 `regression-r1-interruption.json` 保留,已按 owner 标签核对并只清理该轮隔离容器/临时目录。第二轮使用同一命令和断言在独立进程执行,不缩小范围、不增加用例重试。
- 较早失败记录保留:首轮账号解密返回空值的分类问题已修;前两轮浏览器分别暴露选择框可访问名称和测试错误包装问题,已修并完整重跑专项;`mutations-r3`–`r5` 的合成交错类型/顺序及捕获分类未通过,不计入通过次数,最终以 r6 为准。
AC28–AC31 的本地实现及验收已完成,最终文档治理结果见本目录 `final-checks.json`。文档索引保留既有 22 份未登记文件的警告,无新增错误,不在本轮整理无关文档。N5 真实台账/公司授权登记和 N6 首笔真实还款仍待办理,整体任务保持 `in_progress`;没有提交、推送、部署、访问生产、调用真实 OCR 或代录真实资料。线上仍为 `beb9f02c`;新候选以后发布须重新跑完整门禁。
## 2026-10-09 N4 发布结果与 N5/N6 接续
本节记录已完成的发布,候选为 `beb9f02c19970aa452c3fac02debfb10db0d4a3d`。Claude 会话执行发布及核对、由用户转交结果;主会话另核对本地候选、只读汇总、部署与补验日志、独立复核记录及生产 PDF 冒烟回执。本轮只更新现有任务文档,没有重新连接生产、执行付款或改动程序;整体任务仍为 `in_progress`。
### 本次发布事实
| 检查 | 已取得的结果与证据 |
| --- | --- |
| 固定候选门禁 | `artifacts/release-gate/release-beb9f02c-20261009/release-result.json` 为 PASS;static/full-local 通过,82 迁移,服务端 4558 通过/1 项既有可选跳过,浏览器 372 全通过且零失败/跳过/重试。离线接收记录为本次准备目录的 `gate-reception-n4.json`,只绑定该候选。 |
| 独立代码复核 | `4c37fcee..1c4633b6` 的 62 个文件,结论 `REVIEWED_NO_BLOCKER`,无 P0/P1;复核人未重跑测试。其后 `beb9f02c` 仅补三份文档,P2 已落规则,P3 继续后置。原复核正文见下节,接收记录见 N3 准备目录。 |
| 发布前生产只读核对 | `production-readonly-summary-20261009.json` 为 PASS;2026-10-09 15:59(北京时间)观察的出借人、借款、还款、批次、分配、回单及已知导出均为 0。生产 73 项、本地候选 82 项,实际差集 9 项;无未完成/回滚迁移、重复名称、生产额外项或 checksum 不一致,缺表与待应用迁移相符。只读事务已 ROLLBACK。该结果仅代表当时 OA 存量。 |
| 推送及部署 | `origin/main` 已从 `9cbefdf2` 更新到 `beb9f02c`。远端服务最终运行该候选,82/82 迁移应用完成。原部署入口因 SSH 断开报告 `DEPLOY_EXISTING_FAILED`,不改写为一次成功;补验过程见下文及 `deploy.log`。 |
| 合同刷新及部署后复核 | `post-deploy-refresh.log` 记录合同刷新 PASS;`post-deploy-preflight-2.log` 为最终补验,Claude 会话核对 13/13 PASS,迁移 `pending=none`。刷新前的 12/13 和失败入口记录保留在 `post-deploy-preflight.log`。 |
| 公网基础检查 | Claude 会话核对 `/ready` 的 `ok:true` 和版本 `beb9f02c1997`,`/health`、首页、浏览器方式请求的登录/移动/付款批次/公司借款页面及前端资源正常。本次接收这些检查结果,未另行登录真实业务账号或复跑公网矩阵。 |
| 生产 PDF 解析冒烟 | `production-pdf-smoke-result.json` 为 PASS、退出码 0;运行完整 SHA 与候选一致。合成单页结果为 `bank_receipt` / `pdf_text`、明确成功、`debit`、`issues:[]`,耗时 521 毫秒。未写数据库、未调用云 OCR、未在容器保存样本;本地生成器、样本摘要及命令摘要留在同目录。 |
除另列路径外,上表本次发布证据均位于 `artifacts/qa-flow/release-beb9f02c-20261009/`。公网基础检查不扩大为真实借款办理或已登录角色的完整业务验收;合成 PDF 只证明该生产解析链路可用。
### 断连、补验及回退边界
- 本地 SSH 在 init 镜像构建期间断开,部署包装器退出,但 Claude 会话只读确认远端 `deploy.sh` 继续完成并重启服务。包装器尾部未执行的合同刷新和部署后复核已分别补跑;第一次复核因备份服务记录的版本尚未刷新为 12/13,刷新后最终 13/13。保留各次原日志及失败码,不凭进程退出码推断线上版本,也不再次发布已完成的候选。
- 部署检查里的 `rollbackWindow=OPEN` 来自既有合同终止记录检查(`terminated_status_count`),不能据此允许借款旧语义代码直接回退。产生关联决定、晚到补记或追回等事实后,继续执行本任务已定的兼容处置和回退限制;本次没有新增恢复演练或回退授权。
- 本次部署前未做手动轻量快照:用户明确决定接受无恢复点风险,自动备份模式未切换。若迁移或部署后出现数据问题,只能现场修复,不能整体回退到部署前状态。
- 原门禁与线上版本继续绑定 `beb9f02c`。这次事后文档记录可形成独立本地提交,提交仍需明确授权;不推送、不重新部署、不改写原门禁,下次发布对最终候选重新取得有效回执。本轮不重跑完整门禁或应用测试,按文档差异执行任务/治理/流程及差异检查。
### 后续两项业务工作
1. **N5 真实台账与公司授权登记(待办理)**:财务使用已整理的原件和已确认事实,在 OA 登记真实出借人及员工关联、公司主体、收付款账户、两笔历史借入、未还本金、余额截止日和原会计记录引用;留存依据,不生成当天新增收款或重复历史凭证。再登记已有公司代表权及覆盖借款,由马经理在 OA 确认。技术员工不参与。真实写入获准后按页面逐项办理,本轮没有代录。
2. **N6 首笔真实还款与会计交接(待实际付款安排)**:办理前确定本次金额、逐借款分配及日期;财务申请、马经理按关联模式批准、财务导出并在网银实际提交,留存本笔提交详情和正式付款回单,完成对应核验/必要人工确认、核销及代账交接。实际付款仍由有权人员操作;只核销本次已支付本金,不从余额推定全额还款,不为验收制造交易。
已确认的历史未还本金、本年无新增借还、开卡小额往来排除、收款账户及马经理公司代表权不再重复提问。首笔付款发生时再核对该笔提交与回单的对应关系;未覆盖的异常实样和 AC5 真实银行闭环继续开放。AC8、AC27 的本次软件复核与发布证据已补齐,整体任务不完成、不归档。以下记录保留各自历史时点。
## 2026-10-09 N3 独立复核接收与文档收尾
已接收用户回传的 Claude 独立只读复核,范围为 `4c37fcee..1c4633b6` 的 62 个文件,结论 **REVIEWED_NO_BLOCKER**,无 P0/P1。主会话核对交审包后确认:当前只有本文件新增复核记录,其余 61 个文件摘要仍一致;原始复核文字保留在下节。复核人未重新运行测试,不把第五轮结果写成独立测试结果。
- **P2 本期采用现有保守策略**:依据已批准 N1 设计第 2 条,图片与无可提取文字的扫描件 PDF 可继续上传、预览和 OCR 字段提取,但报销回单须由财务核对原件、录入付款依据,再由另一名合格人员独立复核;可读 PDF 仍须满足全部付款凭证条件才可自动核验。没有合格独立复核人时保持待核对,不能把借款关联确认推广到普通报销或要求技术员工参与。已补入 `docs/报销发票附件规则.md`,不修改程序,不扩大借款关联模式的适用范围。
- **P3 后续安排**:优先评估把文件读取及 PDF 解析移到锁外,锁内保留摘要、版本和全部状态重验,须以并发反例验证后单独实施;旧记录缺少云端限制字段的重检差异保留为已知限制;记账日期下限须先区分正常付款和历史补记等语义,再决定提示或硬校验。本轮三项均未实施。
- **验证依据**:`1c4633b6` 第五轮完整门禁及只读回执重验 PASS;82 迁移、服务端 4558 通过/1 项既有可选跳过、浏览器 372 通过且零失败/跳过/重试,源码一致性和专用资源清理通过。当前只收尾规则和任务文档,复用未变代码的验证,另做文档/治理检查,不重复全量业务测试。
- **提交与候选边界**:沿既有 N3 本地提交授权单独保存本次三份文档,实际提交和检查结果写入准备目录的接收回执。原第五轮 PASS 仍只绑定 `1c4633b6`;文档收尾提交不冒用该回执取得新 SHA 的发布资格。N4 冻结最终发布候选后须按现行门禁取得有效回执,不修改原回执或门禁规则。
- **下一阶段**:N4 发布准备纳入部署后的本地 PDF 解析冒烟:使用合成正式付款 PDF 检查解析依赖和工作线程可用,不调用真实云 OCR、不写业务。生产只读核实、推送、部署及 N5/N6 真实台账/付款仍按各自明确授权办理。整体任务继续 `in_progress`;下方“独立复核待完成”为各历史时点。
## 2026-10-09 独立只读代码复核(Claude,非实施会话)
范围按 `readonly-review-handoff-r5.json`:`4c37fcee..1c4633b6` 共 62 个文件,复核时逐个核对摘要,均与交审包一致。第五轮门禁 `1c4633b6` 为 PASS(82 迁移、服务端 4558/1 既有可选跳过、浏览器 372/372),本次复核未重跑测试,也未改动源码。
**结论:未发现阻断问题(无 P0/P1)**;有 1 项需要产品确认,3 项为低优先级,均可在启用前或后续处理。
- 已核对且无发现的部分:
- 迁移只做增量:关联授权与范围、事件不可改删;`approval_mode` 冻结后不可转换;所有决定记录在数据库层都校验授权版本/事件、`purpose`、确认人与经办人分离、范围一致。经办触发器拒绝确认人担任经办,同时禁用 Q6。
- 服务端 `decisionFields`/`assertDecision` 已接入以下消费者:付款审批/退回、清单、归属、终态、未付款、SR、晚到/追回、人工回单、最终核销/取消,覆盖完整。冲突原因只豁免收款人,已作废回单的上传人仍计入冲突。退回在数据库层禁止进入 `reviewed`。
- 锁序保持"批次 → 回单 advisory/附件 → 出借人 → 人员",授权停用只锁出借人,未发现逆序。
- 凭证分类采取保守策略:非最终、贷方、矛盾、多回单都会阻断,人工不能覆盖;`booked_debit` 不补造成功文字;PDF 解析在受限 worker 中运行,出错时视为未知。
- 4 处 e2e 修正(R106 就绪、企微 Worker 隔离、PWA 属性断言、报销人工回单 `paymentProof`)语义与原断言等价或更严,没有放宽期限、增加重试或删除断言。
- **P2 待产品确认**:共享报销消费者的行为有变化。`paymentDocumentReady` 的自动路径只接受 `pdf_text`,因此 JPG/PNG/WEBP 及扫描件 PDF 的报销回单不再自动核验。这类回单一律需要人工录入 `paymentProof` 并经独立复核(`server/src/services/paymentReceiptDocument.js` 的 `paymentDocumentReady`;`paymentReceiptManualReview.js` 中 `paymentProof` 会强制 `requiresIndependentReview`)。design 第 2 条隐含了这一点,但 `docs/报销发票附件规则.md` 仍写着回单支持 JPG/PNG/WEBP,没有说明图片回单不能自动核验。请确认可以接受,并补充规则说明。
- P3:`document-check` 在 `lockContext` 取得全局回单 advisory 锁(键 1)后,才读文件、解析 PDF 页数并运行最长 5 秒的 worker(`paymentReceiptManualPersistence.js` 的 `refreshReceiptDocument`)。这段时间内全系统的回单认领、人工核验和执行都要排队,默认 5 秒超时的并发事务可能失败。建议把读取和解析移到加锁之前,加锁后只复核摘要和版本。
- P3:旧记录重检只用本地 PDF 文本重新分类。原云端字段没有留存,所以 `withProviderRestrictions` 无法再次施加;若本地文本能判为正式回单并显示成功,旧记录可以直接自动匹配。风险低,因为是同一原件,但与新上传的双重检查不完全一致。
- P3:`booked_debit` 的 `bookedOn` 只限制不晚于今天,没有与批次审批或导出时间做下限比对。目前依靠字段匹配和交易唯一来兜底,可以考虑增加"不早于审批日"的提示或校验。
- 观察(非缺陷):所有经理/CEO 的导航都会出现"公司借款",非指定人员打开后只看到空的授权列表。单测已明确断言这一行为,视为产品选择。另外,生产镜像在构建时用 `npm ci` 安装 `pdfjs-dist` 及 ARM 版 canvas 可选依赖,部署后应实测一次 PDF 分类不是一律 unknown;若一律 unknown 不会造成错误放行,只会全部转人工。
独立复核状态:**REVIEWED_NO_BLOCKER**。真实还款、生产启用、推送和部署仍按原授权边界处理,本复核不构成公网或交付验收。
## 2026-10-09 N3 第四轮结果及第五轮候选验证
第四轮候选 `8e17e8df` 完整门禁为 **FAIL**:82 迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建及业务回归通过;浏览器 371 通过/1 失败、零跳过/重试。报销付款主链路、PWA 升级和企微历史三项均通过,环境、源码一致性及自有资源清理通过。
- 失败栈位于 R106 手机登录页首次全页截图:`Page.captureScreenshot: Unable to capture screenshot`,字体等待已结束。手机登录尚未执行;前次“手机登录失败”线索不能当作结论。安全登录日志、准确失败摘要与原回执分别保存在 N3 准备目录和第四轮回执,Chromium 内部唯一成因尚未证明。
- 原测试在 `goto` 后立即截图,未检查 React 页面就绪。由现有 `09-06-release-gate-integrity` 在截图前确认登录标题、输入和按钮;保留原截图、全部电脑/手机/管理员巡检、真实隔离后端登录、Worker 策略和原预算,不加截图重试、刷新或休眠。
- [x] 受管 `retained-local` 完整 R106 文件 1 项通过、零失败/跳过/重试,浏览器阶段约 32.7 秒;原手机登录前截图及后续员工/管理员巡检均完成,14 张截图和报告实际产出。环境、源码一致性及清理通过;证据为准备目录的 `r106-readiness-focused/` 及同级 process/summary 回执。不据单次通过倒推历史唯一成因。
- [ ] 任务/治理及主会话差异检查后,按 N3 既有授权本地提交,再对干净新候选运行原 `bash scripts/qa/run-release-gate.sh verify-candidate`。第五轮回执为 `artifacts/release-gate/loan-receipt-n3-20261009-r5/`,不预填 PASS。
- 前四轮 FAIL 均保留;验证期间冻结源码、测试和文档,实际提交、结果及交审信息写 ignored 回执。独立代码复核、真实还款与公网仍待;没有推送、部署、生产查询或真实 OCR。
最终候选及结论以第五轮回执和 `local-followup.json` 为准,以下历史时点不改写。
## 2026-10-09 N3 第三轮结果及第四轮候选验证
第三轮候选 `98bab397` 的完整门禁为 **FAIL**:82 个迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建及业务回归通过;浏览器 371 通过/1 失败、零跳过/重试。报销付款主链路和 PWA 跨版本升级通过。原回执及准确失败边界见 `artifacts/release-gate/loan-receipt-n3-20261009-r3/`;环境、源码一致性及自有资源清理通过。
- 唯一失败是 `internal-readiness-ui.spec.ts` 桌面企微历史页整页导航后等待标题超时,截图为登录页。确认该文件的模拟接口只在手机手动 context 屏蔽 Worker,默认桌面 fixture 遗漏既有合同;原运行没有请求来源证据,历史唯一成因仍未证实。
- 已由 `09-06-release-gate-integrity` 补文件级 Worker 隔离,并在原桌面导航中验证 refresh 与 `/api/me` 的 200、非 Worker 和预设 requestId。保留全部原三项用例、登录/会话、桌面只读、手机布局和截图,不改认证/PWA/借款资金代码、迁移、预算或全局并发。
- 修正后的完整文件受管定向 3 项通过、无失败/跳过/重试;新增响应来源检查、生产构建、环境/源码一致性/清理通过。证据为准备目录的 `internal-readiness-focused/`、`internal-readiness-focused.log`、`internal-focused-process.json`。原第三轮登录体验 16 项和 R101 3 项按未变输入保留,不累加成此次定向总数。
- 经主会话差异及任务/治理检查后按 N3 既有授权本地提交,再对干净新候选执行原 `bash scripts/qa/run-release-gate.sh verify-candidate`。第四轮回执为 `artifacts/release-gate/loan-receipt-n3-20261009-r4/`;前三轮失败不覆盖、不与定向拼接,不预填 PASS。
- 验证期间冻结源码、测试和任务文档,实际提交、完整结果、复核交接及专用浏览器清理写入 ignored 回执。独立代码复核、真实还款及公网仍待;未推送、部署、查询生产或调用真实 OCR。
最终候选及实际结果以第四轮回执和 `local-followup.json` 为准。以下保留前三轮历史记录,整体任务尚未完成。
## 2026-10-09 N3 第二轮结果及第三轮候选验证
第二轮候选为 `18315d11`,完整 `verify-candidate` 为 **FAIL**。82 个迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建和业务回归通过;浏览器 371 通过/1 失败、无跳过或重试。修正后的报销付款主链路实际走到执行及下游收口并通过。原始回执、失败定位及环境清理见 `artifacts/release-gate/loan-receipt-n3-20261009-r2/`,不可由定向结果抵扣。
- 唯一失败为 `pwa-cross-version-upgrade.spec.ts`。原始栈明确:B 版本 `expect.poll` 的回调直接执行 `documentBuildSha`,应用自动导航时旧执行环境被销毁,`page.evaluate` 抛错。冻结诊断另观察到 B 文档、控制器、缓存和资源已更新,但不据此宣称原断言通过。
- 已由现有 `09-06-release-gate-integrity` 承接这处验收测试修正,使用当前 `html` 的版本属性断言,保持原 45 秒期限和后续全部联合见证;不修改产品 PWA、资金代码、迁移、全局并发或零重试要求。
- 修正后完整 PWA 文件受管定向 1 项通过、零失败/跳过/重试;同一 origin/BrowserContext 的 A→B 控制器、缓存、实际加载、会话与负向断言通过,环境/源码一致性/清理通过。证据为准备目录的 `pwa-navigation-focused/`、`pwa-navigation-focused.log`、`pwa-focused-process.json`。
- 完成主会话差异与任务/治理检查后,按既有 N3 本地提交授权形成单独修正提交,不 amend 两个已有提交。第三轮完整回执固定为 `artifacts/release-gate/loan-receipt-n3-20261009-r3/`;正式命令仍为 `bash scripts/qa/run-release-gate.sh verify-candidate`,不以单例通过或前两轮已通过项拼接资格。
- 候选固定后冻结源码、测试及任务文档;实际提交、完整结果、只读复核交接和本轮专用浏览器清理写入 ignored 回执。独立代码复核继续待完成;不推送、部署、查询生产、读取真实 OCR 配置或操作真实数据。
当前实际候选和最终结果以第三轮回执及其 `local-followup.json` 为准;本节不提前宣称 PASS。以下记录保留前两轮各自的修正与验证事实。
## 2026-10-09 N3 首轮结果及人工核验测试补充
本地提交 `5a7a1352` 包含 N1–N2 的 31 个文件。首轮 `verify-candidate` 已完成且结果为 **FAIL**:static、82 迁移、服务端 4558 通过/1 项既有可选跳过、业务回归通过;浏览器 371 通过、1 失败、无跳过或重试。失败为报销付款批次主链路在人工核验提交时收到 HTTP 409、`VALID_001`,尚未执行付款。首轮完整回执和环境清理记录保留在 `artifacts/release-gate/loan-receipt-n3-20261009/`。
- 原测试的错误包装只保留通用文案,没有留下 `reasonCode` 或凭证分类;不能事后将本地解析超时写成已确认根因。失败摘要见准备目录的 `first-failure-summary.json`。
- 已确认的测试缺口:该链路人工录入全部付款字段,却未提交 `paymentProof`,依赖自动凭证分类恰好成功。现有服务端确定性回归证明:凭证未知时缺少明确原件依据必须拒绝,补充有效依据后仍须复核;本地受限解析允许返回未知。
- 本轮补全合成正式回单实际具有的“原件明确成功”依据和原件已核对声明,同时记录凭证类别/来源及失败时的允许列举业务原因。保留字段对应、拒绝自审、独立复核、最终执行和下游收口断言,不修改应用资金规则、解析限时或正式门禁范围。
- 修正后的受管限定重验通过:报销付款主链路 1 项,实际完成核销及下游收口,环境及自有资源清理 PASS;回单服务端 3 文件、93 项通过。本次实际解析类别为 `bank_receipt/pdf_text`,未知凭证分支由既有确定性服务端反例证明,不凭这次定向通过倒推首轮解析结果。证据为准备目录中的 `retained-manual-proof/`、`retained-manual-proof.log` 和 `guard-targeted.json`。
- 修复提交范围为 4 个文件:人工核验测试 helper、后端测试规约及 PRD/implement;应用服务、页面、数据库及门禁脚本均未更改。保持本地提交,不推送;新候选与完整复验结果见下述 r2 回执及其 `local-followup.json`。
- 先在受管新数据库限定重验报销付款主链路,并复用/核对已有未知凭证与不可覆盖限制的服务端反例;通过后形成新的本地修复提交,不 amend 原提交。随后对干净的新候选重新运行完整 `verify-candidate`,本轮复验回执固定为 `artifacts/release-gate/loan-receipt-n3-20261009-r2/`,结果以该回执为准,不提前写 PASS。
- 独立代码复核仍受当前 inline 指令限制而待完成;真实还款及生产启用未验,未推送、未部署、未访问生产或外发银行原件。验证期间不修改正在验证的输入。
下方 N3 安排及 N1–N2 回执保留各自历史时点;最新候选、修复和复验结论由本节所列回执记录。
## 2026-10-09 N3 本地提交与新候选验证(独立代码复核待完成)
用户在 N1–N2 完成回执后明确“继续下一步”,本轮按已说明的 N3 接续本地提交和新候选验证。提交范围为已核对的 31 项改动;源码、测试及规约与上一轮最终清单逐项摘要一致,本轮仅补本节和 PRD 接续记录。提交、验证的实际结果以本轮回执及 Git 记录为准,不提前记为通过。
- 单独形成一个本地提交:`完善付款回单凭证核验与本地重检(09-17-company-loan-principal-repayment)`,包含 27 个修改文件、4 个新增文件;不加入输入材料、本地验证产物或个人日志。提交说明保留“独立代码复核及真实还款验收待完成”,不推送、不部署。
- 复用 N1–N2 已通过且输入未变化的针对性结果;完成本轮任务/流程/敏感/差异检查后提交。新提交固定后运行 `bash scripts/qa/run-release-gate.sh verify-candidate`,其范围为 static 和完整受管 full-local;不调用发布入口,不以旧候选或限定重验替代。
- 本轮回执固定为 `artifacts/release-gate/loan-receipt-n3-20261009/`,准备与清理记录为 `artifacts/qa-flow/loan-receipt-n3-20261009/`。测试期间冻结源码、测试和任务文档;结果、当前候选及复核交接记录写入本轮回执,不修改正在验证的提交。
- 本轮使用专用的临时浏览器目录和已有制单 Python 依赖环境;完整验证由既有受管入口建立新数据库及隔离网络,使用合成账号/材料。验证结束后只清理本轮拥有的临时资源,不读取真实 OCR 配置、不外发银行文件、不查询生产。
- 当前 developer 的 inline 指令明确禁止派 implement/check 子代理。主会话已完成可执行检查,但独立代码复核仍未完成,已有旧阶段代理报告不能覆盖关联模式和 N1–N2;保持独立复核、真实还款、生产启用的开放状态,不因本地提交或候选门禁通过而勾选整体任务完成。
- 门禁如发现本任务问题,在既有范围内修复并做相关验证,再形成新的本地修复提交与对应回执;保留失败证据,不修改原提交、不忽略失败或缩减正式门禁范围。N4 的生产查询、推送、部署和 N5–N6 的真实业务/付款不在本轮范围。
下方“未提交”等为 2026-10-08 完成时点;本轮候选与验证结论以以上回执为准。
## 2026-10-08 实际材料核对后的后续计划(N1–N2 本地完成,未提交)
用户先要求重新梳理规划,随后批准 N1–N2 本地实施、针对性验证和主会话检查。实施基线为已提交的 `ce11dea9`,其 `verify-candidate` 为 PASS:82 迁移、服务端 4519 通过/1 项既有可选跳过、浏览器 372 通过且无失败/跳过/重试;基线回执见 `artifacts/release-gate/loan-ce11dea9-20261008/`。本轮实现和验证见下方完成回执,旧候选门禁不覆盖本轮差异。没有本轮提交、推送、部署、生产访问或真实业务写入;任务仍为 `in_progress`。下方其他阶段状态保留为历史时点。
### 已完成及无需重复索取
- [x] A/B/C、S1–S8、SR 补证恢复、电脑/手机界面和两人关联模式已本地实现并提交,不再按未开发项目排期。
- [x] 两笔正式借入回单本地核对完成;用户已确认历史未还本金、本年无新增借还、开卡小额往来排除及沿用原个人收款账户。实际值见受控材料,不抄入版本库;真实 OA 台账尚未登记。
- [x] 财务经办、马经理公司代表权及关联身份已确认;技术员工不参与业务审批/复核/见证。关联 Q6 关闭,不再将第三人或查询无结果 PDF 列为普通还款前提。
- [x] 原四份获授权 PDF 已做真实 OCR 实测。S001/S003 字段匹配但为非最终回执;S002 保持需复核、专项适配后置。两份新借入原件为正式回单,不代表未来支出。没有执行真实核销或银行验真。
### 下一阶段顺序与完成条件
| 顺序 | 执行内容 | 完成条件及依赖 | 人工配合 |
|---|---|---|---|
| N1 凭证判断与最小修复 | 已实现正式回单、非最终回执及未知分类;自动核验、人工记账依据、旧证据本地重检、证据重建和最终消费共用有效依据 | 本地完成。非最终和未知不得自动核销;人工不得覆盖已知限制或补造银行成功文字,资金反例与变异通过;无新增迁移 | 现有余额、账户、人员不重问;当前无需新增人工配合 |
| N2 正常路径及材料预验 | 已复用六份材料本地核对,并以一份既有正式支出样本做真实字段的内存人工录入预验;隔离环境完成财务与经理的自动/人工流程、提交记录及拒绝场景 | 本地预验完成;合成借款可实际核销,电脑/手机均实操。历史样本只证明其原交易与格式,未证明真实借款还本及网银提交对应;真实闭环仍待 N6 | 当前不用重新下载材料或制造交易。首笔真实还款时保留本笔提交详情与正式付款回单;新增文件外发 OCR 才需明确新增文件范围 |
| N3 独立代码复核与候选验证 | 固定最终差异及证据,完成独立只读复核和修复后的针对性验证;获准本地提交后对干净新候选运行正式门禁 | 依赖 N1/N2;范围覆盖当前关联模式以及本轮凭证变化。记录复核来源与结论,当前 inline 主会话检查不替代独立复核。源码变化后不能沿用 `ce11dea9` 回执 | 不让公司技术员工做业务复核;独立审查执行条件不足时如实列明。提交另按明确授权办理 |
| N4 发布准备及获准发布 | 准备候选、真实迁移差集核实方案、数据库及附件快照、兼容处置和部署后电脑/手机检查;获准后只读复核生产,再按批准候选推送部署 | 依赖 N3 与正常路径可用;2026-10-07 空存量不是发布前现状,73→82 只是历史推算,实际差集现场核实。保留未验异常边界;产生关联决定后不能直接降级到旧语义代码 | 生产只读查询、推送、部署分别取得明确授权。独立备份切换仍按原范围处理,不能借安装脚本发布整个 main |
| N5 真实台账及授权登记 | 财务按已有原件和用户确认登记两笔历史借入、未还本金、核对截止日、双方账户及会计引用;登记已有公司代表权和覆盖借款,由马经理在 OA 确认 | 依赖已获准可用环境和真实业务录入授权;逐笔核对与现有会计负债记录一致,不重复生成历史现金流或会计凭证,不把 OCR 结果当成余额确认 | 财务实际录入并核对,马经理确认授权范围及相关声明;不重复向用户索取已确认事实,不要求技术员工参与 |
| N6 首笔真实还款及会计交接 | 确认本次金额/分配/日期,财务申请,马经理关联方批准,财务导出、在网银实际提交、留存提交详情与正式付款回单,核验/必要人工确认后核销,交代账留存 | 依赖 N5 及本笔真实付款批准。实际支付仍由有权人员在网银操作;只核销本次确实付款的本金。首笔成功后才能记录真实银行闭环验收;不把软件预验写成真实还款已通过 | 到办理时确认本次还多少及付款安排;不从剩余本金推定全额付款。保留银行指令详情、正式回单和代账交接结果;异常未知不重付 |
N1–N2 已按授权完成本地实施和验证;后续进入 N3 的独立代码复核、本地提交与新候选验证,再按 N4–N6 办理发布和真实业务。复核交接范围已列在本轮完成回执中;当前 inline 主会话不能代替独立复核。提交、发布及真实付款不包含在本轮实施授权里;已明确批准的同范围工作执行时不再逐步询问。
### 验收与取样纪律
- 原件类型、OCR 字段、交易归属、最终核销分别记录。现有实测止于匹配函数,不宣称已复现生产错误核销。正式回单没有字面成功状态的问题须按实际记账证据设计,不能以人工补写状态通过。
- N1 先跑相关回单/OCR/人工重建单测及借款隔离 HTTP/数据库资金反例;涉及页面再跑相应电脑/手机操作。覆盖共享报销路径,重点反例配有效变异。新候选形成后再运行完整正式门禁,本轮定向结果不代替该门禁。
- 真样本不足的异常路径继续标未验,保持银行事实、占用及冻结;不得用异常“人工说没付”绕过。若上线前仍不能验证一条正常最终付款路径,N4 不进入真实启用。
- 不再要求补本年完整银行流水、重新核实已确认借款是否还本、S002 保证金退款材料或重复下载同格式回单。确需补材料时明确具体交易、材料名称、缺失字段、取得方法和用途。
- 仅在现有材料无法回答本次需要时再问银行资料问题;普通 OCR 不以前置咨询银行为条件。新增文件云 OCR 授权、生产业务访问及真实写入与原四份样本授权分开。
### 规划及实施检查
- [x] 已重新核对当前候选回执、四份样本实测、本地新增回单分类及用户确认;没有新增云 OCR 调用或读取生产配置。
- [x] 规划阶段的任务校验、Trellis 治理(含敏感扫描)、流程合同 baseline 和 `git diff --check` 通过;文档注册检查零错误,保留原有“22 个 docs 未登记”的一条汇总告警。该时点仅三份既有任务文档新增内容,历史正文完整保留,尚未运行应用测试;实施后的验证见下方完成回执。
- [x] 用户明确“开始执行,需要我手动操作的及时告诉我”,批准 N1–N2 本地实施与针对性验证。实施期间需要人工配合时说明具体步骤和用途;不重复索取已确认事实或原四份样本授权。
- [x] N1:凭证识别及保存、自动/人工核验、旧记录本地重检、最终消费与页面接续。
- [x] N2:现有材料的受控本地核对、隔离资金与电脑/手机回归、定向变异、主会话检查及真实验收边界记录。无提交、推送、部署或真实数据写入授权。
### N1–N2 本轮完成回执
本轮 31 项改动为 27 个已跟踪文件修改及 4 个新增文件,均未提交。新增受限本地 PDF 凭证解析服务/工作线程、其单测和带真实可提取文字的合成回单工具;服务端新增 `pdfjs-dist` 依赖,继续使用部署及 CI 既有 Node 22。没有新增迁移,隔离数据库仍验证 82 个迁移。
- 正式回单、非最终回执、未知分类随加密核验证据保留。构建核验和最终消费均拒绝非最终、入账方向、已知状态矛盾和缺少依据;失败/终态流程共用的低层字段匹配规则未被付款凭证门禁替换。
- 正式回单没有字面成功状态时,可依据原件记账支出、实际记账日期和原件已核对声明提出人工核验。必须由该批次适用的确认人确认;关联模式仍为财务经办与马经理公司代表确认。保留原始状态为空,不生成虚假的“交易成功”。
- 旧核验缺少凭证性质时,财务在原弹窗显式更新,校验原件摘要/大小及版本后新增核验与审计,不发送云 OCR、不改历史或沿用旧人工批准。重检和最终核销按同一批次锁串行;审计失败整体回滚,已消费证据不可重检。
- 主会话检查补齐历史 OCR 零页结果的详情兼容:零页仍可进入本地重检,负数、超过 20 页或异常大页数拒绝;新增 4 项路由反例。此项仅改善详情入口,不放宽最终资金判断。
- 合成 PDF 票面金额、账户及银行编号与对应的模拟 OCR/人工录入一致。测试沿真实解析、归一化、加密核验、人工重建及核销,仅替换云端识别返回;不是只向匹配函数塞入“成功”结果。
验证证据统一位于 `artifacts/qa-flow/loan-receipt-evidence-20261008/`;各行是不同范围,不累计为独立测试总数:
| 验证 | 结果与准确范围 | 回执 |
|---|---|---|
| 完整借款 HTTP 与数据库 | 116 组 HTTP、9 组数据库约束、82 个迁移通过;含 21 组关联/本轮回单场景、拒绝后本金占用不变、旧自动/人工记录重检和两种确定性交错 | `loan-http-final.log` |
| 关联模式电脑/手机实操 | 各 9 组,共 18 组通过;实际填写记账依据/日期、必须勾选原件核对、公司代表确认、最终核销,非最终回执无手动覆盖或核销动作;本轮运行明确未跑 HTTP | `loan-ui-final.log`;截图索引在该日志 |
| 服务端全量 | 228 文件、4554 项通过,1 项既有可选跳过。随后仅改进合成 PDF 数据一致性和零页详情兼容,对应以下定向/HTTP/浏览器回归;不将新增 4 项虚报为已经重跑的全量数字 | `server-unit-final.log` |
| 最新回单及报销路由定向 | 7 文件、292 项通过,覆盖上述最后改动 | `receipt-targeted-latest.log` |
| 共享回单数据库及真实认证链 | 38 组通过,使用合成账号经真实密码/JWT;审核、读取、重复交易、事务及并发受约束 | `receipt-db.log` |
| 共享报销页面限定重验 | 24 项通过,受管环境 PASS,电脑/手机回单交互及实际报销付款链通过;不是整站正式门禁 | `web-shared-ready.log`、`web-shared-ready/results/` |
| 资金检查变异 | 基线通过,9 个不同守卫全部被具体断言捕获;对最终合成数据又复验同一组 9 个,不累计为 18 个守卫。临时副本测试,当前源码摘要未变、副本已删除 | `mutation-final/mutations.json`;首轮 `mutations.json` 保留 |
| 静态及合同 | Prisma 校验、前端类型检查/构建、错误码合同、UI 规则、敏感扫描、任务和流程/文档检查通过;最终文档检查回执见同目录 `checks-final.json` | 同目录检查日志 |
早期失败证据保留:`server-unit.log` 的 6 项制单测试因未指向现有 Python 依赖环境失败,指定既有环境后全量通过;`web-shared.log` 为缺 WebKit 导致的环境无效,使用本轮专用浏览器后受管重验通过;`loan-full.log` 已通过 HTTP 后在浏览器错误期待“禁用按钮”,产品实际隐藏该动作,改成验证不存在后相关电脑/手机 18 组通过。不得将这些早期日志记作整轮 PASS,也未无原因重跑已通过的无关测试。
### 实样预验、复核交接及待人工事项
- 六份已有材料均本地读取且原件摘要未变:S001/S003 为非最终回执,S002-A 为正式支出回单,S002-B 凭证性质未知,两份借入回单为正式入账回单。S002 仍仅用于格式预验,不作为借款或还本事实,专项 OCR 兼容继续后置。回执 `real-document-check.json`。
- S002-A 按原件实际金额、币种、双方账号、编号及日期,在内存中构造已记账支出的人工核验提案成功,要求后续业务确认,未编造成功状态。没有建立真实 OA 批次、真实批准或核销;未验证其银行提交对应或真实借款还款。原始字段没有写入报告,回执 `local-manual-proof-check.json`。
- 本轮新增云 OCR 调用为 0,未读取 OCR 配置或生产数据、未写真实台账、未付款。原四份样本既有 OCR 授权不扩大到新增借入文件;本地预验无需外发这些文件。
- 主会话按本任务验收检查了全部改动,包括 4 个未跟踪新文件,未发现尚未处理的本轮阻断;当前 inline 模式不能派 implement/check 子代理,**独立代码复核仍未完成**。N3 需同时复核关联模式与本轮差异,重点为原件限制/人工依据、旧证据重建、权限与锁序、共享报销消费者、页面及 9 项变异证据;不能仅检查 `git diff` 而遗漏新增文件。
- 当前无需用户补下载材料、询问银行或要求技术员工参与。获准上线和真实录入时,财务用已有凭据登记历史本金及公司授权,马经理在 OA 确认;首笔真实还款前再明确本次金额/分配,财务实际网银提交,保留该笔提交详情及正式付款回单。到对应步骤再给出操作指引,不从余额推定全额付款。
- 本轮独立代码复核、明确授权的本地提交、新候选正式门禁、获准发布和首笔真实还款闭环均未完成;AC5、AC8、AC27 及整体真实业务验收保持开放。没有推送、部署、远端备份切换、生产查询、真实写入或付款。
## 2026-10-08 关联方模式本地提交与正式验证(已授权)
用户明确答复“是,授权”,同意将本轮 39 项改动作为一个完整的本地提交,并对干净的新候选运行正式验证。提交范围为 33 个修改文件和 6 个新增文件,含一个新增迁移;文件摘要已与上一轮收尾清单核对一致,本次只补授权及验证安排的记录。
- 按中文提交说明引用 `09-17-company-loan-principal-repayment`,保留“真实回单待验、独立代码复核待完成”的限制;不推送、不部署、不查询生产、不配置真实授权或操作真实资金。
- 提交后只运行 `bash scripts/qa/run-release-gate.sh verify-candidate`,在独立的 `artifacts/release-gate/` 目录留存该候选回执。运行期间冻结源码、测试与任务文档,不把旧候选或限定重验结果视为本次正式通过。
- 门禁发现本任务问题时,在已批准范围内修复并做针对性验证,再形成新候选;失败证据保留。每个实际候选和最终结论以 Git 记录及其对应回执为准,不提前记录 PASS。
- 独立代码复核仍受 inline 限制而待完成;正式本地门禁不能替代独立复核、实际回单验收和生产启用审批。整体任务保持 `in_progress`,不归档。
下方“未提交”“待授权”等为相应阶段时点,当前授权与执行顺序以本节为准。
## 2026-10-08 关联方模式收尾接续(用户要求按既定思路规划并实施)
沿已批准的 RP1–RP4 和两人办理规则继续完成本地收尾,不重新实施已通过的流程,也不重新要求确认马经理公司代表权。技术员工不参与业务审批;普通回单直接按获准实际材料验收既有 OCR,无需先问银行。
- [x] 对当前 39 项改动做最终主会话检查,重点核对授权时点、历史经办冲突、材料读取、最终资金消费者及迁移;修复下述文案遗漏,未发现未处理的本轮资金规则阻断。
- [x] 核对既有验证回执和当前差异,补齐可供只读复核的范围及真实材料验收清单;无变化的通过结果直接复用,不把旧候选正式门禁当成关联模式门禁。
- [x] 更新本任务记录并完成任务、治理、文档引用及差异格式检查,形成可审阅的 39 项本地提交范围;本次没有提交、推送、部署或查询生产。
- [ ] 本轮独立代码复核:当前 inline 指令禁止派 implement/check 子代理;已有两份代理报告属于前阶段,不覆盖关联方改动。主会话检查不替代此项。
- [ ] 本地提交及固定候选正式门禁:提交按明确授权执行;门禁使用干净、已提交的新候选,不能通过临时提交或忽略工作区差异绕过。
- [ ] 真实材料验收和发布准备:财务提供既有借入凭据、历史还款及余额核对、双方账户、可授权使用的回单与提交记录;生产查询、真实录入、推送和部署各自按明确授权执行。此前空存量结果不代替发布前查询。
本次不更改业务规则或扩大为 Q6、第三人审批、远端备份切换;待配合事项在本地收尾完成后集中说明。
### 复核交接范围
基线为 `4c37fcee`,本轮待提交范围仍为 33 个修改文件和 6 个新增文件。正式复核须同时检查未跟踪的新文件;仅检查 `git diff` 会漏掉新授权服务、迁移、界面及测试。以下作为只读复核入口,不能把此交接清单视为独立复核通过:
| 检查面 | 入口与必须保持的结果 |
|---|---|
| 授权与历史决定 | `loanApprovalPolicy.js`、新迁移及 Prisma:最新已确认范围不回退、付款/对账分别停用、同一员工多账号仍冲突、历史有效决定可消费、模式不可改 |
| 最终资金动作 | `companyLoanPayments.js`、提交/终态/SR/银行结果服务和人工回单重建:所有入口及最终消费使用相同模式;缺证仍占用、重复交易仍拒绝、关联 Q6 不可用 |
| 页面与读取 | 两个路由、授权/还款/对账组件、付款页、导航及责任人:财务经办、指定公司代表确认,技术员工无审批和材料权限;完整账号及原件仍按用途审计 |
| 数据及并发 | 新迁移不改旧迁移,旧记录独立模式;当前授权、决定人与材料上下文受约束;既有批次→回单→出借人→借款锁序,无逆序 |
| 验证及文案 | 关联 HTTP/电脑手机 fixture、单测、错误码合同:包括完整闭环、资金拒绝后的本金占用不变和授权停用两种顺序;公共借款错误提示不能把关联确认说成独立复核 |
本次主会话发现并修正 5 条公共借款错误提示:银行结果、补证需确认/已失效、回单归属、提交清单。只改提示及对应的前后端合同,未改资金判断;独立模式专用的无复核人提示和 Q6 双人要求保留。
本次增量验证证据位于 `artifacts/qa-flow/loan-related-closeout-20261008/`:错误码合同零发现;已有错误提示及业务错误测试 2 文件、908/908 通过;前端类型检查和构建通过;UI 规则 161 文件零发现;改动的服务端常量语法检查通过。未为文字修改重跑数据库、HTTP、浏览器或资金变异,也未重跑服务端全量。前阶段完整借款专项仍为 82 迁移、HTTP 109、浏览器 33、数据库约束 9 组通过;有效变异分三轮 8+3+2 全部捕获。最后一轮变异回执中的 5 个资金/权限关键文件摘要与当前文件一致;此比较只覆盖所列文件,不作为整仓或发布证明。主会话检查、独立复核、正式门禁及真实验收仍分别记录。
本次 task validate、Trellis 治理(含敏感扫描)、流程合同 baseline 和 `git diff --check` 通过。文档注册校验零错误,保留原有“22 个 docs 未登记”的一条汇总告警;不扩展清理范围。inline 缺失的 implement/check manifests 按现有规则跳过。
### 财务配合与真实材料验收
| 顺序 | 需要的既有材料 | 核对结果 |
|---|---|---|
| 1 本金 | 原借入凭据、协议或确认资料、系统外已还依据、代账核对结果及截止日期 | 按原借款逐笔确定未还本金;资料未核实不能申请,OA 无记录不能推定银行未付款 |
| 2 身份与范围 | 公司主体、财务和马经理真实员工关联、已确认的公司代表权说明、所覆盖借款、双方银行账户 | 在获准业务录入时登记范围并由马经理确认;不新增第三人审批,不在聊天或测试报告抄录完整账号 |
| 3 回单 | 获准用于验收的既有银行回单原件,以及有对应关系的银行提交记录 | 在受控环境按实际 OCR→归一化→匹配处理,逐项核对金额、币种、账户、状态、流水号及时间;不能仅看 OCR 返回成功 |
| 4 歧义及异常 | 现有同金额候选的归属依据;已有失败/处理中材料及相应指令终态材料(如有) | 按实际文件记录支持与不支持的字段及编号对应;材料不足保持待对账。缺少异常样本就保留该项真实验收未完成,不制造付款取样 |
原件只在获准的受控位置处理;验收记录只保留样本代号、字段是否可读、匹配或拒绝结论及脱敏证据引用。普通 OCR 验收不以询问银行或取得“查询无结果”PDF为前提;公司现有人员安排下,关联 Q6 继续关闭。
### 候选与发布接续
1. 本地问题修复及针对性验证完成后,固定只读复核范围;独立复核未完成时明确保留该项。拟提交内容为完整的关联模式及验证、任务记录,提交说明保留“未部署、真实回单待验、独立代码复核状态”。提交只在获得明确授权后进行。
2. 对获准提交后的干净候选运行 `bash scripts/qa/run-release-gate.sh verify-candidate`,另存候选回执;运行期间不修改源码、测试或任务文档,不并发重建前端。此命令只验证,不使用会进入生产链的 `all` 或 `ci-release`。
3. 发布前获准重新只读核实生产借款、在途/终态批次及迁移差集;本地为 82 个迁移,若生产仍保持此前的 73 个,预计差集为 9 个,但不得把这个推算填作实际 `EXPECTED_PENDING_MIGRATIONS`。准备覆盖数据库和附件的部署前手动快照,以及生成关联决定后禁止直接降级的兼容处置方案。
4. 推送、部署和真实授权/借款录入/付款各自按明确授权执行;部署后核对版本、实际迁移、电脑手机入口和权限,再办理真实已批准的还款。备份切换仍只按原独立范围安装指定脚本,不能借此发布整个应用。
## 2026-10-08 关联方还款本地实施完成(未提交;独立代码复核及真实材料待验)
用户在规划完成后明确“开始实施”,授权按 RP1–RP4 自主完成本地实施及验证。本轮按财务经办、马经理代表公司确认的已定分工实施;技术员工不参与财务审批、复核或见证。当前 `inline` 由主会话直接实施与检查,未派 implement/check 代理;以前代理的复核不覆盖本轮差异。没有提交、推送、部署、查询生产、配置真实授权或操作真实资金。
- [x] RP1:新增一个增量迁移 `20261009010000_loan_related_approval`(本地共 82 个迁移),新增授权、覆盖借款和生命周期事件,冻结还款模式与范围,补齐逐次决定上下文及数据库约束。历史记录默认独立模式,不补造授权;未改旧迁移。
- [x] RP2:贯通付款批准/退回、导出、清单、成功/失败归属、人工回单决定及冷重建、严格失败、终态与最终取消、SR、晚到成功、误报及追回。只豁免指定确认人的收款人关联,全部历史经办冲突保留;关联 Q6 在发起、决定和最终释放处拒绝。
- [x] RP3:现有电脑/手机页面接入授权范围和公司代表确认,按服务端能力区分动作;经理只读授权范围内的材料,查看原件与完整账号需用途及审计。两个独立登录实际操作完整正常及异常流程,技术员工无新增候选、待办或材料权限。
- [x] RP4 可执行部分:定向 DB/HTTP/浏览器、确定性交错、资金守卫变异、受影响共用路径、主会话只读检查及既有规约维护完成。任务与流程收尾校验另见本节末。
- [ ] 本轮独立代码复核、获准真实材料验收及固定提交候选的正式发布门禁;不以本地测试或旧候选回执勾选 AC27/整体借款验收。
### 关键行为与收口修正
- 授权分为新付款与历史对账两方面。使用最新已确认版本,缩小范围或停用后不回退旧版本;旧版本不能再登记停用事件。新申请/批准/导出检查当前付款授权,新对账决定及最终释放检查当前对账授权;已生效审批及银行事实在证据有效时按历史上下文消费,不因事后停用或确认人离职丢失效力。
- 公司代表可以退回付款申请,必须写理由;决定不可改,不能再批准或导出,退回本身不释放占用。财务安全取消后新建更正申请,详情、台账、责任人及提醒均标为退回。
- 同一员工兼任角色或使用多账号仍不能自审;经办冲突收集包含作废、撤回及被取代材料。数据库同时校验决定的实际确认人与上下文相符、目标及授权范围一致,禁止把关联决定写进旧独立记录。
- 核销、人工证据重建、银行事实补记及恢复释放均重验历史决定,而非只信任 `approved`。篡改原付款或人工决定上下文的隔离反例会被拒,本金和占用不变。
- 手机实测发现退回菜单被底部导航遮挡,已改为向上展开并保留可点击高度。完整浏览器回归后仅另改一处账号查看弹窗文案,将借款的“报销单”改成“还款单”;该文字修正后受管构建/类型检查、UI 规则及差旅冻结保护再次通过。
锁序保持:既有批次 → 回单交易/附件 → 出借人及人员资格 → 排序借款;创建锁出借人 → 借款,仅新建批次。授权生命周期只锁出借人,不等待既有批次。授权停用分别与批准、导出、事实确认和最终释放做两种先后顺序,共 8 个确定性交错;材料及候选变化继续沿原门禁。串行化只覆盖动作当时已知事实,之后的新银行事实仍走晚到结果对账。
### 本地验证与证据
主要记录在 `artifacts/qa-flow/loan-related-20261008/`,均为合成资料与本轮拥有的隔离环境。
| 范围 | 实际结果与边界 |
|---|---|
| 完整借款专项 | `loan-full-first.log`:82 迁移、HTTP 109 组、浏览器 33 组、数据库约束 9 组全部通过,清理通过。HTTP 包含原独立模式 95 组及关联 14 组;浏览器包含原 19 组及关联电脑/手机各 7 组。OCR 只替换云端返回,识别、归一化、匹配、人工重建及最终消费走真实实现 |
| 关联正常及异常 | 范围登记/确认、原件读取、批准与退回、导出/OCR核销、人工核对、归属变化重提、逐指令终态、SR及释放、占用冲突、部分/整笔超额、部分/全额追回、误报、Q6拒绝及技术员工拒绝访问通过;审核或资金写入异常的事务回滚也有反例 |
| 服务端 | `server-full.log`:227 文件、4519 项通过,1 项原有跳过。此后补旧授权停用检查与数据库决定人核对,最后的 `targeted-final.log` 5 文件 77/77 通过,最新数据库/HTTP验证包含于上述完整专项;没有把较早全量回执说成最后小改后再次全跑 |
| 受影响共用界面 | `loan-related-shared-20261008` 的受管首轮为 35 通过、1 失败:报销付款、付款权限和导航通过;误选了覆盖合同已标 `frozen` 的历史 `travel-payment-flow.spec.ts`,员工入口按现行规则返回 403。未改差旅代码或权限,改按合同入口 `travel-freeze-protection.spec.ts` 在 `loan-related-shared-freeze-20261008` 重验 2/2 通过。保留首轮失败,不称首轮全通过;两轮源码/仓库完整性和自有环境清理通过,均不具有正式发布资格 |
| 静态与编译 | Prisma validate、前端类型检查/构建通过;最新 UI 规则扫描 161 文件零发现,错误码合同、敏感扫描及 21 个改动 JS/CJS 的语法检查通过。文字修正后的类型检查/构建日志在 `shared-freeze-retained.log` |
| 守卫变异 | `mutations.json` 8/8、`mutations-extra.json` 3/3、`mutations-final.json` 2/2,共 13 个有效变异全部捕获;均在临时源码副本测试,工作区被测源码摘要未变,副本已清理 |
变异覆盖当前付款授权、范围、指定身份、历史经办冲突、最终原批准消费、人工回单重建、Q6、退回决定、冻结付款上下文、最终释放当前资格、范围读取、旧授权停用和数据库首个决定的实际确认人。移除原批准/人工证据最终检查会造成错误核销,测试明确捕获;移除旧授权停用的服务检查时,数据库仍拒绝,测试捕获的是 `500` 取代约定 `409`,不是错误停用或错误资金动作。最初变异运行器用错 Vitest 配置扩展名的启动失败不计入 13 个有效结果。
中间浏览器失败记录保留于 `related-browser-*.log`、`related-browser-ui-*.log`:先修正隔离 origin 的端口、两个视口重复按钮定位、提交响应与页面刷新的等待、证据选择与查询刷新的等待,再修复实际手机菜单遮挡。最后完整专项通过;不将先前局部桌面通过描述为电脑/手机全过。相关截图位于完整专项回执列出的 `artifacts/qa-layout/` 子目录。
复现入口:
- 完整专项:`RUN_ISOLATED_LOAN_DB_TEST=1 RUN_ISOLATED_LOAN_BROWSER=1 node scripts/qa/test-company-loan-db.cjs`;需沿已验证的 BIFF8 Python 环境和 Playwright 浏览器缓存配置。
- 关联定向:增加 `RUN_ISOLATED_LOAN_RELATED_ONLY=1`;若另加 `RUN_ISOLATED_LOAN_RELATED_UI_ONLY=1`,只做浏览器准备,关联 HTTP 明确为 `NOT_RUN`,不得计通过。
- 共用界面:受管 `bash scripts/qa/run-web-gates.sh retained-local`,通过 `QA_RETAINED_SPECS` 选择报销付款、付款权限、导航及现行差旅冻结保护合同。不能用已封存的差旅整链恢复被冻结权限,也不把 retained-local 当作 `verify-candidate`。
### 主会话检查及后续边界
主会话只读检查覆盖所有授权生命周期、决定入口与最终消费者、共享人工回单重建、范围读取/审计、不可变迁移、Q6及锁序,未发现未处理的本轮阻断项。对比原迁移确认两个被替换的历史触发器仅适配新增决定字段,旧状态转换保护保留。按 `trellis-update-spec` 更新既有后端规约,写入模式/权限时点、经办冲突、历史消费、读取与回退合同,并替换过时的“S8恢复界面未做”测试说明;运行次数保留在本任务。
- 任务仍为 `in_progress`。AC20–AC26 仅勾选本地合成验收;AC5、AC8、AC27及既有整体业务验收保持开放。仓库 `.trellis/config.yaml` 的 `dispatch_mode: inline` 和 workflow 禁止派 implement/check 代理,本轮没有独立代码复核结论;不需要技术员工承担财务复核。
- 新模式真实启用前仍需财务核实借款余额与账户、登记已获确认的公司授权范围,再使用获准实际回单和提交记录验收现有 OCR 及编号对应。无需事先向银行咨询普通 OCR;证据无法对应时保持待对账。Q6 在关联模式下不可用,不能以两人声明代替银行终态证据。
- 当前 HEAD 仍为 `4c37fcee`,本地 main 比本地 origin/main 多 12 个已存在提交,本轮差异未提交。旧候选正式门禁不证明本轮差异;后续固定提交候选再做正式门禁,推送、部署、真实授权/付款及发布前生产核实分别按授权执行。
- 新增迁移须纳入将来部署的实际迁移差集。2026-10-07 的 OA 空存量与 73 个已应用迁移只是当时时点,不能代替发布前再核实;已有银行事实后不得降回不能解释关联模式的旧代码。
- 收尾 task validate、Trellis 治理(含敏感扫描)、流程合同 baseline 及 `git diff --check` 通过;inline 下不存在的 implement/check manifests 按规则跳过。文档注册检查零错误,保留原有一条“22 个 docs 未登记”的汇总告警,本轮未扩大清理范围。AC1–AC27 连续、原 AC1–AC19 勾选状态保留、历史正文未删;较早门禁标题仅补充“历史计划”标记。
## 2026-10-08 关联方还款实施规划(历史规划回执,已获本地实施授权)
用户已确认马经理有权代表公司批准,要求按财务与马经理两人办理的方向规划;技术员工不参与复核、审批、见证或财务授权。本轮完成既有PRD/design/implement收敛,不把“规划”扩为代码或真实业务操作授权。下面较早的阶段记录保留各自时点,当前实现状态与后续工作以本节为准。
### 当前基础与本轮产物
- 既有A/B/C、S1–S8、SR补证恢复、电脑/手机界面均已在本地实现。当前HEAD为 `4c37fcee`,本地main比本地origin/main多12个提交,未推送、未部署。本次待做的是关联方模式,不再把S4–S8或SR列为未实现。
- 该干净候选的正式 `verify-candidate` 回执为PASS:浏览器372/372、无失败/跳过/重试;服务端4480通过、1项原有跳过;7个默认关闭的可选专项未执行。源码/仓库完整性及自有环境清理通过,专用浏览器目录已清理。
- 证据为 `artifacts/release-gate/loan-4c37fcee-20261008/release-result.json` 与同目录 `local-followup.json`;保留此前失败回执,不以新回执覆盖历史。更早的借款专项为81迁移、HTTP95、浏览器19、数据库约束9组通过。以上只证明旧独立模式及各自候选,不能证明新模式或真实还款已验收。
- S0人员事实已明确:财务一人、收款经理一人,技术员工不参与,独立模式无人可办理该笔还款。马经理公司代表权已确认,不再提问;关联模式关闭Q6,不再把额外两名独立复核人或无结果PDF作为普通还款启用条件。
- 普通回单沿已有OCR按实际文件处理,无需先问银行;真实样本尚未验收,不补造字段或编号关系。2026-10-07生产只读汇总为空只是当时时点,本轮不重查。
本轮文档清单:
- [x] 记录已确认的公司授权、两人分工、技术员工排除和OCR验收纠正;删除未定方向的表述,保留被否定方案的历史说明。
- [x] 收敛PRD的R3/R4/R6、原AC3独立基线及AC9–AC19的模式语义,新增未勾选的AC20–AC27;已付、异常与Q6边界一致。
- [x] 在design给出范围/授权、权限时点、全流程分工、数据与消费者、并发、界面及启用/回退方案;覆盖人工回单重建与最终消费,不能只改审批入口。
- [x] 拆分以下RP1–RP4及定向验收;本轮无应用实现、迁移或业务配置。
- [x] 任务校验、Trellis治理(含敏感扫描)、流程合同baseline及git diff --check通过。主会话另核对AC1–AC27连续且既有勾选状态保留、新AC未提前验收、design/implement历史正文保留、差异仅三份规划文档;未运行应用测试或正式门禁,未进行独立代理复核。
### 原实施拆分(历史规划时点;当前结果见顶部)
| 切片 | 内容与主要范围 | 验收和完成条件 |
|---|---|---|
| RP1 授权、模式与数据约束 | 一个新增型迁移;借款范围授权及生命周期事件,真实身份关联,付款/对账授权区分,冻结还款模式,逐次决定上下文。沿用现有角色而不授予全局新权 | AC20/21/22/25/27;历史独立回填、关联字段/外键/不可变约束、范围和状态验证;不会单独使付款入口放行 |
| RP2 后端全链路 | 候选/创建/批准/导出;清单、两种归属、人工回单含重建、严格失败、终态、取消、SR、晚到/误报/追回;所有最终消费者、范围读取及授权接口;关联Q6三处拒绝 | AC21–AC25;每个消费者两人正例与经办冲突反例;拒绝后本金/占用/冻结正确;原独立、报销和差旅守卫不变 |
| RP3 现有页面接入 | 在借款内登记/确认范围,现有还款及对账页面显示模式、公司代表身份、材料/理由、分工按钮及不可用原因;待办、通知和审计文案一致 | AC22/26;电脑和手机实际走两人正常及异常流程,技术员工无候选/任务/材料,前后端能力一致 |
| RP4 验证、只读复核与收口 | 定向DB/HTTP/浏览器、资金守卫变异及确定性交错;针对真实OCR处理链的合成输入;补齐任务证据及复核发现,按最终变更范围跑必需检查 | AC20–AC27及受影响旧AC;只读review不改代码,inline无法派审时明确待独立复核;固定最终已提交候选后按已获授权运行正式门禁 |
- [ ] RP1完成。
- [ ] RP2完成。
- [ ] RP3完成。
- [ ] RP4完成;记录运行时验证、静态复核、真实业务验收各自结论,不合并写成“全部验收”。
所有切片作为完整可办理、可对账的模式一起启用;即使某部分能独立验证或提交,也不能部署只放开收款人审批的中间状态。公司授权登记只反映已确认的代表权,不再增加第三人批准层。新授权版本、付款批准和银行事实决定分开留痕,模式不通过前端开关或通用admin权限绕过。
### 针对性验收矩阵
| 主题 | 必须证明的行为 |
|---|---|
| 实际两人正例 | 仅财务、收款经理两名合成办理人,从范围登记/确认、建单、经理关联方确认、财务导出、OCR成功到核销;技术员工只作为拒绝访问的合成反例 |
| 只豁免收款人关联 | 经理仅作为收款人可以确认;分别加入制单、提交、导出、清单登记、各原件上传、人工录入或提案参与后全部拒绝。覆盖多角色及同一员工多账号,移除一条检查不能由删除收款人标识一并放行 |
| 授权和历史 | 未生效、超公司/出借人/借款范围、身份变更、客户端伪造模式、旧独立单转模式均拒绝;新版本不能改写旧付款授权。付款权限停止不破坏已付核销,新的对账决定及最终释放检查当前对账授权 |
| 正常与异常闭环 | 自动回单成功;人工录入→关联确认→证据重建→核销;同额成功/失败归属;清单及逐提交终态;严格失败与最终取消;补证重提;晚到成功→占用冲突/超额→部分/全额追回;误报关闭与多原因冻结 |
| 证据持续有效 | 缺字段、状态矛盾、同金额无归属、指令不符、缺任次提交终态、等待期未满、材料作废/替换/候选变化均不因关联模式放行;只登记事实不直接减少本金或释放占用 |
| Q6及其他业务 | 关联模式发起、复核、伪造双审后的取消均拒绝;旧独立Q6仍要求两名独立人及全证据;独立借款、报销/差旅及跨业务交易唯一性回归 |
| 决定与资金并发 | 授权停止分别与批准、导出、事实确认及释放测试两种顺序;沿现有出借人锁与人员资格锁,不新增逆序。材料/候选变化与最终资金动作仍做确定性交错;结果只保证当时已知集合,晚到证据进入对账 |
| 不可变与回滚 | 模式/授权引用不能换写,批准人与提案人不得同人,旧事实不可删;审计或资金更新失败全回滚;重复请求不重复核销/释放/追回;相关限制在服务和数据库分别验证 |
| 界面和隐私 | 两个独立登录在电脑、手机走实际弹窗;关联文案覆盖详情/待办/历史/通知,角色能力从服务端来;完整材料仍按用途审计,越范围及技术员工直接访问拒绝 |
测试沿项目已有隔离数据库、真实Fastify、Vitest及浏览器入口,不新造一套业务认证替身;OCR仅替换云端返回。每个关键资金/权限守卫做有区分度的反例及定向变异,若下游保护仍阻断则如实记录,不谎称该变异已造成错误资金动作。按切片做针对性回归,完整候选形成后再做受影响范围的完整验证,避免纯文档阶段重复全量门禁。
### 真实启用前的事项
1. 完成上述代码、页面、迁移及验证;独立只读review按项目规则执行,受inline限制时保留待办而不虚报通过。
2. 经正式业务录入核实公司、借款、未还本金、双方账户及马经理员工关联,在系统里登记此次已经确认的公司授权与范围。无需聊天提供完整账号,也不安排技术员工审批。
3. 使用获准的实际回单及提交记录验收现有OCR和编号关系;正常识别不以事先银行咨询为前提。异常无终态证据继续占用,Q6保持不可用,不因样本不足降低证据标准。
4. 提交、推送、部署与生产录入/付款分别按授权执行;发布前重新获准核实存量、迁移差集及手动快照。备份脚本的单独远端切换不在此范围,不能借此发布当前main。
## 2026-10-08 测试稳定性集中检查与新候选门禁(历史计划,最终回执见上)
用户已批准集中检查、必要测试修正、本地提交及对新干净候选运行正式门禁。本轮不推送、不部署、不查询生产、不执行远端备份操作;任务仍为进行中。
- [x] 检查两份失败测试、此前修正的审批测试,以及邻近布局用例:严格同排对齐修正为同一次浏览器执行取值;其余宽高/横向比较、带足够间隔的上下顺序及非同类动画场景不机械改写。检查详情标题与加载提示,当前需修正的仍为下方已验证的两处。
- [x] 保留两份测试全部原有断言和运行配置;没有新增用例、修改业务实现、增加容差、超时或重试。被测输入未变,复用下方受管定向 61/61 通过结果,不为本次文档更新重复运行。
- [x] 将同次几何取值、精确标题定位两条已验证的规则补入既有前端规约;按任务、治理、流程合同、文档注册及 diff 检查后,本地提交两份测试、规约和本记录。
- [ ] 对新提交执行 `bash scripts/qa/run-release-gate.sh verify-candidate`,保留两次失败回执,新结果写入独立的 `artifacts/release-gate/` 目录。此处为提交前执行计划,不提前宣称通过;候选冻结后不再修改受版本控制的记录,最终状态以该候选的正式回执为准。
- 真实建行样本、官方查询材料和编号对应关系、合格复核人员及独立业务验收继续待外部核实;正式本地门禁不替代这些条件。
## 2026-10-08 第二轮正式门禁及新增测试稳定性修正
用户确认后,仅将此前的审批按钮测量修正和任务记录本地提交为 `1dd84065`,工作区干净;对该固定候选执行 `bash scripts/qa/run-release-gate.sh verify-candidate`。未推送、部署、查询生产或执行远端备份操作。
- 正式回执 `artifacts/release-gate/loan-1dd84065-20261008/release-result.json` 为 **FAIL,不具备发布资格**。static 和 full-local 的前 11 个阶段通过,服务端单测 4480 通过、1 项原有跳过;网页 370/372 通过、2 失败、0 跳过、0 重试。默认关闭的 7 个可选服务端专项不计通过。上一轮失败的审批按钮用例已在本轮完整回归中通过。
- 两个新增失败来自既有测试:`r92-mobile-invoice-usability.spec.ts:335` 的宽泛文字定位同时命中标题与“加载票据详情…”提示,上传步骤尚未执行;`system-action-confirmation.spec.ts:835` 顺序读取动画中两个按钮的位置,中心差约 3.69px,超过原有 2px 上限。此次候选仅改动另一份审批测试及记录,没有直接修改这两个用例或业务页面。
- 本轮仅局部修正两份测试:票据标题改用精确的 heading 定位;两个布局坐标改为同一次浏览器执行读取。保留中心差小于 2px、按钮顺序、侧栏宽度和批量上传计数等原有断言,不修改业务代码、不增大容差或跳过用例。
- [x] 官方受管 `retained-local` 验证这两个完整文件:61/61 通过、0 跳过、0 重试,包含原失败用例、批量上传计数及 1280/1440/1920 布局断言;运行中源码/仓库未变,环境和自有容器/运行目录清理通过。结果位于 `artifacts/qa-flow/loan-gate-followup-1dd84065-20261008/`,不替代两轮正式失败回执。
- 定向入口:`QA_FULL_REPORT_DIR=artifacts/qa-flow/loan-gate-followup-1dd84065-20261008 QA_RETAINED_SPECS='r92-mobile-invoice-usability.spec.ts system-action-confirmation.spec.ts' bash scripts/qa/run-web-gates.sh retained-local`;另显式指定本轮专用浏览器副本和受控 BIFF8 Python。任务校验、治理、流程合同及 `git diff --check` 通过。
- 正式运行全程源码/仓库未变,隔离容器及运行目录清理通过。新修正与本记录尚未提交,后续仍需固定新的已提交候选重跑正式门禁;真实建行材料、人员核实和独立业务验收继续待完成。
## 2026-10-08 正式本地发布门禁及测量时序修正
用户同意对固定干净候选 `7a48a1e7` 运行正式本地门禁;执行 `bash scripts/qa/run-release-gate.sh verify-candidate`,未推送、部署、查询生产或执行远端备份切换。专用浏览器经官方安装及受控复制,Chromium/WebKit 原生隔离检查通过。原始回执保留在 `artifacts/release-gate/loan-7a48a1e7-20261008/release-result.json`,结论 **FAIL,不具备发布资格**,不以针对性重验覆盖它。
- static 通过;完整服务端单测 4480 通过、1 项原有跳过,前端类型/构建、审批操作及门禁默认配置的服务端流程通过。`regression-all.sh` 默认关闭的 7 个可选专项没有执行,不计通过。
- 网页完整发现 59 个本地 spec、372 个用例,执行 371 通过、1 失败、0 跳过、0 重试。唯一失败是既有报销审批用例 `workflow-action-confirm-ui.spec.ts:530`:两个同排按钮先后读取纵坐标,相差约 1.16px,严格相等断言失败。原用例及报销页面均不在本轮借款业务改动中。
- 回执确认候选源码/仓库全程未变,隔离数据库容器及运行目录清理通过。仍不替代真实建行材料、人员可用性与外部业务验收。
- 本轮仅修正该用例的测量时序:在同一次浏览器执行中读取两个按钮的位置,保留原有纵坐标严格相等及高度差上限断言;页面仍保留 320ms 入场动画。不修改业务实现、不增加像素容差、不跳过用例。
- [x] 用官方受管 `retained-local` 对整个 `workflow-action-confirm-ui.spec.ts` 定向验证:21/21 通过,0 跳过、0 重试,原报销证据/退回意见断言以及电脑/手机审批场景均执行,环境和自有容器/运行目录清理通过。结果保留在 `artifacts/qa-flow/loan-gate-layout-20261008/`,不作为正式发布回执。
- 定向入口:`QA_FULL_REPORT_DIR=artifacts/qa-flow/loan-gate-layout-20261008 QA_RETAINED_SPECS=workflow-action-confirm-ui.spec.ts bash scripts/qa/run-web-gates.sh retained-local`;执行时另显式指定本次经校验复制的专用浏览器目录和受控 BIFF8 Python,不使用共享历史浏览器缓存。任务校验、治理、流程合同及 `git diff --check` 通过。
- 用户已确认将本次测试修正及任务记录这两个文件本地提交,不推送、不部署。提交后对新的固定干净候选重跑正式完整门禁,结果写入新的本地回执,保留上次失败记录;本记录提交时尚不宣称正式门禁通过。
## 2026-10-07 后续收口执行(用户同意执行)
按后续工作清单,先将已验证的 S4–S8 共 32 项改动本地提交,提交保留“真实回单待验、整体业务验收未通过”。随后补齐提交登记、清单复核、失败归属、晚到补记和追回的浏览器闭环,并准备发布前存量/迁移/回退检查材料。当前 inline 主会话直接实现和检查,不另派代理;此前两名代理的复核仅覆盖其当时差异。用户本轮已明确授权生产借款存量的只读汇总查询;人员与银行材料答复“不清楚”,保持待核实;推送、部署和远端备份切换不在本次默认执行内。以下“32 项未提交”属于提交前验证时点。
- [x] 本地提交已验证 S4–S8:`431c36ea`,32 项,未推送。
- [x] 补齐其余银行对账表单的电脑/手机闭环;最终固定副本通过,在本次本地提交授权内将新增测试及 S0/发布准备记录单独提交。
- [x] 在本任务记录具体迁移差集、发布顺序、回退限制和未满足条件。
- [x] S0 生产存量只读核实完成;人员与银行材料仍待外部核实。
### 剩余界面验收补测
新增 `company-loan-reconciliation-browser.cjs`,由既有隔离浏览器入口调用。合成种子通过正式接口准备,实际待验动作由页面完成:电脑/手机各走提交登记→清单确认/独立复核→失败归属/独立复核→失败回单终态→取消;以及晚到成功原件上传/登记→用途审计查看输入→独立复核→补记→部分与全额追回→凭更正材料独立关闭重复误报。断言经办人无自审按钮、原占用释放、待追回变化、部分追回仍冻结、全部追回后关闭对应冻结、不创建新付款批次及手机无横向溢出。
未修改应用业务代码或新增资金规则。首轮用例把归一化后的大写指令号与小写测试预期比较而失败,已修正测试预期;后一轮通过。最新副本补明确选择新上传的更正证据,再验证最终用例。首轮失败不计通过;不新增变异测试或重复整套服务端单测,因为本轮仅补浏览器覆盖与文档。
复现:在隔离源码/构建副本内执行 `RUN_ISOLATED_LOAN_DB_TEST=1 RUN_ISOLATED_LOAN_BROWSER=1 node scripts/qa/test-company-loan-db.cjs`,BIFF8 使用已准备的受控 Python 环境。最终固定副本通过 81 迁移、HTTP 95、浏览器 19、数据库约束 9 组,自有副本/容器清理 PASS。脚本语法、任务、治理、流程合同、敏感扫描与 git diff --check 通过。应用代码与依赖未变,复用先前通过的构建、类型及单元测试证据。主会话遵循 inline 直接检查,没有新增代理复核,也不替代财务/银行事实验收。
### S0 只读核实及发布准备(2026-10-07)
用户明确授权本轮生产借款存量只读汇总;通过既有生产连接,在 `REPEATABLE READ READ ONLY` 事务中查询并 `ROLLBACK`,设置查询/锁等待超时,未输出账户、原件或业务正文,未运行部署/迁移。核实时点 2026-10-07 22:08–22:09(北京时间)。
- OA 中出借人、借款、还款批次、占用分配和借款回单均为 0;已确认失败未取消也是 0。当前没有系统内借款存量需要回填;这不证明银行或线下没有付款。发布前必须再次核对,不能把本次空库结论永久复用。
- 已应用迁移 73 个,未完成迁移 0;与本地同名迁移的 SHA-256 全部一致,没有生产多出的迁移。本地 81 个,差集为以下 8 个(不是仅本轮新增的 3 个):
1. `20261006010000_loan_receipt_attribution`
2. `20261007010000_loan_bank_submissions`
3. `20261007020000_loan_failure_attribution`
4. `20261008010000_loan_bank_terminal_facts`
5. `20261008020000_loan_release_recoveries`
6. `20261008030000_loan_not_submitted`
7. `20261008040000_loan_freeze_reasons`
8. `20261008050000_loan_bank_result_events`
- 人员、官方无结果 PDF、回单与指令编号关系:用户答复“不清楚”,均保留待核实;Q6 不能宣称具备实际使用条件。脱敏只读结果保存在本轮 S0 本地证据目录的 summary.json。
发布准备顺序(本轮只准备,不执行发布):
1. 完成剩余浏览器闭环及业务/真实样本验收,固定最终已提交候选;不得把本轮合成回归当作正式 release-gate 回执。
2. 对固定干净候选运行 `bash scripts/qa/run-release-gate.sh verify-candidate`,绑定当次回执;当前仍有待验证/未提交的补测,不提前运行大范围门禁或写“可部署”。不能用 `all`/`ci-release` 代替本地验证,因为它们会进入生产发布链。
3. 经单独批准后做发布前只读核实,将实际差集作为 `EXPECTED_PENDING_MIGRATIONS`。若生产出现新增借款/批次、迁移差异或未完成项,重新评估,不自动套用本次 8 项或空存量结论。
4. 按既定部署前手动快照方案确认快照完成与恢复证据。备份脚本切换属于另一项远端授权,仅安装指定 refresh 脚本及执行既定停用顺序,不借此部署应用。
5. 推送、部署各自批准后才执行迁移/应用发布;部署后核对应用版本、81 项预期迁移、readiness、权限和借款只读页面。真实借款录入/付款仍需业务明确批准,不能制造付款验收。
6. 回退保留新增表和历史事实,不删迁移或重置数据库。一旦生成补记/追回等新事实,旧代码未计算新台账,不能直接降级;停止新付款并按获批兼容修复或恢复方案处理。确认此前没有新资金事实,也仍需具体回退审批,不能默认恢复覆盖期间其他业务。
## 2026-10-07 后续执行接续(用户要求已确定工作直接执行)
沿既有设计与 S4–S8 清单推进本地实施、针对性验证与主会话检查,不再逐阶段等待通知。先 S4,再按依赖推进 S5、S6、S7、S8;提交、推送、生产操作仍遵守单独授权。SR-A/B 已本地提交 `2e00d30f`。前阶段 inline 下未派独立代理;本轮工具已可用,按 AGENTS 对资金流程的要求另派两名只读代理检查资金与界面,修复后静态复核通过(同模型,非业务独立验收)。
- [x] S4 本地实施与合成验证:Q6 三类证据独立分类、全量材料快照、两名独立复核、人工终态及最终取消重验;覆盖混合导出(已提交部分沿 S3,未提交部分逐份举证)。
- [x] S5–S8 本地实施、针对性回归及只读静态复核;整体业务验收仍受 S0 和真实样本限制。
- S4 技术边界:人工声明覆盖未关联提交的导出,不可覆盖任何已登记(含撤回)的提交;查询及对账单覆盖首次导出至登记日(公司时区),所有导出人的文件去向说明齐全。快照变更后重新登记、重新双审,原终态不改。附件分类不允许事后互换,不进入回单 OCR;真实材料及人员可用性仍待 S0。
### 本轮阶段结果(本地验证通过,尚未提交)
- S4:新增 `loan_not_submitted_proposals/reviews`、三类固定证据分类、完整空清单复核、双人决定、人工终态、材料变更取代及最终取消重验。增量迁移 `20261008030000_loan_not_submitted`。
- S5:新增逐原因冻结、付款前统一门禁;事实登记不冻结,没有通用管理员解冻接口。迁移 `20261008040000_loan_freeze_reasons`。
- S6/S7:新增银行事实、跨核销空间交易认领、逐借款补记、实际追回;本金容量同时包含补记结清。迁移 `20261008050000_loan_bank_result_events`。当前原件人工录入/独立核对,不声称 OCR 或银行真实性自动验证。待审的同一交易可用新证据取代,先产生新冻结再关闭旧冻结;已复核银行事实的原件不得作废,物理文件损坏仍拒绝入账。
- S8:详情页接入提交、清单、终态、失败归属、Q6、SR 恢复、晚到补记/追回;查询完整人工输入和原件要求用途与审计,电脑/手机完成 Q6、SR 恢复及多回单终态的完整弹窗流程;其他新增表单以 HTTP 与类型检查覆盖。沿用既有视觉组件。
- 有效变异共 13/13 被测试捕获(6 个首轮、2 个金额边界、2 个最终入账守卫、3 个复核修复守卫)。包括三证类别、物理摘要、快照、冻结、交易身份、部分追回、占用冲突、超额拆分、最终候选、冻结转移、更正依据和旧取消旁路。部分变异仍被下游/数据库拒绝,测试捕获的是错误响应或错误原因,不能写成全部造成了错误释放。环境路径错误的首轮未计入;变异只在临时源码副本中进行,后续固定源码轮次摘要未变。
- 最终隔离回归:81 个迁移、HTTP 95 组、浏览器 13 组、数据库约束 9 组通过,容器清理 PASS。包含整笔超额、逐原借款差额、跨流程交易复用、原审批人离职、审计回滚、候选变更重新复核及冻结/新申请/导出的确定性交错。固定前后端源码/构建副本的最后一轮再次得到相同通过结果,副本及自有容器已清理。浏览器覆盖原有 7 组及电脑/手机 Q6 双审、SR 补证、两份处理中回单终态释放(包括作废历史回单的复核下载)6 组。人工等待期在 HTTP 验证,浏览器合成配置设为 0,不等待现实三天。
- 服务端首跑 4472 通过、8 失败、1 原有跳过(4481 总);8 个失败为报销回单旧测试替身缺少新增跨台账认领查询,补齐后相关两文件 150/150 通过,最后共享下载路径调整后再次 150/150 通过。合并覆盖 4480 项通过、1 项原有跳过,未将其描述为完整套件重新全跑通过。
- 中间失败如实保留:浏览器精确标签、分页缓存等待、Q6 合成等待期设置及重新登录加载等待先后修正;运行器后来固定 client/dist 副本,避免与构建文件更换交错。失败轮次不计通过。首轮变异因临时 Python 路径错误停在制单生成,不计有效变异。
- Prisma 校验、前端类型检查/构建、共享回单定向测试、UI 规则、错误码合同、敏感扫描、任务治理/流程合同及 git diff --check 通过。文档注册检查退出 0,保留原有 22 个未登记 docs 告警。
- 本轮只读复核修复:取代银行事件遗留冲突冻结;误报解冻依据可作废;终态界面只能选一份处理中回单;各复核卡缺准确材料绑定;已作废处理中回单无法供复核查看。分别补齐服务/数据库保护、历史证据读取及桌面手机回归。两名代理对修复后源码静态复核通过,最终运行时结果见上方;不把同模型审查当作外部业务验收。
- 最终候选另外修正:晚到事实未处理时旧取消不能释放;归属候选在批准后变化时入账拒绝;唯一交易认领只在最终入账事务消费,允许未入账失效记录重新登记。
- 所有测试只用合成数据和本次拥有的隔离容器。未查询生产、未提交推送部署;S0、真实样本和外部业务验收仍待完成,整体借款验收未通过。
复现入口沿用上面的隔离回归命令(具体命令见下方 SR 记录);新增 3 个迁移必须列入将来经过批准的预期迁移。本轮 32 项未提交,HEAD 为 `2e00d30f`;未推送、未部署、未查生产。S0 仍须核实存量、两名额外合格复核人、建行官方无结果材料和回单/指令编号对应。真实银行材料、银行事实的业务真实性以及异模型/业务独立验收不由合成数据证明。保持任务进行中,不归档。
## 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. 新增制单导出记录表(序号、时间、导出人、文件摘要、客户方流水号、金额、快照摘要),每次导出写入。<br>2. 新增银行提交尝试登记(财务登记,关联导出记录与银行指令号),提交清单须经独立复核。<br>3. 确认失败:只计未作废附件,但作废的成功或处理中回单仍阻断;**同时保留拦截**——批次存在多于一条导出记录、提交清单未经复核、或清单中不止一次提交时,一律拒绝确认失败,留待 S3 的逐次终态规则处理。<br>4. 确认失败改按付款后规则:核对冻结快照,不要求出借员工在职,当前操作人按当前资格。<br>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全部结案,但也不默认接受未知密钥风险。