# 看板数据一致性陷阱（2026-08-07 实战复盘）

## 场景
上传 7月和8月 ERP 文件后，看板累计达成显示 2517.6万，实际应为 2633.3万。
经排查发现 4 层连环缺陷，层层叠加导致显示错误。

## 缺陷链

### 缺陷 1：`cb_sync_data.sh` 遗漏 `kpi_dashboard.json` (P23)
**现象**：本地文件正确，CloudBase 上仍是旧值。
**根因**：`cb_sync_data.sh` 同步列表不含 `kpi_dashboard.json`，但前端 ENDPOINTS 直接 fetch 此文件。
**验证**：
```bash
# 本地
python3 -c "import json;d=json.load(open('数据/kpi_dashboard.json'));print(d['total_h1_h2'])"
# CloudBase
curl -s "https://bier-sales-....tcloudbaseapp.com/数据/kpi_dashboard.json" | python3 -c "import json,sys;d=json.load(sys.stdin);print(d['total_h1_h2'])"
```
**修复**：`cb_sync_data.sh` FILES 数组加入 `kpi_dashboard.json`。

### 缺陷 2：`mcp_kpi_pipeline.py` 第 115 行单月索引 bug (P24)
```python
# ❌ 第115行原代码 — 只取当月
kpi['total_h2_actual'] = round(sum(p['h2_actual_months'][month_idx] for p in kpi['people']), 2)
# → 8月跑完 = 115.7万（丢失7月353.6万）

# ✅ 修复 — 取个人累计
kpi['total_h2_actual'] = round(sum(p.get('h2_actual', 0) for p in kpi['people']), 2)
# → 469.3万 = 7月+8月
```
每次 KPI cron（每日 00:00）运行都会触发此 bug，`total_h2_actual` 被重设为当月值。

### 缺陷 3：看板 `getKPI()` H2 月份索引错位 (P25)
```javascript
// ❌ 原代码 — 当月值永远放第一位（7月显示8月数据）
return { h2Actuals: [current, 0, 0, 0, 0, 0] };

// ✅ 修复 — 从 threeYearMonthly 读取各月实际值
var tym = d.threeYearMonthly || {}; var t2026 = tym['2026'] || {};
var h2Actuals = [t2026['7']||0, t2026['8']||current, t2026['9']||0, ...];
```

### 缺陷 4：看板"累计达成"计算不含历史月 (P26)
```javascript
// ❌ 原代码 — H1 + 当月(仅115.7万) = 2279万
var fullYearTax = filteredYtd + (prog.total || 0);

// ✅ 修复 — 无筛选时用 kpiDashboard 权威累计
if (!filteredSalesSet) fullYearTax = dash.total_h1_h2 || fullYearTax;
```

## 系统性修复原则

1. **数据部署验证**：改 JSON 后必须 `curl` 验证 CloudBase 版本，local ≠ CloudBase 是常见陷阱
2. **KPI 管线幂等性**：cron 重复运行不应改变 `total_h2_actual`（应基于个人 `h2_actual` 汇总而非单月）
3. **前端图表用权威源**：monthly charts 读 `threeYearMonthly`（逐月精确），累计读 `kpiDashboard.total_h1_h2`
4. **CDN 缓存**：CloudBase 有 5 分钟 CDN 缓存，部署后需 `Cache-Control: no-cache` 验证或等数分钟
