Files
Neo-ZQYY/docs/_overview/wave1-findings/F1-5b-tasks.md
Neo af02446740 feat(ai): F1-5b Wave A 中段 沙箱业务日全栈架构主体收口 (W1)
完成 F1-5b 任务:
- T1 RuntimeContext unit 测试基础(36 case PASS,本地不入仓走 .gitignore:71)
- A1 admin_service.py 4 处 CURRENT_DATE → business_date 改造
  - _get_range_stats / _get_7d_trend / _get_app_distribution
  - 上下界双全(下界 - 6 days + 上界 < + 1 day,Step 4b 暴露原 PR
    上界缺失,sandbox=4-20 时 trend_7d 漏 4-21~5-01 数据 → 修补)
  - 全局聚合 list_trigger_jobs / get_budget 保留 CURRENT_DATE
    (Neo D 决策选 A: 多 site 时全局无单一业务日)
- A2 fdw_queries:113 / 2552 异常分支兜底 + 三层 fallback + warning
  - conn=None 也尝试 get_runtime_context(自开 conn)
  - RuntimeContext 不可用降级真实 today + logger.warning
- A3 _fdw_context docstring 显式登记唯一 ETL 入口架构契约
  (D2 完整且统一: 所有 ETL 视图查询通过 _fdw_context 自动 SET 三个
   GUC: site_id / business_date / runtime_mode)
- 防御 hook post_edit_business_date_check.py
  Wave 2 后续 PR 引回 CURRENT_DATE / date.today() 即提醒

双口径验证(§3.1 4a + 4b):
- 4a live: dashboard trend_7d 2 条 4-30~5-01 (真实今天)
- 4b sandbox=2026-04-20: trend_7d 1 条仅 4-20 (业务日上界生效硬证据)
- pytest test_runtime_context 36/36 全过

未完(下一批 Wave A): T2 integration / UI-1/2/4 / MP-3/5 / MP-1 / BE-1
F1-5b-tasks.md 新增 + audit 记录已就位

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 15:01:51 +08:00

493 lines
25 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.
# F1-5b 任务拆分(规范化稳健版)
> 日期:2026-05-05
> 上游:F1-5a 主体(commit `421e193`)+ 走查 bug fix(`1baa212` `a045625`)已完成
> 走查报告:[`docs/audit/changes/2026-05-05__wave1_f1_5a_backend_walkthrough.md`](../../audit/changes/2026-05-05__wave1_f1_5a_backend_walkthrough.md)
> 决策卡:[`F1-5-impl-decisions.md`](F1-5-impl-decisions.md)(D1-D6 已 Neo 拍板)
> 用法:本文档为 F1-5b 阶段唯一权威任务清单。每项任务按 §3 标准 5 步流程实施,每个 Wave 末做 checkpoint。
---
## 〇、与 v1 版的关键调整(规范化)
| 调整 | 原版 | 调整版 |
|---|---|---|
| 实施流程 | 各任务自由实施 | **统一 5 步**:调研 → TDD → 实施 → 验证 → 审计(§3) |
| **Step 4 验证(关键稳健性)** | **单口径 mcp 走查** | **双口径**:4a live 主验 + 4b sandbox 二验,防沙箱遗漏(§3.1 + §3.3 必做清单) |
| Commit 粒度 | 2 个 commit(混合后端/前端/测试) | **4-6 个 commit**,每个逻辑独立可 review/revert(§4.3) |
| 防御机制 | 仅 grep 验证 | **A1 完成立即加 PreToolUse hook 防回归**(§5.1) |
| Wave 节奏 | A 收尾直接进 B | **Wave A 末 mid-wave checkpoint**,Neo 复审后启动 B(§4.2) |
| 进度跟踪 | 无 | **§6 进度表**,每项含 status / commit / audit / 4a 4b 完成状态 |
| Neo 决策点 | 末尾"反馈区"空白 | **§7 结构化决策表**(D7-D10 4 项,Neo 拍板后启动) |
| 失败兜底 | 仅回退路径 | **§8 失败决策矩阵**:严重度阈值 + 升级路径 |
| 测试守护 | 测试整体在 Wave A | **TDD 红绿重构嵌入每项 A 任务**,T1 case 与 A 任务同步演进 |
---
## 一、阶段总览
### 1.1 阶段目标(不变)
把 F1-5a "沙箱 batch-run 接入 runtime_context"上半场未收口的工作做完:
1. **架构主体收口**:F1-5a 计划但未做的 admin_service `CURRENT_DATE``business_date`、fdw_queries 异常分支兜底、apply_runtime_session_vars 全 DB 入口统一注入(D2 决策"完整且统一")
2. **F1-5a 走查 follow-up**:12 项闭环
3. **测试 3 套**:test_runtime_context.py / test_admin_ai_batch_runtime.py / test_dispatcher_runtime.py
4. **文档同步**:P20 SPEC §6/§10/§11/§15
### 1.2 验收标准(不变)
| # | 标准 | 验证手段 |
|---|---|---|
| AC1 | sandbox=2026-04-20 时,admin-web 全局可见沙箱状态 | Playwright 多页面截图 |
| AC2 | sandbox=2026-04-20 时,小程序所有看板 + 子页 lastService / 月份切换均严格 ≤ 业务日 | weixin-devtools-mcp + DB 累计核对 |
| AC3 | admin_service.py 6 处 CURRENT_DATE 全部走 business_date | pytest integration |
| AC4 | apply_runtime_session_vars 在选定"统一注入点"全部生效,grep 0 处遗漏 | grep + integration test |
| AC5 | 3 套测试本地全绿,覆盖 ≥ 80% RuntimeContext 公共 API | pytest --cov |
| AC6 | P20 SPEC §6/§10/§11/§15 文字与现状一致;§10 矩阵 12 项全 ✓ | 逐项 reviewer 核对 |
| AC7 | board-finance 储值充值 132000 vs 66000 字段差异有结论 | DB 复算脚本入仓 |
| AC8 | task-list 403 manager 权限链路矛盾找到根因并修复 | curl + DB 双源核对 |
| **AC9 新增** | **A1 落地后 PreToolUse hook 阻止 PR 引回 CURRENT_DATE / date.today()** | **手动测试 hook + 审计** |
### 1.3 工作量估算(微调)
| 组 | 任务数 | 工作量 | 折算人天 |
|---|---|---|---|
| 架构主体收口 | 6 | 1×L + 2×M + 3×S | 1.5 |
| 走查 follow-up | 12 | 1×L + 4×M + 5×S + 2×XS | 2.0 |
| 测试 | 3 | 2×M + 1×L | 1.0 |
| 文档同步 | 4 | 4×S | 0.5 |
| **防御 hook(新增)** | **1** | **S** | **0.2** |
| **mid-wave checkpoint(新增)** | **1** | **M** | **0.3** |
| **合计** | **27** | — | **5.5 天** |
---
## 二、关键背景与判断(同 v1)
### 2.1 D2"完整且统一"解读 = (a) 不 (b)
**(a) 在所有 DB 入口注入 GUC** ✅ 本次必做(F1-5a 仅 run_log_service 试点,不统一)
**(b) zqyy_app 新建 RLS 视图层** ❌ 不做(zqyy_app `app` 实为 fdw_etl 外表,业务读写 `biz.*` 走应用层 A 方案已覆盖,新建会形成两套保护违反"单一权威源")
后续 Wave 2/3 业务模块新增直查 `biz.*` 的 SQL,沿用应用层 A 方案,**通过 PreToolUse hook 保障(§5.1)**。
### 2.2 月度聚合表 MP-2 推荐 D 双口径
`dws_assistant_salary_calc` 月度粒度含罚分扣减,daily 不可还原。
**推荐方案 D**:API 同时返回 `current_month_partial`(daily 累计到 business_date)+ `current_month_settled`(monthly 全量),前端默认显 partial 加"实时累计(不含扣减)"标。约 4h 改造。
### 2.3 BE-1 task-list 403 首要假设
**`require_permission` factory 取 site_id 不一致**(JWT vs path/query/body)。F1-5a 走查临时插桩已删,需重做。
### 2.4 BE-2 db-health UnicodeDecodeError
`_get_etl_connection` 强制 `SET client_encoding TO 'UTF8'` + db-health 端点 try/except 降级。属偶发不阻塞,P2。
---
## 三、实施流程标准化(每项任务必走 5 步)
### 3.1 五步流程(Step 4 双口径)
每项任务实施时必须按以下 5 步,**Step 4 验证拆 live + sandbox 双口径**(关键稳健性补强):
```text
Step 1: 调研(强制,符合 CLAUDE.md "逻辑改动前置调研")
- 用 Explore agent 找现有相关代码
- 输出"改动前上下文摘要":模块职责 / 历史变更 / 影响范围 / 风险点
- Neo 确认后才进 Step 2
Step 2: TDD 红(测试先行)
- 写 test case(若任务在测试组,本身就是 case;若在收口/follow-up,补对应 test case)
- 运行 test → 红(测试失败,因为代码还未改)
Step 3: 实施(写代码)
- 改代码,最小改动原则
- 运行 test → 绿
- 重构(如有)
Step 4: 验证(双口径)
─ Step 4a: live 模式主验证(默认起点)
· 后端改动: curl + Python 脚本 DB 核对(主路径功能正确)
· admin-web 改动: Playwright 截图核对
· 小程序改动: weixin-devtools-mcp 实地 + DB 核对
· 多端: 逐端 live 验证
─ Step 4b: sandbox 二次验证(强制,除非任务标"sandbox 无关")
· 切 sandbox=2026-04-20(主走查日,有数据)
· 重复 4a 同样的验证,确认 sandbox 下:
(i) 业务日上界裁剪正确
(ii) UI 沙箱状态透出(若涉及)
(iii) 业务时钟生效(若涉及)
· 若 4b 发现 4a 未暴露的 bug → 回 Step 3 修复 → 重做 4a + 4b
· 验证完成 → 切回 live(fixture try/finally 保证)
─ 4b 跳过条件: 任务在 Step 1 调研时明确标"sandbox 无关",
如纯文档同步 / 与时间无关的字段映射 / hook 注册等
Step 5: 审计
- 写"改动后摘要":diff / 风险点 / 未覆盖路径 / **4a 与 4b 验证结果**
- 审计记录入 docs/audit/changes/2026-05-XX__wave1_f1_5b_<slug>.md
```
### 3.2 跳过条件(罕见)
| 步骤 | 可跳条件 |
|---|---|
| Step 1 调研 | 任务标"XS 工作量"+ 文档已显式列改动行号 |
| Step 2 TDD | 文档/SPEC 类任务(组 4) |
| Step 3 实施 | 仅文档/SPEC 类任务 |
| Step 4a live 验证 | XS 文档类任务,但仍需 grep 验证 |
| **Step 4b sandbox 二次验证** | **任务在 Step 1 调研时明确标"sandbox 无关"**(纯文档/无时间字段/hook 等) |
| Step 5 审计 | **无可跳条件**,所有改动必入审计 |
### 3.3 Step 4b 必做任务清单(预判)
| 任务 | sandbox 必验? | 验证关注点 |
|---|---|---|
| A1 admin_service 6 处 CURRENT_DATE | **是** | dashboard 区间显示业务月而非真实今天 |
| A2 fdw_queries 异常分支兜底 | **是** | conn=None 路径降级 RuntimeContext.business_date |
| A3 apply_runtime_session_vars 统一注入 | **是** | EXPLAIN 视图 WHERE 含 ≤ business_date |
| A4 zqyy_app 永不做登记 | 否(纯文档) | — |
| A5 batch_id 命名规则 | 否(纯文档) | — |
| A6 db-health UnicodeDecodeError | 否(与 sandbox 无关) | — |
| Hook §5.1 防回归 | 否(hook 触发只与代码改动相关) | — |
| UI-1/2/4 admin-web runtime 透出 | **是** | sandbox 下徽章/列/Drawer 真显沙箱 |
| UI-3 AIDashboard sandbox 提示+分组 | **是** | sandbox 下提示条显示 + 分组数据正确 |
| UI-5 AITriggerJobs runtime 列 | **是** | sandbox 下列正确显示 |
| MP-1 board-finance 储值充值复核 | **是** | sandbox 月数据 vs DB 累计核对 |
| MP-2 board-coach 月度面板双口径 | **是** | sandbox 月 partial vs settled 字段 |
| MP-3 customer-detail lastService 裁剪 | **是** | sandbox 下 lastService 不超业务日 |
| MP-4 coach-detail data.coachId 修复 | 否(预存前端 bug,与 sandbox 无关) | — |
| MP-5 coach-service-records 接 runtime-clock | **是** | sandbox 下默认月 = 业务月 |
| BE-1 task-list 403 manager 权限 | 否(权限链路与 sandbox 无关) | — |
| BE-3 ai_run_logs runtime 回归测试 | **是**(测试本身覆盖 sandbox 路径) | runtime_mode='sandbox' 字段写入 |
| T1 unit RuntimeContext | 否(测试用 mock,不切真实 sandbox) | — |
| T2 integration ctx_snapshot | **是**(测试本身就是 sandbox/live 切换) | ctx_snapshot 不漂移 |
| T3 unit dispatcher | 否(测试用 mock) | — |
| D1-D4 文档 | 否(纯文档) | — |
---
## 四、任务执行顺序
### 4.1 DAG 依赖图(同 v1)
```text
T1-pre (RuntimeContext API test cases) ─┐
A1 (admin_service CURRENT_DATE) ────────┼─> A3 (GUC 统一注入) ──┐
A2 (fdw_queries 异常分支) ──────────────┘ │
├─> T2 (integration)
T1 (其他 unit) ────────────────────────────────────────────────┤
└─> T3 (dispatcher unit) ──> A4
A1 完成 ──> Hook (§5.1 防回归) ──> Wave A 内继续
UI-1 ──> UI-2 / UI-3 (依赖 A1) / UI-4 (独立) / UI-5 (独立)
MP-1 (独立) / MP-2 (依赖 A2) / MP-3 (独立) / MP-4 (独立, 预存 bug) / MP-5 (依赖已修)
BE-1 (独立) / BE-2 (独立) / BE-3 (依赖 T2)
D1 ──> D2 ──> D3 ──> D4 (本阶段全部完成后)
```
### 4.2 Wave 节奏(强化 mid-wave checkpoint)
#### Wave F1-5b-A(P0 核心,2 天)
**目标**:架构主体收口 + 沙箱硬要求 + 关键回归测试就位 + 防御 hook 落地
| 顺序 | 任务 | 类型 | 工作量 | 依赖 | Commit 归属 |
|---|---|---|---|---|---|
| 1 | T1 unit RuntimeContext 公共 API | 测试 | M | 无 | C1 |
| 2 | A1 admin_service.py 6 处 CURRENT_DATE | 收口 | M | T1 部分 case | C2 |
| 3 | **§5.1 PreToolUse hook 防回归** | **新增** | **S** | A1 | C2 |
| 4 | A2 fdw_queries 异常分支兜底 | 收口 | S | T1 | C2 |
| 5 | A3 apply_runtime_session_vars 统一注入 | 收口 | L | A1+A2 | C2 |
| 6 | T2 integration estimate→confirm ctx_snapshot 不漂移 | 测试 | L | A1+A3 | C2 |
| 7 | UI-1 + UI-2 AIRunLogs runtime 列+Drawer | follow-up | S+XS | 无 | C3 |
| 8 | UI-4 全局 sandbox 徽章 | follow-up | M | 无 | C3 |
| 9 | MP-3 customer-detail lastService 裁剪 | follow-up | M | 无 | C4 |
| 10 | MP-5 coach-service-records 接入 runtime-clock | follow-up | M | 已修 | C4 |
| 11 | MP-1 board-finance 储值充值复核 | follow-up | M | 无 | C2 |
| 12 | BE-1 task-list 403 详查 | follow-up | M | 无 | C2 |
**Wave A mid-wave checkpoint(强制)**:
```text
1. 切 sandbox=2026-04-20
2. 跑全套 P0 走查(Playwright 5 页 admin-web + weixin-devtools-mcp 7 页小程序)
3. 写 mid-wave 走查报告 docs/audit/changes/2026-05-XX__wave1_f1_5b_wave_a_checkpoint.md
4. Neo 复审 → 决定是否进 Wave B / 调整 Wave B 优先级 / 修复发现的新 bug
5. 切回 live
```
#### Wave F1-5b-B(P1/P2 增强 + 文档,3 天)
**目标**:剩余 follow-up + 测试补全 + SPEC 同步
| 顺序 | 任务 | 类型 | 工作量 | 依赖 | Commit 归属 |
|---|---|---|---|---|---|
| 13 | UI-3 AIDashboard sandbox 提示条 + runtime 分组 | follow-up | M | A1 | C3 |
| 14 | UI-5 AITriggerJobs runtime 列 | follow-up | XS | 无 | C3 |
| 15 | MP-2 board-coach 月度面板双口径 | follow-up | L | A2 | C4 |
| 16 | MP-4 coach-detail data.coachId 修复 | follow-up | S | 无 | C4 |
| 17 | T3 unit dispatcher runtime | 测试 | M | A3 | C5 |
| 18 | BE-3 ai_run_logs runtime 写入回归 | follow-up | S | T2 | C5 |
| 19 | A6 db-health UnicodeDecodeError | 收口 | M | 无 | C5 |
| 20 | A4 zqyy_app 永不做登记 | 收口 | XS | A3 | C6 |
| 21 | A5 batch_id 命名规则文档化 | 收口 | XS | 无 | C6 |
| 22 | D1 P20 SPEC §6 | 文档 | S | A3+A4 | C6 |
| 23 | D2 P20 SPEC §10 | 文档 | S | 全部 follow-up | C6 |
| 24 | D3 P20 SPEC §11 | 文档 | XS | 全部任务 | C6 |
| 25 | D4 P20 SPEC §15 + audit dashboard | 文档 | S | C5 commit 后 | C6 |
### 4.3 Commit 策略(细化为 4-6 个独立逻辑单元)
| Commit | 主题 | 内容 | 验证 |
|---|---|---|---|
| **C1** `feat(test): F1-5b-A1 RuntimeContext unit 测试基础` | 测试基础 | T1 部分 case(为 A 任务红绿) | pytest 红(预期) |
| **C2** `fix(backend): F1-5b-A 沙箱主体收口 + 测试 + 防御 hook` | 后端架构 | A1+A2+A3 + 防御 hook + T2 + MP-1 + BE-1 | pytest 绿 + curl + Playwright + MCP |
| **C3** `feat(admin-web): F1-5b UI sandbox runtime 透出` | admin-web | UI-1/2/4 (Wave A) + UI-3/5 (Wave B) | Playwright 截图核对 |
| **C4** `fix(miniprogram): F1-5b 小程序 sandbox 上界 + 时钟接入` | 小程序 | MP-3/5 (Wave A) + MP-2/4 (Wave B) | weixin-devtools-mcp + DB 累计 |
| **C5** `test+fix(backend): F1-5b 测试增量 + db-health 编码 + retry 回归` | 测试 + 杂项 | T3 + BE-3 + A6 | pytest 全绿 |
| **C6** `docs(spec): F1-5b P20 SPEC §6/§10/§11/§15 同步 + audit` | 文档收尾 | A4+A5 + D1-D4 + audit dashboard 刷新 | grep 一致性 |
每个 commit 跑一次 `/audit` → 生成 `docs/audit/changes/2026-05-XX__wave1_f1_5b_<slug>.md`
C2 是"原 Commit 1"的精炼,C5 是"原 Commit 2 后端部分",C6 是"原 Commit 2 文档部分" — 拆细后每个 commit 独立可 review,失败可单独 revert 不影响其他。
---
## 五、防御机制(本次新增)
### 5.1 PreToolUse hook 防回归(A1 完成立即落地)
A1 完成后立即加 hook,防 PR 引回 `CURRENT_DATE``date.today()`:
**位置**:`.claude/hooks/pre_check_business_date_regression.py`(参照 F2-1B `post_edit_*_reminder.py` 同类机制)
**触发**:Edit/Write 命中 `apps/backend/app/services/**/*.py`
**逻辑**:
1. 读取目标文件 new_content
2. grep `CURRENT_DATE` / `date\.today\(\)`(排除 fallback 注释行)
3. 命中则提示:"检测到 CURRENT_DATE / date.today() 直接调用,F1-5b 决策要求走 RuntimeContext.business_date,如确需绕过请加 `# RUNTIME_CTX_BYPASS: <理由>` 注释"
4. 不强阻断(soft warning),允许 fallback 路径
**配套**:`.claude/settings.json` 加 hook 注册;CLAUDE.md 加"业务日上界规范"章节,引用本 hook。
**工作量**:S(60min)
**优先级**:P0(防回归)
### 5.2 Lint 加 grep 校验
每个 commit 之前自动跑:
```bash
# 不应出现:
grep -rn "CURRENT_DATE\|date\.today\(\)" apps/backend/app/services/ | grep -v "# RUNTIME_CTX_BYPASS"
# 期望:0 处(或仅 RUNTIME_CTX_BYPASS 注释行)
```
集成到 `scripts/audit/prescan.py`,作为 audit 前置检查。
### 5.3 测试库环境守护
每项 Step 4 验证前后,**强制切回 live**:
```python
# 通用 fixture(F1-5b-T2 复用)
@pytest.fixture(autouse=True)
def reset_runtime_context_to_live():
yield
# try/finally 保证测试失败也切回 live
requests.patch(BASE+"/api/admin/runtime-context",
json={"site_id": SITE, "mode": "live", "sandbox_date": None,
"reason": "F1-5b 测试 fixture autorestore"},
headers=auth_header())
```
---
## 六、进度跟踪表
每项任务完成后填写。Wave A 完成后 mid-wave checkpoint 复审本表。
**4a/4b 列说明**:`-` 任务无需 / `▢` 待做 / `✓` 通过 / `✗` 发现问题需回 Step 3。任一为 `✗` 该任务不算完成。
| ID | 任务 | 状态 | 完成时间 | Commit | 审计 | 4a live | 4b sandbox | 备注 |
|---|---|---|---|---|---|---|---|---|
| T1 | RuntimeContext unit 测试 | 待开始 | — | C1 | — | ▢ | - | mock 不切真实 sandbox |
| A1 | admin_service CURRENT_DATE → business_date | 待开始 | — | C2 | — | ▢ | ▢ | dashboard 显示业务月 |
| **Hook** | PreToolUse 防回归 hook | 待开始 | — | C2 | — | ▢ | - | hook 与 sandbox 无关 |
| A2 | fdw_queries 异常分支兜底 | 待开始 | — | C2 | — | ▢ | ▢ | conn=None 路径 |
| A3 | apply_runtime_session_vars 统一注入 | 待开始 | — | C2 | — | ▢ | ▢ | EXPLAIN GUC 生效 |
| T2 | integration estimate→confirm 不漂移 | 待开始 | — | C2 | — | ▢ | ▢ | 测试本身就是双模式 |
| UI-1 | AIRunLogs 列表 runtime 列 | 待开始 | — | C3 | — | ▢ | ▢ | sandbox 行 Tag 显示 |
| UI-2 | AIRunLogs 详情 Drawer | 待开始 | — | C3 | — | ▢ | ▢ | Drawer runtime 字段 |
| UI-4 | 全局 sandbox 徽章 | 待开始 | — | C3 | — | ▢ | ▢ | 顶栏徽章颜色切换 |
| MP-3 | customer-detail lastService 裁剪 | 待开始 | — | C4 | — | ▢ | ▢ | sandbox 下不显未来 |
| MP-5 | coach-service-records 接入 runtime-clock | 待开始 | — | C4 | — | ▢ | ▢ | 默认月=业务月 |
| MP-1 | board-finance 储值充值复核 | 待开始 | — | C2 | — | ▢ | ▢ | DB 累计 vs 前端 |
| BE-1 | task-list 403 manager 权限详查 | 待开始 | — | C2 | — | ▢ | - | 权限与 sandbox 无关 |
| — | **Wave A mid-wave checkpoint** | — | — | — | — | — | — | Neo 复审 |
| UI-3 | AIDashboard sandbox 提示+分组 | 待开始 | — | C3 | — | ▢ | ▢ | 双线分组显示 |
| UI-5 | AITriggerJobs runtime 列 | 待开始 | — | C3 | — | ▢ | ▢ | 列正确显示 |
| MP-2 | board-coach 月度面板双口径 | 待开始 | — | C4 | — | ▢ | ▢ | partial vs settled |
| MP-4 | coach-detail data.coachId 修复 | 待开始 | — | C4 | — | ▢ | - | 预存 bug 与 sandbox 无关 |
| T3 | dispatcher unit | 待开始 | — | C5 | — | ▢ | - | mock |
| BE-3 | ai_run_logs runtime 回归 | 待开始 | — | C5 | — | ▢ | ▢ | runtime 字段写入 |
| A6 | db-health UnicodeDecodeError | 待开始 | — | C5 | — | ▢ | - | 与 sandbox 无关 |
| A4 | zqyy_app RLS 永不做登记 | 待开始 | — | C6 | — | ▢ | - | 纯文档 |
| A5 | batch_id 命名规则文档化 | 待开始 | — | C6 | — | ▢ | - | 纯文档 |
| D1 | SPEC §6 GUC 路线 | 待开始 | — | C6 | — | ▢ | - | 纯文档 |
| D2 | SPEC §10 矩阵 | 待开始 | — | C6 | — | ▢ | - | 纯文档 |
| D3 | SPEC §11 已知遗漏 | 待开始 | — | C6 | — | ▢ | - | 纯文档 |
| D4 | SPEC §15 + audit dashboard | 待开始 | — | C6 | — | ▢ | - | 纯文档 |
---
## 七、Neo 决策点(D7-D10)
启动 Wave A 前,Neo 拍板以下 4 项决策。同 D1-D6 模式,在每项下用 *斜体* 写反馈。
### D7 Commit 拆分粒度
v1 推荐 2 个 commit。规范化版改 4-6 个独立逻辑单元(C1-C6)。
| 选项 | 优势 | 劣势 |
|---|---|---|
| **a 4-6 个独立 commit(规范版推荐)** | 每个 commit 可独立 review/revert / 历史清晰 | commit 数量多 |
| b 沿用 v1 的 2 个 commit | 数量少 | 一个 commit 含混合主题 |
| c 折中 3 个 commit(测试 / 后端架构 / 前端+文档) | 平衡 | 仍混合后端架构 + UI 改动 |
**Claude 推荐 a**
**Neo 反馈**:
*(待填)*
---
### D8 PreToolUse hook 防回归是否落地
§5.1 描述。
| 选项 | 评估 |
|---|---|
| **a 落地(规范版推荐)** | A1 完成立即加 hook,**长期防御**未来 PR 引回 CURRENT_DATE |
| b 不落地 | 仅靠 grep 在 commit 前手动检查 |
**Claude 推荐 a**。F2-1B 已验证 hook 防御机制有效,本次类似场景。
**Neo 反馈**:
*(待填)*
---
### D9 Wave A mid-wave checkpoint 是否做
§4.2 Wave A 末加 mid-wave checkpoint(切 sandbox + 全套 P0 走查 + Neo 复审 + 切回 live)。
| 选项 | 评估 |
|---|---|
| **a 做(规范版推荐)** | Wave B 启动前确认 Wave A 闭环,降低 B 阶段集成 bug 风险 |
| b 不做 | A B 连续做,集成失败时回退面更大 |
**Claude 推荐 a**。F1-5a 走查的教训证明"假定全过其实没过"风险高(走查后才发现 5 个 bug)。
**Neo 反馈**:
*(待填)*
---
### D10 MP-2 月度聚合表方案选型
§2.2 推荐 D 双口径,但破坏性较强(API 字段变 + 前端展示变)。
| 选项 | 评估 |
|---|---|
| **a 方案 D 双口径(推荐)** | 业务一致 + 不丢扣减信息 + 不需新 ETL 表;~4h |
| b 方案 C 接受月度全量 + 前端标注 | 简单透明;但破坏"≤ 业务日"严格性,不符 AC2 |
| c 方案 A daily 累计实时计算 | 业务正确,失去 salary_calc 扣减算法 |
| d 方案 B monthly snapshot + daily 增量 | 实施量大(ETL+DWS+DDL),F1-5b 内做不完 |
**Claude 推荐 a**
**Neo 反馈**:
*(待填)*
---
## 八、失败决策矩阵(本次新增)
每项任务实施中遇到问题时,按严重度自主或升级处理。
### 8.1 严重度阈值
| 严重度 | 描述 | 处理 |
|---|---|---|
| **L0 自主修复** | 单元测试失败 / lint 警告 / 文档拼错 | Claude 自主修,不打断 Neo |
| **L1 自主回退** | 单 task 出错且不影响其他 task / Step 4 验证发现局部回归 | Claude `git revert` 单 task → 写回退报告 → 跳过该 task 进下一项 |
| **L2 升级 Neo** | 数据 bug 影响生产财务 / 跨组依赖断裂 / 走查发现 ≥ 2 个生产 bug | **立即停止 Wave** → 写阻塞报告 → 等 Neo 决定 |
| **L3 紧急停 Wave** | 全 PG 库不可达 / 测试库被污染影响其他正在跑的测试 / commit 已 push 后发现关键 bug | **立即停止全部任务** → 报警 → 等 Neo 决定回滚或修补 |
### 8.2 阶段级回退
| 场景 | 严重度 | 回退路径 |
|---|---|---|
| Wave A 完成后 mid-wave checkpoint 发现 ≥ 1 个 P0 bug | L2 | 当 commit revert + 原任务回 Wave A 重做 |
| Wave A 完成后 checkpoint 发现 sandbox 仍漏裁剪 | L2 | revert C2 → 加补丁 task → 重过 A3 |
| Wave B 完成后 SPEC 与代码不一致 | L0 | 单独修 D1-D4 文字,不动代码 |
| 整个 F1-5b 失败 | L3 | revert C1-C6 → 回到 F1-5a 完整状态(`421e193+1baa212+a045625`) |
### 8.3 单项风险表(细化 v1)
| 任务 | 风险 | 严重度 | 回退路径 | 升级阈值 |
|---|---|---|---|---|
| A1 | live 模式 RuntimeContext 失效 → 显示旧日期 | L1 | 三层 fallback:RuntimeContext → date.today() → warning | RuntimeContext 完全不可用 → L2 |
| A2 | conn=None + RuntimeContext 同时失效 | L1 | fallback 真实 today + warning | 同上 |
| A3 | GUC 注入与 `_fdw_context` SET LOCAL 重复 | L1 | grep `_fdw_context` 之前已 SET 跳过 | 性能 ≥ 5ms / 调用 → L2 |
| A6 | SET client_encoding 影响其他 ETL 连接 | L1 | feature flag `ETL_FORCE_UTF8` | ETL 全部断 → L3 |
| **Hook §5.1** | **hook 误伤 fallback 路径** | **L1** | **soft warning,允许 RUNTIME_CTX_BYPASS 注释 bypass** | **正常代码 ≥ 30% 命中误报 → L2 调整 grep 规则** |
| UI-3 | 分组显示破坏图表 | L1 | feature flag `VITE_AI_RUNTIME_GROUPING` | manager 反馈强 → L2 回退视图 |
| UI-4 | 顶栏徽章 API 500 整站破 | L1 | ErrorBoundary 包裹 | 整站破 → L3 |
| MP-1 | 修后影响生产财务数据 | **H/L2** | **修前后对照表给 Neo 确认** | **任何指标变负 / 误差 > 5% → L2** |
| MP-2 | 双口径 UX 不直观 | L1 | feature flag `enable_partial_month` | 反馈强 → L2 |
| MP-3 | 月末闭区间 `<=` vs `<` 边界 | L0 | boundary case test 守护 | — |
| MP-4 | setData 时机修复连带 | L1 | 仅 line 247-251 加补强 | 影响其他 page.data → L2 |
| MP-5 | localFallback 仍走真实 today | L1 | localFallback 改读 RuntimeContext sandbox_date 缓存 | sandbox 看到 5 月 → L2 |
| BE-1 | 插桩日志噪音 | L0 | logger.warning 加 [F1-5b-BE-1 DIAG] 前缀,排查完删除 | — |
| T2 | fixture 不切回 live 污染下次 | L1 | autouse fixture 强制切回 | 测试库被污染影响生产模拟 → L3 |
---
## 九、关联
- F1-5a 主体审计:[`docs/audit/changes/2026-05-05__wave1_f1_5a_sandbox_batch_run.md`](../../audit/changes/2026-05-05__wave1_f1_5a_sandbox_batch_run.md)
- F1-5a 走查报告:[`docs/audit/changes/2026-05-05__wave1_f1_5a_backend_walkthrough.md`](../../audit/changes/2026-05-05__wave1_f1_5a_backend_walkthrough.md)
- F1-5 实施决策卡:[`F1-5-impl-decisions.md`](F1-5-impl-decisions.md)
- P20 SPEC:[`docs/prd/specs/P20-runtime-context-sandbox.md`](../../prd/specs/P20-runtime-context-sandbox.md)
- W1-T7 PRD 批 1:[`docs/_overview/admin-api-prd/batch1-runtime-context-and-ai.md`](../admin-api-prd/batch1-runtime-context-and-ai.md)
- 测试库 site 清单:`memory/project_test_db_sites.md`(只有 `2790685415443269` 有数据)
- F2-1B 防御 hook 经验:`.claude/hooks/post_edit_openapi_reminder.py` / `.claude/hooks/post_edit_prompt_sync_reminder.py`
- Reload 卡死预防:`scripts/ops/start-admin.ps1` / `apps/backend/start_uvicorn.py` / `scripts/ops/backend-watchdog.ps1`
---
## 十、启动指令
Neo 复核 §7 D7-D10 后,在每项决策下填 *斜体* 反馈,然后回复"启动 Wave A"或"调整后启动",Claude 即按 §4.2 + §3 标准 5 步流程执行。
每项任务完成后:
1. 更新 §6 进度表(状态 / 完成时间 / commit)
2. 写审计记录(§3 Step 5)
3. 跑 §5.2 lint grep 校验(必过)
4. 进下一项
Wave A 末做 §4.2 mid-wave checkpoint,等 Neo 复审。