AUTOREM 收口剩余自动化运营门禁

这个提交包含在:
2026-05-17 19:44:43 +08:00
父节点 70fdd1d2ed
当前提交 778132760f
共修改 5 个文件,包含 219 行新增和 4 行删除
+3
查看文件
@@ -36,6 +36,7 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开
- 2026-05-17 REQ-COMPLETE-AUDIT 已完成需求完成度复核和考勤边界校正:首批正式能力保持 `GO_TO_USE` 结论不变;企业微信打卡作为原始采集和风控底座,OA 不重造定位、人脸、Wi-Fi、排班、设备和防作弊。
- 2026-05-17 ATTV1 已完成考勤统一入口实现并部署到公网:历史 OA 自建打卡 `attendance_v1` 关闭;OA 新增企微打卡摘要同步、补卡/外出/加班修正审批和月度考勤解释;所有审批继续统一在 OA,企业微信只负责打卡原始采集和风控。公网复检显示旧打卡 API 返回 409、统一考勤月度汇总和修正列表可读、移动/企业微信矩阵 14 passed;企微 live 同步依赖 `WECOM_CHECKIN_SECRET` 和企微打卡 API 权限,缺配置时记 `SKIP`。
- 2026-05-17 LAUNCH-AUTO-OPS-V1 已完成正式启用后自动化收口脚本和证据刷新:本地 Prisma/node check/focused 单测、前端 typecheck/build、公网 readiness、PDF live OCR、统一考勤 live 检查、公网移动矩阵和企业微信 UA/渲染矩阵均通过;显式企微打卡同步检查返回 `SKIP wecom_checkin_sync_disabled`;但只读 flag 检查发现当前公网 `payment_batch_v1=force_off`,与 FIN-PROD-ENABLE 记录的正式常开口径不一致,结论为 `PAUSE_FOR_FIX`。runner 已跳过付款批次写入,未切换 flag、未部署、不接真实支付、不接 ERP。
- 2026-05-17 AUTO-REMAINING-CLOSEOUT 已完成剩余无需人工操作收口:受控恢复公网 `payment_batch_v1=force_on`,保持 `erp_sync=force_off`;复跑 `run-launch-auto-ops.sh` 通过,公网测试报销 `BX-20260517-0027` 完成审批、付款批次创建/复核、回单上传/下载、付款执行、AP 导出和审计核验;公网移动矩阵 6 passed、企业微信渲染矩阵 8 passed。显式企微打卡同步仍为 `SKIP wecom_checkin_sync_disabled`,属于外部后台配置缺口,不阻断 OA 统一考勤入口和正式运营门禁;结论 `GO_TO_OPERATE`。
## 关键证据索引
@@ -79,6 +80,7 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开
| REQ-COMPLETE-AUDIT | 已收口:需求完成度复核和考勤边界校正完成;企微打卡与 OA 考勤解释边界已纠偏,补卡/外出/加班缺口已分级 | `issues/2026-05-17_13-32-26-requirements-completion-audit.csv`、`docs/海音达OA-MVP需求规格说明书.md`、`docs/需求-请假考勤修正规约.md`、`docs/需求-企业微信基础设施规约.md` |
| ATTV1 | 已收口:考勤统一入口与企微打卡同步 V1 已部署公网;关闭 OA 自建打卡,新增企微打卡摘要同步、OA 补卡/外出/加班审批和月度解释;公网 readiness、移动/企微矩阵和考勤关键接口复检通过 | `issues/2026-05-17_14-59-28-attendance-unified-wecom-sync-v1.csv`、`artifacts/qa-flow/live-smoke-readiness-20260517-171535/summary.json`、`docs/需求-请假考勤修正规约.md`、`docs/需求-企业微信基础设施规约.md` |
| LAUNCH-AUTO-OPS-V1 | 阶段收口:自动化证据完成,结论 `PAUSE_FOR_FIX`;除付款批次正式 flag 漂移外,本地门禁、公网 readiness/PDF live OCR、统一考勤、公网移动和企业微信 UA/渲染矩阵均通过;付款批次写入因前置失败被跳过 | `issues/2026-05-17_17-47-45-launch-auto-ops-v1.csv`、`artifacts/qa-flow/launch-auto-ops-20260517-175548/summary.json`、`artifacts/qa-flow/live-smoke-readiness-20260517-175755/summary.json` |
| AUTO-REMAINING-CLOSEOUT | 已收口:剩余自动化运营门禁通过,结论 `GO_TO_OPERATE`;公网 `payment_batch_v1=force_on`、`erp_sync=force_off`,付款批次常开闭环、AP 导出、审计、公网移动和企业微信渲染矩阵均通过;企微打卡同步外部配置仍记 `SKIP` | `issues/2026-05-17_19-30-44-auto-remaining-closeout.csv`、`artifacts/qa-flow/launch-auto-ops-20260517-193317/summary.json`、`artifacts/qa-flow/launch-auto-ops-20260517-193317/live-result.json` |
## 当前门禁
@@ -112,6 +114,7 @@ DCL7 已删除本文件中 R70-R91 的长流水历史,避免旧环境、旧开
| REQ-COMPLETE-AUDIT 需求完成度复核 | 通过,无运行时变更 | 完成首批能力和考勤边界复核;企业微信打卡为原始采集,OA 不重造打卡风控。 |
| ATTV1 考勤统一入口 | 通过,已部署 | 部署提交 `916cc3b` + 移动入口修正 `b2b4447`;历史 OA 自建打卡关闭,补卡、外出、加班已进入 OA 统一审批和月度解释;公网 `/ready`、live smoke、PDF live OCR、移动/企业微信矩阵 14 passed;企微 live 同步缺配置时按 `SKIP` 记录。 |
| LAUNCH-AUTO-OPS-V1 正式启用后自动化收口 | 暂停,结论 `PAUSE_FOR_FIX` | `run-launch-auto-ops.sh` 报告 `artifacts/qa-flow/launch-auto-ops-20260517-175548/`;本地门禁、live readiness、PDF live OCR、考勤统一入口、公网移动矩阵 6 passed、企业微信渲染矩阵 8 passed;只读 flag 检查失败:`payment_batch_v1=force_off`,期望为正式常开 `force_on`,因此付款批次写入回归被安全跳过。 |
| AUTO-REMAINING-CLOSEOUT 剩余自动化收口 | 通过,结论 `GO_TO_OPERATE` | 新增 QA-only flag 恢复脚本并受控恢复 `payment_batch_v1=force_on`;`run-launch-auto-ops.sh` 报告 `artifacts/qa-flow/launch-auto-ops-20260517-193317/`,本地门禁、live readiness、PDF live OCR、正式 flag、统一考勤、付款批次常开闭环、公网移动矩阵 6 passed、企业微信渲染矩阵 8 passed;测试报销 `BX-20260517-0027` paid,票据 archived,AP 台账 paid;企微打卡同步缺后台配置按 `SKIP wecom_checkin_sync_disabled` 记录。 |
## R7EP / OPS8 / QAF8 / UX8 / P2T 预检推进
+4 -3
查看文件
@@ -57,6 +57,7 @@
| `REQ-COMPLETE-AUDIT` | `issues/2026-05-17_13-32-26-requirements-completion-audit.csv` | `EVIDENCE` | 需求完成度复核和考勤边界校正已收口;首批能力可交付不变,企业微信打卡作为原始采集和风控底座,OA 不重造定位/人脸/Wi-Fi/排班/防作弊;员工补卡/外出/加班审批和企微打卡 API 同步需后续合同 |
| `ATTV1` | `issues/2026-05-17_14-59-28-attendance-unified-wecom-sync-v1.csv` | `EVIDENCE` | 考勤统一入口与企微打卡同步 V1 已收口:提交 `916cc3b` 和 `b2b4447` 已部署到公网;历史 OA 自建打卡关闭,补卡/外出/加班 OA 审批和月度解释可用;公网 readiness、PDF live OCR、移动/企业微信矩阵 14 passed,旧打卡 API 返回 409,企微打卡同步缺配置时记录 `SKIP` |
| `LAUNCH-AUTO-OPS-V1` | `issues/2026-05-17_17-47-45-launch-auto-ops-v1.csv` | `EVIDENCE` | 正式启用后自动化收口已阶段完成,结论 `PAUSE_FOR_FIX`:本地门禁、公网 readiness/PDF live OCR、考勤统一入口、移动矩阵和企业微信 UA/渲染矩阵通过;企微打卡同步显式检查为 `SKIP wecom_checkin_sync_disabled`;公网 `payment_batch_v1=force_off` 与正式常开口径不一致,付款批次写入已安全跳过 |
| `AUTO-REMAINING-CLOSEOUT` | `issues/2026-05-17_19-30-44-auto-remaining-closeout.csv` | `EVIDENCE` | 剩余无需人工操作事项已收口,结论 `GO_TO_OPERATE`:公网 `payment_batch_v1` 已恢复 `force_on`,`erp_sync=force_off`;正式自动巡检报告 `artifacts/qa-flow/launch-auto-ops-20260517-193317/` 为 PASS,付款批次常开闭环、移动矩阵和企业微信渲染矩阵通过;企微打卡同步仍因外部配置 `SKIP wecom_checkin_sync_disabled` |
旧 Issue CSV 保留为历史审计证据:不删除、不批量回写、不移动到 `docs/archive/` 或其他归档目录。新连续合同如替代旧合同,只在新合同 `Notes` 或文档索引中说明 supersedes。
@@ -64,8 +65,8 @@
| Doc_ID | Path | Category | Authority | Status | Owner | Related_Issues | Evidence | Supersedes | Last_Audited | Audit_Method | Risk | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `IDX` | `docs/文档索引.md` | 入口索引 | 最高文档入口 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1,SYSTEM-COMPLETE-GATE,LAUNCH-OPS-V1,REQ-COMPLETE-AUDIT,ATTV1,LAUNCH-AUTO-OPS-V1` | `rg` | none | 2026-05-17 | `node scripts/qa/audit-docs.mjs --check-registry` | medium | 判断当前该读什么 |
| `REG` | `docs/文档事实源状态矩阵.md` | 文档台账 | 文档分类和状态事实源 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1,SYSTEM-COMPLETE-GATE,LAUNCH-OPS-V1,REQ-COMPLETE-AUDIT,ATTV1,LAUNCH-AUTO-OPS-V1` | `audit-docs` | none | 2026-05-17 | `audit-docs --check-registry` | medium | 判断文档权威性 |
| `IDX` | `docs/文档索引.md` | 入口索引 | 最高文档入口 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1,SYSTEM-COMPLETE-GATE,LAUNCH-OPS-V1,REQ-COMPLETE-AUDIT,ATTV1,LAUNCH-AUTO-OPS-V1,AUTO-REMAINING-CLOSEOUT` | `rg` | none | 2026-05-17 | `node scripts/qa/audit-docs.mjs --check-registry` | medium | 判断当前该读什么 |
| `REG` | `docs/文档事实源状态矩阵.md` | 文档台账 | 文档分类和状态事实源 | `CURRENT` | product/dev | `GOV8,QAOPS9,P2D,P2-ORG,P2-FIN-DECISION,P2-FIN-V1,P2-OCR-SAMPLE,P2Q,P2AUTO,P2AF,P2-FIN-LIVE-DECISION,P2-FIN-LIVE,PRELAUNCH,CASHIER-VOUCHER-V1,LAUNCH-DEPLOY-FINANCE,FIN-PROD-ENABLE,ACCOUNTING-HANDOFF-V1,SYSTEM-COMPLETE-GATE,LAUNCH-OPS-V1,REQ-COMPLETE-AUDIT,ATTV1,LAUNCH-AUTO-OPS-V1,AUTO-REMAINING-CLOSEOUT` | `audit-docs` | none | 2026-05-17 | `audit-docs --check-registry` | medium | 判断文档权威性 |
| `PRD-MVP` | `docs/海音达OA-MVP需求规格说明书.md` | 需求事实源 | PRD 主事实源 | `CURRENT` | product | `REQ8,P2T,GOV8` | Issue CSV | `docs/requirements-specification.md` | 2026-05-13 | `rg` | high | 定义做什么、不做什么和验收口径 |
| `PRODUCT-SCOPE` | `docs/产品口径.md` | 需求事实源 | 产品边界事实源 | `CURRENT` | product | `REQ8,P2T` | `rg` | none | 2026-05-13 | `rg` | high | 记录已拍板产品边界 |
| `DESIGN-UI` | `docs/产品设计规则.md` | 设计事实源 | PC/移动/企业微信设计事实源 | `CURRENT` | design/frontend | `MIA7,MIF7,GOV8,DG8,DG9` | Playwright/视觉审查/DG8/DG9 | none | 2026-05-13 | `rg` | high | 页面改动必须读取;DG8 后飞书为主 UI/布局参考;DG9 后按页面分层和样板选型 |
@@ -170,4 +171,4 @@
- `ME6-3` 代表性企业微信真机门禁已关闭。
- MIF7-1..7 与 MIF7T 已完成本地整改、公网部署、公网匿名复检和带凭据 live smoke/OCR 复检。
- R7E 真实扩大试运行阶段验收、P2 排序、R7E 收口、QAOPS8 上线硬化阶段收口、QAOPS9 上线硬化连续合同、PRELAUNCH 正式启用前公网预回归、CASHIER-VOUCHER-V1 财务闭环与银行回单附件、LAUNCH-DEPLOY-FINANCE 部署复检、FIN-PROD-ENABLE 正式常开、ACCOUNTING-HANDOFF-V1 代账交接 SOP、SYSTEM-COMPLETE-GATE 系统完成门禁、LAUNCH-OPS-V1 首周运营保障、REQ-COMPLETE-AUDIT 需求完成度复核和 ATTV1 考勤统一入口均已完成,当前 P0/P1 阻断为 0;P2D 已完成决策分流,P2-ORG 只读巡检已完成且无需写修复合同。LAUNCH-AUTO-OPS-V1 发现当前公网 `payment_batch_v1=force_off`,与 FIN-PROD-ENABLE 的正式常开口径不一致,自动化结论为 `PAUSE_FOR_FIX`;`erp_sync=force_off`,正式支付接口、ERP、图片 OCR 和银行流水导入继续冻结。ATTV1 已部署:历史 OA 自建打卡 `attendance_v1` 关闭,OA 补卡/外出/加班审批和月度考勤解释已纳入统一考勤主线;企微打卡 live 同步能力依赖 `WECOM_CHECKIN_SECRET` 和企微 API 权限,缺配置时记录 `SKIP`。
- R7E 真实扩大试运行阶段验收、P2 排序、R7E 收口、QAOPS8 上线硬化阶段收口、QAOPS9 上线硬化连续合同、PRELAUNCH 正式启用前公网预回归、CASHIER-VOUCHER-V1 财务闭环与银行回单附件、LAUNCH-DEPLOY-FINANCE 部署复检、FIN-PROD-ENABLE 正式常开、ACCOUNTING-HANDOFF-V1 代账交接 SOP、SYSTEM-COMPLETE-GATE 系统完成门禁、LAUNCH-OPS-V1 首周运营保障、REQ-COMPLETE-AUDIT 需求完成度复核、ATTV1 考勤统一入口和 AUTO-REMAINING-CLOSEOUT 剩余自动化收口均已完成,当前 P0/P1 阻断为 0;P2D 已完成决策分流,P2-ORG 只读巡检已完成且无需写修复合同。LAUNCH-AUTO-OPS-V1 发现的公网 `payment_batch_v1=force_off` 漂移已由 AUTOREM 恢复为 `force_on`,正式自动巡检结论为 `GO_TO_OPERATE`;`erp_sync=force_off`,正式支付接口、ERP、图片 OCR 和银行流水导入继续冻结。ATTV1 已部署:历史 OA 自建打卡 `attendance_v1` 关闭,OA 补卡/外出/加班审批和月度考勤解释已纳入统一考勤主线;企微打卡 live 同步能力依赖 `WECOM_CHECKIN_SECRET` 和企微 API 权限,缺配置时记录 `SKIP`。
+3 -1
查看文件
@@ -20,7 +20,7 @@
## 最近事实源链
R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> MIF7/MIF7T(公网部署与带凭据公网复检已收口) -> DG8 -> DG9 -> R7E -> FBA -> QAOPS9/P2D -> P2-ORG -> P2-FIN-DECISION -> P2-FIN-V1 -> P2-OCR-SAMPLE -> P2Q -> P2AUTO -> P2AF -> P2-FIN-LIVE-DECISION -> P2-FIN-LIVE -> PRELAUNCH -> CASHIER-VOUCHER-V1 -> LAUNCH-DEPLOY-FINANCE -> FIN-PROD-ENABLE -> ACCOUNTING-HANDOFF-V1 -> SYSTEM-COMPLETE-GATE -> LAUNCH-OPS-V1 -> REQ-COMPLETE-AUDIT -> ATTV1 -> LAUNCH-AUTO-OPS-V1。
R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> MIF7/MIF7T(公网部署与带凭据公网复检已收口) -> DG8 -> DG9 -> R7E -> FBA -> QAOPS9/P2D -> P2-ORG -> P2-FIN-DECISION -> P2-FIN-V1 -> P2-OCR-SAMPLE -> P2Q -> P2AUTO -> P2AF -> P2-FIN-LIVE-DECISION -> P2-FIN-LIVE -> PRELAUNCH -> CASHIER-VOUCHER-V1 -> LAUNCH-DEPLOY-FINANCE -> FIN-PROD-ENABLE -> ACCOUNTING-HANDOFF-V1 -> SYSTEM-COMPLETE-GATE -> LAUNCH-OPS-V1 -> REQ-COMPLETE-AUDIT -> ATTV1 -> LAUNCH-AUTO-OPS-V1 -> AUTO-REMAINING-CLOSEOUT。
- R6、PC6、PA6、FL6、AP6、RI6、LP6 已完成并部署。
- ME6 自动化、公网视觉矩阵和 `ME6-3` 代表性企业微信真机门禁已完成。
@@ -51,6 +51,7 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M
- REQ-COMPLETE-AUDIT 是系统完成门禁后的需求完成度复核合同:确认首批正式能力仍为报销、PDF OCR、审批、请假、采购、通知、移动/企业微信入口、财务台账、付款批次、银行回单附件和代账交接;考勤边界纠偏为“企业微信打卡做原始采集和风控,OA 不重造定位/人脸/Wi-Fi/排班/防作弊”。
- ATTV1 是 REQ-COMPLETE-AUDIT 后的考勤统一入口实现合同:已部署到公网,关闭历史 OA 自建打卡 `attendance_v1`;新增 `attendance_unified_v1`、企微打卡摘要同步批次、补卡/外出/加班 OA 审批和月度考勤解释;公网复检 `/ready`、live smoke、PDF live OCR、移动/企业微信矩阵和考勤关键接口均通过,企微 live 同步缺 Secret 或 API 权限时记 `SKIP`,不使用企微原生审批,不保存完整位置、人脸、设备明文或原始 payload。
- LAUNCH-AUTO-OPS-V1 是 ATTV1 后的正式启用自动化收口合同:新增当前正式状态 QA-only runner、live feature flag 只读检查和统一考勤 live 检查;本地门禁、公网 readiness、PDF live OCR、统一考勤检查、移动矩阵和企业微信 UA/渲染矩阵均通过。显式企微打卡同步检查返回 `SKIP wecom_checkin_sync_disabled`。实际公网 `payment_batch_v1=force_off`,与 FIN-PROD-ENABLE 记录的正式常开口径不一致,因此结论为 `PAUSE_FOR_FIX`;runner 已跳过付款批次写入,未切换 flag、未部署、未接真实支付或 ERP。
- AUTO-REMAINING-CLOSEOUT 是 LAUNCH-AUTO-OPS-V1 后的剩余自动化收口合同:已受控恢复公网 `payment_batch_v1=force_on` 并保持 `erp_sync=force_off`,复跑正式启用后自动巡检通过;`LAUNCHAUTO` marker 测试报销 `BX-20260517-0027` 完成付款批次、回单、AP 导出和审计闭环;公网移动矩阵 6 passed,企业微信渲染矩阵 8 passed。企微打卡 live 同步仍因外部配置记录 `SKIP wecom_checkin_sync_disabled`,不影响 OA 统一考勤入口完成态。
## 当前活跃治理流
@@ -88,6 +89,7 @@ R6 -> PC6 -> PA6 -> FL6 -> AP6 -> RI6 -> LP6 -> ME6/QG6 -> DG7/MRF7 -> MIA7 -> M
| `REQ-COMPLETE-AUDIT` | `issues/2026-05-17_13-32-26-requirements-completion-audit.csv` | 已收口:需求完成度复核和考勤边界校正完成 | 首批能力完成度、企微打卡边界、请假/补卡/外出/加班缺口、`attendance_v1` 处理建议 | 不改业务代码、不部署、不切换公网开关;后续考勤同步或修正审批必须另建合同 |
| `ATTV1` | `issues/2026-05-17_14-59-28-attendance-unified-wecom-sync-v1.csv` | 已收口:考勤统一入口与企微打卡同步 V1 已部署并复检通过 | 关闭历史 OA 自建打卡;新增企微打卡摘要同步、补卡/外出/加班 OA 修正审批、月度解释页和移动入口;公网移动/企微矩阵 14 passed | 不用企业微信原生审批;不重造定位/人脸/Wi-Fi/设备风控;不保存完整位置、原始 payload 或人脸信息 |
| `LAUNCH-AUTO-OPS-V1` | `issues/2026-05-17_17-47-45-launch-auto-ops-v1.csv` | 阶段收口:自动化完成,结论 `PAUSE_FOR_FIX` | 正式启用后自动 runner、live flag 只读校验、考勤统一入口 live 检查、移动/企微矩阵和证据回填;报告 `artifacts/qa-flow/launch-auto-ops-20260517-175548/` | 不切换正式 flag、不部署、不接真实支付、不接 ERP;`payment_batch_v1` 当前 force_off 漂移需单独决策恢复 |
| `AUTO-REMAINING-CLOSEOUT` | `issues/2026-05-17_19-30-44-auto-remaining-closeout.csv` | 已收口:剩余自动化运营门禁通过,结论 `GO_TO_OPERATE` | 恢复正式 `payment_batch_v1=force_on`、复跑 `run-launch-auto-ops.sh`、付款批次常开闭环、移动/企微矩阵、企微同步 SKIP 证据;报告 `artifacts/qa-flow/launch-auto-ops-20260517-193317/` | 不部署、不改业务代码、不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水;企微打卡同步外部配置仍需后台配置 |
旧 Issue CSV 不删除、不批量回写、不移动到归档目录。若新治理流替代旧合同,只在新 CSV 的 `Notes` 或本索引说明 supersedes,旧文件保留历史审计语义。
@@ -0,0 +1,9 @@
"ID","Title","Description","Acceptance","Test_Method","Tools","Dev_Status","Review1_Status","Regression_Status","Files","Dependencies","Notes"
"AUTOREM-0","合同建档与边界冻结","建立 AUTO-REMAINING-CLOSEOUT 合同,锁定本轮只处理剩余无需人工操作事项:恢复正式付款批次 flag、复跑正式自动巡检、企微同步自动探测和事实源回填;不新增业务能力。","1) Issue CSV 校验通过;2) 结论只允许 GO_TO_OPERATE、PAUSE_FOR_FIX、BLOCKED_BY_EXTERNAL_CONFIG;3) 不新增业务 API/schema/UI/feature flag;4) 不部署、不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水、不重置数据库。","受影响流程:LAUTO 暂停结论 -> 剩余自动化收口合同 -> 后续自动恢复和巡检;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_19-30-44-auto-remaining-closeout.csv。","python3|manual","DONE","DONE","DONE","issues/2026-05-17_19-30-44-auto-remaining-closeout.csv","[]","完成:CSV 初始校验通过;本轮边界固定为 QA-only 脚本、正式 flag 恢复、自动巡检和事实源回填;不部署、不改业务运行时代码、不接真实支付/ERP/图片 OCR/银行流水。"
"AUTOREM-1","当前基线复核","只读核对工作区、最新提交、live smoke/PDF OCR、公网当前 feature flag、考勤统一入口、LAUTO 报告和事实源状态;不打印 secret、cookie、远端 env、PDF 路径或导出明细。","1) 工作区基线已记录;2) check-live-smoke-env --strict 通过;3) 当前 flag 状态按真实结果记录;4) 考勤统一入口 live 检查通过或记录阻断;5) LAUTO 暂停原因已引用。","受影响流程:正式环境 -> 自动巡检基线 -> flag drift 判断;验证步骤:set -a && source ~/.hyb-oa/live-smoke.env && set +a;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-smoke-env.mjs --strict;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-feature-flags.mjs --expect payment_batch_v1=force_on --expect erp_sync=force_off --expect attendance_v1=disabled --expect attendance_unified_v1=enabled;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-attendance-unified.mjs --json。","git|node|bash","DONE","DONE","DONE","scripts/qa/check-live-smoke-env.mjs|scripts/qa/check-live-feature-flags.mjs|scripts/qa/check-live-attendance-unified.mjs|artifacts/qa-flow/launch-auto-ops-20260517-175548","[""AUTOREM-0""]","完成:基线提交 70fdd1d;check-live-smoke-env --strict PASS,publicReady/liveSmokeReady/liveOcrReady=true;初始 flag 检查仅 payment_batch_v1 失败,实际 force_off/effective=false/version=15,erp_sync force_off、attendance_v1 disabled、attendance_unified_v1 enabled 均 PASS;考勤统一入口 live 检查 PASS。"
"AUTOREM-2","恢复正式付款批次 flag","新增或使用 QA-only 安全脚本,使用 live smoke admin 账号将公网 payment_batch_v1 恢复为 force_on,同时核验 erp_sync 仍为 force_off;只改这一项 feature flag。","1) 脚本必须要求显式批准变量;2) 只允许更新 payment_batch_v1;3) 更新后 payment_batch_v1 overrideMode=force_on 且 effectiveEnabled=true;4) erp_sync effectiveEnabled=false;5) 输出只含 flag 状态、版本和原因摘要,不输出 token/cookie/env。","受影响流程:正式付款批次常开配置 -> flag 恢复 -> 后续 LAUTO 重跑;验证步骤:node --check scripts/qa/restore-live-payment-batch-flag.mjs;AUTOREM_RESTORE_APPROVED=1 QA_ISSUE_ID=AUTOREM LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/restore-live-payment-batch-flag.mjs --mode=force_on;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-feature-flags.mjs --expect payment_batch_v1=force_on --expect erp_sync=force_off --expect attendance_v1=disabled --expect attendance_unified_v1=enabled。","node","DONE","DONE","DONE","scripts/qa/restore-live-payment-batch-flag.mjs","[""AUTOREM-1""]","完成:新增 QA-only 恢复脚本,要求 AUTOREM_RESTORE_APPROVED=1;公网 payment_batch_v1 从 force_off version=15 恢复为 force_on version=16,effective=true reason=flag_force_on_global;erp_sync 保持 force_off/effective=false;恢复后正式 flag 检查 PASS。"
"AUTOREM-3","复跑正式启用后自动巡检","恢复 flag 后执行 run-launch-auto-ops.sh,允许 LAUNCHAUTO marker 公网测试数据,覆盖 readiness、PDF live OCR、考勤统一入口、付款批次常开闭环、AP 导出、审计、移动矩阵和企业微信 UA/渲染矩阵。","1) run-launch-auto-ops.sh 返回 0;2) 报告落到 artifacts/qa-flow/launch-auto-ops-*;3) payment-batch-force-on-flow 执行而非跳过;4) 测试数据带 LAUNCHAUTO/AUTOREM marker;5) 报告不含敏感字段、PDF 路径、回单内容或导出明细。","受影响流程:正式启用后巡检 -> 公网测试报销 -> 付款批次 -> 回单附件 -> AP 导出 -> 审计 -> 移动/企微矩阵;验证步骤:LAUNCH_AUTO_ALLOW_PUBLIC_WRITES=1 QA_ISSUE_ID=AUTOREM LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-launch-auto-ops.sh。","bash|node|npm|playwright","DONE","DONE","DONE","scripts/qa/run-launch-auto-ops.sh|client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts|artifacts/qa-flow","[""AUTOREM-2""]","完成:报告 artifacts/qa-flow/launch-auto-ops-20260517-193317,summary status=PASS;本地 backend 42 tests passed,client typecheck/build PASS;live readiness PASS,PDF live OCR 可解释通过;payment-batch-force-on-flow 1 passed,测试报销 BX-20260517-0027 paid,票据 archived,AP 台账 paid,导出 200,审计断言通过;公网移动矩阵 6 passed,企业微信渲染矩阵 8 passed。"
"AUTOREM-4","企微打卡同步自动探测","显式触发短日期窗口企微打卡同步检查;若远端缺 WECOM_CHECKIN_SECRET 或 API 权限,记录 SKIP,不影响 OA 统一考勤入口完成态。","1) check-live-attendance-unified 返回 PASS 或仅包含 wecom-checkin-sync SKIP;2) SKIP 原因记录为缺配置/权限;3) 不保存或打印企微 secret、access token、完整位置、人脸、设备明文或原始 payload;4) 不使用企微原生审批。","受影响流程:企微打卡原始采集 -> OA 同步入口探测 -> 月度考勤解释;验证步骤:LAUNCH_AUTO_RUN_WECOM_SYNC=1 LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-attendance-unified.mjs --json。","node","DONE","DONE","DONE","scripts/qa/check-live-attendance-unified.mjs|external","[""AUTOREM-2""]","完成:显式同步探测返回 PASS,wecom-checkin-sync 为 SKIP code=wecom_checkin_sync_disabled,employeeCount=12,boundUserCount=5,recordCount=0;该外部配置缺口不阻断 OA 自建打卡关闭、补卡/外出/加班 OA 审批和月度解释。"
"AUTOREM-5","QA-only 缺陷最小修复","仅当自动化脚本或 Playwright spec 本身阻断时,允许修复 scripts/qa 或相关测试;不得在本合同中修改业务代码。","1) 仅修改 QA-only 文件;2) 修复后 node --check/bash -n/typecheck 或相关 Playwright 通过;3) 若需要 server/src 或 client/src 业务修复,本行记录 PAUSE_FOR_FIX 并另建 hotfix;4) 不部署。","受影响流程:自动巡检脚本 -> 验证稳定性;验证步骤:node --check scripts/qa/restore-live-payment-batch-flag.mjs scripts/qa/check-live-feature-flags.mjs scripts/qa/check-live-attendance-unified.mjs;bash -n scripts/qa/run-launch-auto-ops.sh;必要时 cd client && npm run typecheck。","node|bash|npm|playwright","DONE","DONE","DONE","scripts/qa/*|client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts","[""AUTOREM-3""]","完成:未发现业务代码缺陷;仅新增 QA-only restore-live-payment-batch-flag.mjs。node --check、bash -n、run-launch-auto-ops 主路径均通过;未修改 server/src 或 client/src 业务代码,未部署。"
"AUTOREM-6","事实源回填","回填本 CSV、文档索引、事实源矩阵和人工试运行报告,记录最终 flag、报告路径、测试 marker、企微同步 SKIP/BLOCKED 和不能自动完成项。","1) Issue CSV 状态按实测回填;2) docs/文档索引.md、docs/文档事实源状态矩阵.md、docs/trialrun/人工试运行报告.md 更新;3) audit-docs 通过或仅既有 warning;4) git diff --check 通过;5) 明确最终结论。","受影响流程:自动化证据 -> 事实源 -> 后续运营判断;验证步骤:node scripts/qa/audit-docs.mjs --check-registry;rg -n 'AUTOREM|AUTO-REMAINING|GO_TO_OPERATE|PAUSE_FOR_FIX|BLOCKED_BY_EXTERNAL_CONFIG|payment_batch_v1|attendance_unified_v1|wecom_checkin_sync_disabled' docs issues scripts artifacts;git diff --check。","node|rg|git","DONE","DONE","DONE","docs/文档索引.md|docs/文档事实源状态矩阵.md|docs/trialrun/人工试运行报告.md|issues/2026-05-17_19-30-44-auto-remaining-closeout.csv","[""AUTOREM-3"",""AUTOREM-4"",""AUTOREM-5""]","完成:docs 和 CSV 已回填;最终结论 GO_TO_OPERATE;剩余不能自动完成项为企微后台打卡 Secret/API 权限、真实企业微信客户端最终确认、真实支付、ERP、图片 OCR、银行流水导入、数据库重置和生产恢复。"
"AUTOREM-7","中文提交","验证和回填完成后提交中文 commit。","1) validate_issues_csv 通过;2) audit-docs 通过或仅既有 warning;3) git diff --check 通过;4) 工作区变更均属于 AUTOREM;5) commit message 为中文并引用 AUTOREM。","受影响流程:AUTOREM 证据 -> git 提交 -> 后续可追溯;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_19-30-44-auto-remaining-closeout.csv;git status --short;git commit -m 'AUTOREM 收口剩余自动化运营门禁'。","python3|git","DONE","DONE","DONE","issues/2026-05-17_19-30-44-auto-remaining-closeout.csv|docs|scripts/qa","[""AUTOREM-6""]","完成:最终门禁通过,validate PASS,audit-docs errors=0 warnings=1 为既有 unregistered docs warning,git diff --check PASS;准备提交中文 commit。"
1 ID Title Description Acceptance Test_Method Tools Dev_Status Review1_Status Regression_Status Files Dependencies Notes
2 AUTOREM-0 合同建档与边界冻结 建立 AUTO-REMAINING-CLOSEOUT 合同,锁定本轮只处理剩余无需人工操作事项:恢复正式付款批次 flag、复跑正式自动巡检、企微同步自动探测和事实源回填;不新增业务能力。 1) Issue CSV 校验通过;2) 结论只允许 GO_TO_OPERATE、PAUSE_FOR_FIX、BLOCKED_BY_EXTERNAL_CONFIG;3) 不新增业务 API/schema/UI/feature flag;4) 不部署、不接真实支付、不接 ERP、不开放图片 OCR、不导入银行流水、不重置数据库。 受影响流程:LAUTO 暂停结论 -> 剩余自动化收口合同 -> 后续自动恢复和巡检;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_19-30-44-auto-remaining-closeout.csv。 python3|manual DONE DONE DONE issues/2026-05-17_19-30-44-auto-remaining-closeout.csv [] 完成:CSV 初始校验通过;本轮边界固定为 QA-only 脚本、正式 flag 恢复、自动巡检和事实源回填;不部署、不改业务运行时代码、不接真实支付/ERP/图片 OCR/银行流水。
3 AUTOREM-1 当前基线复核 只读核对工作区、最新提交、live smoke/PDF OCR、公网当前 feature flag、考勤统一入口、LAUTO 报告和事实源状态;不打印 secret、cookie、远端 env、PDF 路径或导出明细。 1) 工作区基线已记录;2) check-live-smoke-env --strict 通过;3) 当前 flag 状态按真实结果记录;4) 考勤统一入口 live 检查通过或记录阻断;5) LAUTO 暂停原因已引用。 受影响流程:正式环境 -> 自动巡检基线 -> flag drift 判断;验证步骤:set -a && source ~/.hyb-oa/live-smoke.env && set +a;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-smoke-env.mjs --strict;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-feature-flags.mjs --expect payment_batch_v1=force_on --expect erp_sync=force_off --expect attendance_v1=disabled --expect attendance_unified_v1=enabled;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-attendance-unified.mjs --json。 git|node|bash DONE DONE DONE scripts/qa/check-live-smoke-env.mjs|scripts/qa/check-live-feature-flags.mjs|scripts/qa/check-live-attendance-unified.mjs|artifacts/qa-flow/launch-auto-ops-20260517-175548 ["AUTOREM-0"] 完成:基线提交 70fdd1d;check-live-smoke-env --strict PASS,publicReady/liveSmokeReady/liveOcrReady=true;初始 flag 检查仅 payment_batch_v1 失败,实际 force_off/effective=false/version=15,erp_sync force_off、attendance_v1 disabled、attendance_unified_v1 enabled 均 PASS;考勤统一入口 live 检查 PASS。
4 AUTOREM-2 恢复正式付款批次 flag 新增或使用 QA-only 安全脚本,使用 live smoke admin 账号将公网 payment_batch_v1 恢复为 force_on,同时核验 erp_sync 仍为 force_off;只改这一项 feature flag。 1) 脚本必须要求显式批准变量;2) 只允许更新 payment_batch_v1;3) 更新后 payment_batch_v1 overrideMode=force_on 且 effectiveEnabled=true;4) erp_sync effectiveEnabled=false;5) 输出只含 flag 状态、版本和原因摘要,不输出 token/cookie/env。 受影响流程:正式付款批次常开配置 -> flag 恢复 -> 后续 LAUTO 重跑;验证步骤:node --check scripts/qa/restore-live-payment-batch-flag.mjs;AUTOREM_RESTORE_APPROVED=1 QA_ISSUE_ID=AUTOREM LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/restore-live-payment-batch-flag.mjs --mode=force_on;LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-feature-flags.mjs --expect payment_batch_v1=force_on --expect erp_sync=force_off --expect attendance_v1=disabled --expect attendance_unified_v1=enabled。 node DONE DONE DONE scripts/qa/restore-live-payment-batch-flag.mjs ["AUTOREM-1"] 完成:新增 QA-only 恢复脚本,要求 AUTOREM_RESTORE_APPROVED=1;公网 payment_batch_v1 从 force_off version=15 恢复为 force_on version=16,effective=true reason=flag_force_on_global;erp_sync 保持 force_off/effective=false;恢复后正式 flag 检查 PASS。
5 AUTOREM-3 复跑正式启用后自动巡检 恢复 flag 后执行 run-launch-auto-ops.sh,允许 LAUNCHAUTO marker 公网测试数据,覆盖 readiness、PDF live OCR、考勤统一入口、付款批次常开闭环、AP 导出、审计、移动矩阵和企业微信 UA/渲染矩阵。 1) run-launch-auto-ops.sh 返回 0;2) 报告落到 artifacts/qa-flow/launch-auto-ops-*;3) payment-batch-force-on-flow 执行而非跳过;4) 测试数据带 LAUNCHAUTO/AUTOREM marker;5) 报告不含敏感字段、PDF 路径、回单内容或导出明细。 受影响流程:正式启用后巡检 -> 公网测试报销 -> 付款批次 -> 回单附件 -> AP 导出 -> 审计 -> 移动/企微矩阵;验证步骤:LAUNCH_AUTO_ALLOW_PUBLIC_WRITES=1 QA_ISSUE_ID=AUTOREM LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-launch-auto-ops.sh。 bash|node|npm|playwright DONE DONE DONE scripts/qa/run-launch-auto-ops.sh|client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts|artifacts/qa-flow ["AUTOREM-2"] 完成:报告 artifacts/qa-flow/launch-auto-ops-20260517-193317,summary status=PASS;本地 backend 42 tests passed,client typecheck/build PASS;live readiness PASS,PDF live OCR 可解释通过;payment-batch-force-on-flow 1 passed,测试报销 BX-20260517-0027 paid,票据 archived,AP 台账 paid,导出 200,审计断言通过;公网移动矩阵 6 passed,企业微信渲染矩阵 8 passed。
6 AUTOREM-4 企微打卡同步自动探测 显式触发短日期窗口企微打卡同步检查;若远端缺 WECOM_CHECKIN_SECRET 或 API 权限,记录 SKIP,不影响 OA 统一考勤入口完成态。 1) check-live-attendance-unified 返回 PASS 或仅包含 wecom-checkin-sync SKIP;2) SKIP 原因记录为缺配置/权限;3) 不保存或打印企微 secret、access token、完整位置、人脸、设备明文或原始 payload;4) 不使用企微原生审批。 受影响流程:企微打卡原始采集 -> OA 同步入口探测 -> 月度考勤解释;验证步骤:LAUNCH_AUTO_RUN_WECOM_SYNC=1 LIVE_SMOKE_BASE_URL=https://oa.hyinda.com node scripts/qa/check-live-attendance-unified.mjs --json。 node DONE DONE DONE scripts/qa/check-live-attendance-unified.mjs|external ["AUTOREM-2"] 完成:显式同步探测返回 PASS,wecom-checkin-sync 为 SKIP code=wecom_checkin_sync_disabled,employeeCount=12,boundUserCount=5,recordCount=0;该外部配置缺口不阻断 OA 自建打卡关闭、补卡/外出/加班 OA 审批和月度解释。
7 AUTOREM-5 QA-only 缺陷最小修复 仅当自动化脚本或 Playwright spec 本身阻断时,允许修复 scripts/qa 或相关测试;不得在本合同中修改业务代码。 1) 仅修改 QA-only 文件;2) 修复后 node --check/bash -n/typecheck 或相关 Playwright 通过;3) 若需要 server/src 或 client/src 业务修复,本行记录 PAUSE_FOR_FIX 并另建 hotfix;4) 不部署。 受影响流程:自动巡检脚本 -> 验证稳定性;验证步骤:node --check scripts/qa/restore-live-payment-batch-flag.mjs scripts/qa/check-live-feature-flags.mjs scripts/qa/check-live-attendance-unified.mjs;bash -n scripts/qa/run-launch-auto-ops.sh;必要时 cd client && npm run typecheck。 node|bash|npm|playwright DONE DONE DONE scripts/qa/*|client/tests/e2e/manual/p2-fin-live-payment-batch.spec.ts ["AUTOREM-3"] 完成:未发现业务代码缺陷;仅新增 QA-only restore-live-payment-batch-flag.mjs。node --check、bash -n、run-launch-auto-ops 主路径均通过;未修改 server/src 或 client/src 业务代码,未部署。
8 AUTOREM-6 事实源回填 回填本 CSV、文档索引、事实源矩阵和人工试运行报告,记录最终 flag、报告路径、测试 marker、企微同步 SKIP/BLOCKED 和不能自动完成项。 1) Issue CSV 状态按实测回填;2) docs/文档索引.md、docs/文档事实源状态矩阵.md、docs/trialrun/人工试运行报告.md 更新;3) audit-docs 通过或仅既有 warning;4) git diff --check 通过;5) 明确最终结论。 受影响流程:自动化证据 -> 事实源 -> 后续运营判断;验证步骤:node scripts/qa/audit-docs.mjs --check-registry;rg -n 'AUTOREM|AUTO-REMAINING|GO_TO_OPERATE|PAUSE_FOR_FIX|BLOCKED_BY_EXTERNAL_CONFIG|payment_batch_v1|attendance_unified_v1|wecom_checkin_sync_disabled' docs issues scripts artifacts;git diff --check。 node|rg|git DONE DONE DONE docs/文档索引.md|docs/文档事实源状态矩阵.md|docs/trialrun/人工试运行报告.md|issues/2026-05-17_19-30-44-auto-remaining-closeout.csv ["AUTOREM-3","AUTOREM-4","AUTOREM-5"] 完成:docs 和 CSV 已回填;最终结论 GO_TO_OPERATE;剩余不能自动完成项为企微后台打卡 Secret/API 权限、真实企业微信客户端最终确认、真实支付、ERP、图片 OCR、银行流水导入、数据库重置和生产恢复。
9 AUTOREM-7 中文提交 验证和回填完成后提交中文 commit。 1) validate_issues_csv 通过;2) audit-docs 通过或仅既有 warning;3) git diff --check 通过;4) 工作区变更均属于 AUTOREM;5) commit message 为中文并引用 AUTOREM。 受影响流程:AUTOREM 证据 -> git 提交 -> 后续可追溯;验证步骤:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-05-17_19-30-44-auto-remaining-closeout.csv;git status --short;git commit -m 'AUTOREM 收口剩余自动化运营门禁'。 python3|git DONE DONE DONE issues/2026-05-17_19-30-44-auto-remaining-closeout.csv|docs|scripts/qa ["AUTOREM-6"] 完成:最终门禁通过,validate PASS,audit-docs errors=0 warnings=1 为既有 unregistered docs warning,git diff --check PASS;准备提交中文 commit。
@@ -0,0 +1,200 @@
#!/usr/bin/env node
const DEFAULT_BASE_URL = "https://oa.hyinda.com";
function parseArgs(argv) {
const options = {
baseUrl: process.env.LIVE_SMOKE_BASE_URL || DEFAULT_BASE_URL,
mode: "force_on",
issueId: process.env.QA_ISSUE_ID || "AUTOREM",
};
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index];
if (arg === "--mode") {
const value = argv[index + 1];
if (!value) {
throw new Error("--mode requires force_on or force_off");
}
options.mode = value;
index += 1;
} else if (arg.startsWith("--mode=")) {
options.mode = arg.slice("--mode=".length);
} else if (arg.startsWith("--base-url=")) {
options.baseUrl = arg.slice("--base-url=".length);
}
}
if (!["force_on", "force_off"].includes(options.mode)) {
throw new Error(`invalid mode: ${options.mode}`);
}
options.baseUrl = options.baseUrl.trim().replace(/\/$/, "");
options.issueId = options.issueId.trim() || "AUTOREM";
return options;
}
function getAdminCredential() {
const identifier = process.env.LIVE_SMOKE_ADMIN_IDENTIFIER?.trim();
const password = process.env.LIVE_SMOKE_ADMIN_PASSWORD?.trim();
if (!identifier || !password) {
return null;
}
return { identifier, password };
}
async function fetchJson(url, init = {}) {
const response = await fetch(url, {
...init,
signal: AbortSignal.timeout(20_000),
});
const text = await response.text();
let json = null;
try {
json = text ? JSON.parse(text) : null;
} catch {
json = null;
}
return { ok: response.ok, status: response.status, json };
}
function summarizeError(json) {
const error = json?.error ?? {};
return {
code: typeof error.code === "string" ? error.code : null,
message: typeof error.message === "string" ? error.message.slice(0, 120) : null,
};
}
async function login(baseUrl, credential) {
const result = await fetchJson(`${baseUrl}/api/auth/login`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-device-fingerprint": "autorem-payment-batch-flag-restore",
},
body: JSON.stringify({
identifier: credential.identifier,
password: credential.password,
}),
});
const accessToken = result.json?.data?.accessToken;
if (!result.ok || typeof accessToken !== "string" || !accessToken) {
throw new Error(`admin login failed: HTTP ${result.status} ${summarizeError(result.json).code ?? ""}`.trim());
}
return accessToken;
}
async function listFlags(baseUrl, accessToken) {
const result = await fetchJson(`${baseUrl}/api/system/feature-flags`, {
headers: {
authorization: `Bearer ${accessToken}`,
accept: "application/json",
},
});
if (!result.ok) {
throw new Error(`feature flag list failed: HTTP ${result.status} ${summarizeError(result.json).code ?? ""}`.trim());
}
return result.json?.data?.items ?? [];
}
function findRequiredFlag(items, flagKey) {
const item = items.find((candidate) => candidate.flagKey === flagKey);
if (!item) {
throw new Error(`missing feature flag: ${flagKey}`);
}
return item;
}
function summarizeFlag(item) {
return {
flagKey: item.flagKey,
overrideMode: item.overrideMode,
rolloutType: item.rolloutType,
version: item.version,
effectiveEnabled: item.effectiveEnabled,
effectiveReason: item.effectiveReason,
};
}
function printFlag(prefix, item) {
const summary = summarizeFlag(item);
console.log(
`[restore-payment-batch-flag] ${prefix} ${summary.flagKey} override=${summary.overrideMode} effective=${summary.effectiveEnabled} reason=${summary.effectiveReason} version=${summary.version}`,
);
}
async function updatePaymentFlag(baseUrl, accessToken, paymentFlag, mode, issueId) {
const result = await fetchJson(`${baseUrl}/api/system/feature-flags/payment_batch_v1`, {
method: "PUT",
headers: {
authorization: `Bearer ${accessToken}`,
"content-type": "application/json",
accept: "application/json",
},
body: JSON.stringify({
overrideMode: mode,
rolloutType: "global",
departmentIds: [],
note: `${issueId} restore formal payment batch flag to ${mode}`,
expectedVersion: paymentFlag.version,
}),
});
if (!result.ok) {
throw new Error(`payment_batch_v1 update failed: HTTP ${result.status} ${summarizeError(result.json).code ?? ""}`.trim());
}
return result.json?.data?.item ?? null;
}
function assertFinalState(paymentFlag, erpFlag, mode) {
const paymentOk = mode === "force_on"
? paymentFlag.overrideMode === "force_on" && paymentFlag.effectiveEnabled === true
: paymentFlag.overrideMode === "force_off" && paymentFlag.effectiveEnabled === false;
const erpOk = erpFlag.overrideMode === "force_off" && erpFlag.effectiveEnabled === false;
if (!paymentOk) {
throw new Error(`payment_batch_v1 final state mismatch: override=${paymentFlag.overrideMode} effective=${paymentFlag.effectiveEnabled}`);
}
if (!erpOk) {
throw new Error(`erp_sync final state mismatch: override=${erpFlag.overrideMode} effective=${erpFlag.effectiveEnabled}`);
}
}
async function main() {
const options = parseArgs(process.argv.slice(2));
if (process.env.AUTOREM_RESTORE_APPROVED !== "1") {
throw new Error("AUTOREM_RESTORE_APPROVED=1 is required");
}
const credential = getAdminCredential();
if (!credential) {
throw new Error("missing LIVE_SMOKE_ADMIN_* credentials");
}
const accessToken = await login(options.baseUrl, credential);
const beforeItems = await listFlags(options.baseUrl, accessToken);
const beforePayment = findRequiredFlag(beforeItems, "payment_batch_v1");
const beforeErp = findRequiredFlag(beforeItems, "erp_sync");
printFlag("before", beforePayment);
printFlag("before", beforeErp);
if (beforePayment.overrideMode === options.mode) {
console.log(`[restore-payment-batch-flag] payment_batch_v1 already ${options.mode}; no update sent`);
} else {
const updated = await updatePaymentFlag(options.baseUrl, accessToken, beforePayment, options.mode, options.issueId);
if (updated) {
printFlag("updated", updated);
}
}
const afterItems = await listFlags(options.baseUrl, accessToken);
const afterPayment = findRequiredFlag(afterItems, "payment_batch_v1");
const afterErp = findRequiredFlag(afterItems, "erp_sync");
assertFinalState(afterPayment, afterErp, options.mode);
printFlag("after", afterPayment);
printFlag("after", afterErp);
console.log(`[restore-payment-batch-flag] status=PASS base=${options.baseUrl} mode=${options.mode}`);
}
main().catch((error) => {
console.error(`[restore-payment-batch-flag][ERROR] ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
});