Files
gaokao-volunteer-system/docs/P0_P1_P2_REMEDIATION_PLAN_2026-06-14.md
Hermes 7d31d75145
Some checks failed
CI / pytest (Python 3.10) (push) Has been cancelled
CI / pytest (Python 3.11) (push) Has been cancelled
CI / pytest (Python 3.12) (push) Has been cancelled
feat(cli): add order delegation + doctor self-check (phase 3)
docs-only + cli: extend scripts/gaokao-cli with two thin wrappers
without changing data/rules, data/majors_catalog, or rules/_truth.

- gaokao-cli order <subcommand> delegates argv to data.orders.cli.main
  with the 'order' prefix stripped, so callers can use the unified
  command face without changing the existing orders parser.
- gaokao-cli doctor <json?> returns a single self-check payload that
  reuses RuleLoader + MajorsCatalogLoader (no new dependencies, no
  gaokato/ scaffolding). Truth-root or catalog-root failures degrade
  gracefully with structured {error, ok=false} sections instead of
  raising.
- tests/test_cli_doctor_phase3.py covers: help text, order delegation
  to list subcommand, doctor ok-path, doctor failure-path.

Also re-aligns docs/ACTIVE_EXECUTION_BOARD_2026-06-17.md (new) +
docs/CURRENT_STATE.md (single execution口径) + rules/majors source-
of-truth index files so design-phase numbering no longer drifts from
execution-phase numbering. Pre-existing 2026-06-16 optimization board
and 2026-06-17 phase2 plan are demoted to historical snapshots.
P0_P1_P2 remediation plan §4 historical cards get a red warning
banner so they are not re-read as current pending.

Verification:
- focused: 4 passed
- dev-verify: 770 passed, 1 failed
  (alipay_sim E2E failure pre-existed this commit; caused by an
  uncommitted upstream edit in admin/routes/web_public.py that
  rewires payment_return -> /portal/{token}/payment-success while
  the E2E still asserts /portal/{token}/status; out of scope for
  this commit and intentionally not touched.)
2026-06-17 18:05:16 +08:00

435 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SYSTEM_REVIEW_REMEDIATION_PLAN_2026-06-14
生成时间: 2026-06-14
来源报告: `reports/PROJECT_SYSTEM_REVIEW_2026-06-14.md`
适用范围: 仅保留“当前真实有效且需要处理”的问题
真相源: `docs/CURRENT_STATE.md`
---
## 1. 当前门禁结论
结论: 条件通过 / 本轮工程整改已大部分完成,剩余项已转入 T12 后续阶段
说明:
- 对“人工服务运营增强系统 v2.1 已完成”这一表述:仍成立
- 对“可放心放量的完整商业闭环系统”这一表述:当前仍不成立
- 2026-06-15 起,本计划中的任务需要按三类理解:
1. 已完成
2. 已完成但仍有后续生产接入工作,已转入 T12
3. 未完成并已明确并入 T12 后续阶段
禁止错误表述:
- ❌ “支付闭环已完全成熟”
- ❌ “删除/匿名化已完整满足合规”
- ❌ “验证链已经完全可信”
- ❌ “灾备已经完成恢复演练(含生产接入)”
允许表述:
- ✅ “v2.1 已完成后台运营链路与 AI 审核增强闭环”
- ✅ “本轮 P1/P2 大部分工程整改已完成,剩余工作已转入 T12/上线前收口”
---
## 2. 只保留仍然有效的问题
### P1必须优先修
1. 支付回调双写裂缝
2. 删除/匿名化与文档承诺不一致
3. 支付回调校验过弱
4. webhook server 全局 DB 连接污染风险
5. 退款域模型未闭环
6. 分享 edit/admin 默认全透传风险
7. 覆盖率/CI/codecov/dev-verify 门禁口径冲突
8. 备份恢复不是服务级恢复演练
### P2应在下一轮收敛
9. 公共下单先写订单再建支付,失败留孤儿订单
10. channel_sync 仍走被替代的 dao_extension
11. delivery dispatcher 把“文件存在”标记为 sent
12. portal token 与后台 JWT 共用同一根 secret
13. payment webhook secret 有开发默认值且未 fail-closed
14. 历史快照文档仍需统一标注,避免再次漂移
### 2.1 2026-06-15 状态归一
已完成:
- P1-1 / P1-2 / P1-4 / P1-5 / P1-6 / P1-7 / P1-8本地服务级演练层
- P2-1 / P2-2 / P2-3 / P2-4 / P2-5 / P2-6
- X-02 / X-03 / X-04 / X-05 / X-06 / X-08
已转入 T12 / 上线前收口:
- P1-3 真实支付回调校验过弱(需要真实商户 key / 公网 notify_url / 线上 acceptance
- P1-8 备份恢复的异机 / 异地 / 生产接入部分
- X-04 合规基线的正式法务版本、前台/客服自助工单流程
- X-05 密钥托管与异机恢复演练的生产接入
- X-06 dev-verify 已完成,但仍有与部署环境相关的 acceptance 工作
未完成且已并入 T12 后续主线:
- 真实支付 acceptance
- 真正告警推送集成与生产级监控
- 更强的多文件上传策略与更细粒度字段校验
- 用户端 Web 自助支付完整闭环
因此:本计划中的“旧整改任务”并非全部处于 completed 状态;它们已经被拆成“已完成”与“转入 T12 后续”两类。
---
## 3. 最短整改路径(按风险收益排序)
### 第一阶段:先修“真相一致性”
目标:
- 保证订单/支付/退款/交付的业务真相不分裂
进度:
- ✅ P1-1 支付回调双写裂缝已修复Payment 与 Order 状态推进收敛到同一事务)
- ✅ P1-5 退款域模型闭环已修复payment.status 一步收敛到 `refunded`,并把订单推进到 refunded 终态;幂等请求会自愈)
- ✅ P1-2 删除/匿名化已覆盖 orders 主表 + payments.callback_payload + order_intakes.payload_json
- ✅ P1-7 验证链口径统一dev-verify / CI 统一调用 scripts/check_coverage_gate.py并以 80% / 100% 与 codecov 对齐
- ✅ P2-1 公共下单孤儿订单已验证有完整回归测试覆盖admin/tests/test_web_public.py 9 passed
- ✅ P2-3 delivery sent 语义修正dispatcher 现在区分 validated / deliveredstation 只到 validatedemail 才到 delivered
- ✅ P1-4 webhook server DB 连接污染:已为 per-key 连接缓存新增显式回归测试test_webhook_server_db_scoping.py 4 passed锁定“每 db_path 独立 + 释放不影响其他路径 + 线程安全 + release_all 真正关闭所有连接”四项不变量
- ✅ P1-6 分享 allowlistedit / admin 模式已强制走显式 frozenset(\_EDIT_VISIBLE_FIELDS),不再是 None 透传新增敏感字段不会自动外泄data/share/permission.py + data/share/tests/test_permission.py 已验证)
- ✅ P1-8 备份恢复服务级演练backup_verify.sh 改为优先调用 venv python新增 tests/test_backup_restore_service_level.py 1 passed 锁定“健康/portal 200 + 真实落单 + 实际闭环”
- ✅ P2-2 channel_sync 单一 DAO 真相:已新增 data/channel_sync/tests/test_single_dao_truth.py 4 passed 锁定 4 项不变量
- ✅ P2-6 历史快照头注补齐:已新增 tests/test_historical_snapshot_headers.py 4 passed 锁定历史快照+真相源跳转
- ✅ X-06 本地一键验证脚本scripts/dev-verify.sh 新增 --skip-install / --skip-pre-existing flagtests/test_dev_verify_entrypoint.py 3 passed 锁定入口可调
- ✅ X-02 支付域设计docs/PAYMENT_DOMAIN_DESIGN.md 已扩展至含不变量/字段/流程/数据流表
- ✅ X-03 Delivery 交付服务设计docs/DELIVERY_SERVICE_DESIGN.md 已反映 P2-3 修复后的 validated / delivered 生命周期
- ✅ X-04 合规基线文档docs/LEGAL_PRIVACY_BASELINE.md 已存在并通过实质性校验
- ✅ X-05 备份恢复与密钥托管方案docs/BACKUP_AND_RECOVERY_PLAN.md 已扩展至含不变量/流程/恢复演练路径
- ✅ X-08 crowd_db 数据完整度等级化docs/CROWD_DB_DATA_QUALITY.md 新建4 档完整性 + confidence/source 一致性不变量
顺序:
1. P2-1 公共下单孤儿订单
2. P2-3 delivery `sent` 语义修正
### 第二阶段:再修“合规与安全边界”
目标:
- 减少真实合规风险和公开面风险
顺序: 5. P1-2 删除/匿名化不完整 6. P1-3 支付回调校验过弱 7. P1-6 分享 edit/admin 全透传风险 8. P2-4 portal token / JWT secret 分离 9. P2-5 payment webhook secret fail-closed
### 第三阶段:最后修“验证链可信度”
目标:
- 保证后续再 review 不会因门禁口径不一致而反复漂移
顺序: 10. P1-7 覆盖率/CI/codecov/dev-verify 统一 11. P1-8 备份恢复服务级演练 12. P2-2 channel_sync 单一 DAO 真相 13. P2-14 历史快照统一头注
---
## 4. 详细整改任务板(历史执行快照,已不再作为当前状态真相)
> ⚠️ **重要:以下卡片保留的是 2026-06-14 制定整改时的任务模板,绝大多数条目仍显示 `状态: pending`,但实际状态已在 §2.1 中归一为"已完成 / 已转入 T12 / 并入 T12"三类。本节仅作历史记录,不应再被引用为"当前未完成项"。**
> 当前状态请以 `docs/ACTIVE_EXECUTION_BOARD_2026-06-17.md` 与 `docs/CURRENT_STATE.md` §5-§6 为准。
> 当前状态请以上一节“2026-06-15 状态归一”为准;不要再用这里的旧状态判断项目是否全部完成。
### P1-1 支付回调双写裂缝
严重度: P1
Owner: engineer
状态: pending
问题:
- `PaymentService.handle_webhook()` 先提交 payment再在另一上下文推进 order
- 一旦第二步失败,会留下 `payments.status=paid``orders.status!=paid`
目标:
- 支付成功与订单推进必须成为单一业务事务,至少形成可补偿的强一致流程
交付物:
- `docs/plans/P1-1-payment-consistency.md`
- 代码修复:`data/payments/service.py`, `data/payments/dao.py`, `data/orders/dao.py`
- 新测试:`data/payments/tests/test_webhook_consistency.py`
完成标准:
- 回调处理不再跨两个独立 commit 真相源
- 如果 order 推进失败payment 不能被误判为最终 paid
- 或者必须记录明确补偿状态(如 `payment_pending_reconcile`
验证:
- 构造 payment 成功 / order 失败场景,验证系统不会留下分裂状态
---
### P1-2 删除/匿名化不完整
严重度: P1
Owner: engineer + PM
状态: pending
问题:
- 订单主表去标识化不等于完整匿名化
- `order_intakes.payload_json` / `payments.callback_payload` / 报告文件未同步清理
目标:
- 删除/匿名化逻辑与文档承诺一致
交付物:
- `docs/plans/P1-2-deletion-anonymization-closure.md`
- 代码修复:`data/orders/deletion_service.py`, `data/orders/intake_store.py`, `data/payments/dao.py`
- 文档修订:`docs/DATA_RETENTION_AND_DELETION.md`
完成标准:
- 主表、资料提交、支付回调、报告文件、通知痕迹都纳入处理策略
- 文档明确“删除/匿名化”的真实语义,不再误报
验证:
- 构造一条完整订单,执行删除/匿名化后核查所有关联存储
---
### P1-3 支付回调校验过弱
严重度: P1
Owner: engineer
状态: pending
问题:
- 当前只校验签名 + 金额,不校验 `app_id` / 商户标识 / 允许状态边界等
目标:
- 回调必须达到真实业务校验标准,而不是“签名合法即接受”
交付物:
- `docs/plans/P1-3-payment-webhook-hardening.md`
- 代码修复:`admin/routes/web_public.py`, `data/payments/service.py`, `data/payments/providers/alipay.py`
- 新测试:`data/payments/tests/test_webhook_hardening.py`
完成标准:
- app_id / merchant / notify_id / 状态白名单 / 金额 / payment_id 全校验
- 非法字段或状态必须拒绝
验证:
- 伪造 app_id、错商户、错状态、重复 notify 场景测试全通过
---
### P1-4 webhook server 全局 DB 连接污染
严重度: P1
Owner: engineer
状态: pending
问题:
- `_DB_CONN` 模块级单例不区分 `db_path`
- 不同实例可能写到同一个库
目标:
- 连接必须按 `db_path` 隔离,或改为每 server instance 自持连接
交付物:
- `docs/plans/P1-4-webhook-db-scope.md`
- 代码修复:`data/channel_sync/webhook_server.py`
- 新测试:多 db_path 场景测试
完成标准:
- 不同 `db_path` 的 server 互不污染
验证:
- 启动两个不同库实例,分别写入并验证库隔离
---
### P1-5 退款域模型未闭环
严重度: P1
Owner: engineer
状态: pending
问题:
- payment 到 `refund_pending`,但 order 未形成 `refunded` 统一主状态
目标:
- 退款真相源统一,订单域与支付域不再分裂
交付物:
- `docs/plans/P1-5-refund-state-closure.md`
- 代码修复:`data/payments/service.py`, `data/orders/state_machine.py`, `admin/routes/web_public.py`
完成标准:
- 退款成功时,订单主状态与支付状态一致可追踪
验证:
- portal / 订单详情 / 统计使用同一退款真相
---
### P1-6 分享 edit/admin 默认透传风险
严重度: P1
Owner: engineer
状态: pending
问题:
- `visible_fields=None` 导致未来新增敏感字段可能自动外泄
目标:
- edit/admin 也必须改为 allowlist而不是 denylist
交付物:
- `docs/plans/P1-6-share-field-allowlist.md`
- 代码修复:`data/share/permission.py`
- 新测试:新增敏感字段不应自动出现在公开 payload
完成标准:
- 所有权限模式都基于显式字段白名单
验证:
- 向 payload 加入新敏感字段,分享页不自动透出
---
### P1-7 验证链口径统一
严重度: P1
Owner: ops + engineer
状态: pending
问题:
- CI / dev-verify / codecov / gate 脚本口径不一致
目标:
- 建立唯一质量门禁口径
交付物:
- `docs/plans/P1-7-gate-unification.md`
- 修复文件:`.github/workflows/ci.yml`, `scripts/dev-verify.sh`, `scripts/check_coverage_gate.py`, `codecov.yml`
完成标准:
- CI、本地、codecov、脚本给出一致结论
- README 中有唯一执行入口
验证:
- 干净环境执行 CI 同款命令,与 dev-verify 结果一致
---
### P1-8 备份恢复演练不足
严重度: P1
Owner: ops
状态: pending
问题:
- 当前只能证明“文件可复制”,不能证明“恢复后系统可用”
目标:
- 从文件级备份升级到服务级恢复演练
交付物:
- `docs/plans/P1-8-backup-restore-drill.md`
- 脚本修订:`scripts/backup_verify.sh`
- 恢复演练记录文档
完成标准:
- 恢复出的 DB + 文件能重新支撑 portal / 订单 / 报告最小服务可用
验证:
- 临时目录恢复后跑最小服务 smoke test
---
## 5. P2 改进项(第二批处理)
### P2-1 公共下单孤儿订单
- 目标:支付初始化失败时不遗留无补偿订单
### P2-2 channel_sync 单一 DAO 真相
- 目标:移除旧 `dao_extension` 直连路径,统一到 OrdersDAO
### P2-3 delivery `sent` 语义过度乐观
- 目标:区分 `validated` / `queued` / `sent` / `delivered`
### P2-4 portal token 与后台 JWT secret 分离
- 目标:最小权限边界,独立轮换
### P2-5 payment webhook secret fail-closed
- 目标:生产环境禁止默认开发 secret 启动
### P2-6 历史快照头注补齐
- 目标:所有旧报告都显式声明“历史快照 + 当前真相源跳转”
---
## 6. 推荐执行顺序
第一批(必须先做)
1. P1-1 支付回调双写裂缝
2. P1-5 退款域模型未闭环
3. P1-2 删除/匿名化不完整
4. P1-7 验证链口径统一
第二批安全与边界5. P1-3 支付回调校验过弱 6. P1-4 webhook DB 连接污染 7. P1-6 分享 allowlist 8. P1-8 备份恢复演练
第三批技术债9. P2-1 ~ P2-6
---
## 7. 当前最准确的执行口径
> 当前项目已完成 v2.1 的后台运营与 AI 审核增强闭环,但要避免再次虚假完成,后续整改必须只围绕本清单中的真实未解决问题推进;其中最优先的是支付真相一致性、退款闭环、删除/匿名化闭环、以及验证链口径统一。