---
name: flywhlway/ota-log-diagnosis
source: https://app.decimal.ai/s/flywhlway-ota-log-diagnosis@1/SKILL.md
source_sha256: 094909e99ae4
---

# OTA 升级日志诊断

对整车 OTA 升级失败做根因定位。核心原则：**脚本给证据，你给结论**——
不要逐行阅读原始日志（大文件会耗尽上下文），一律先跑解析脚本拿结构化证据链。
脚本负责解析、分类、聚合等确定性工作；根因裁决、批次成因假设、报告措辞是你的工作。

## 执行流程

### 第 0 步 · 输入判定

- 用户已上传日志文件 → 进入第 1 步。
- 用户只有口头描述 → 按以下清单引导取证，不要凭描述猜根因：
  1. 车端 UA 日志（车机工程模式导出，路径通常含 `ota/` 或 `swdl/`）
  2. 云端调度侧该 VIN 的任务记录（campaign 平台导出）
  3. 失败时间点、车辆当时状态（电量／是否在充电／网络环境）
- 多台车 → 全部日志放同一目录，脚本支持批量（直接传目录路径）。

### 第 1 步 · 解析（必做）

```bash
python scripts/parse_logs.py <日志文件或目录> -o parsed.json
```

先看 stderr 的解析率统计：

- **解析率 < 60%**：日志格式不匹配。查看文件前 20 行确认来源；若是管道分隔的
  旧格式，用 `--format-hint legacy` 重试；仍失败则向用户确认日志来源，
  **不要试图自己写正则逐行解析大文件**。
- **出现 `UNPARSED_ERROR_LINES`**：这些行含 ERROR 但格式异常，用 view
  只查看脚本指出的那几行（已给出文件名:行号），人工纳入证据。
- **exit 1 且提示文件为空**：向用户确认导出是否成功。

### 第 2 步 · 分类（必做）

```bash
python scripts/classify_failure.py parsed.json -o classified.json
```

产出：每车终态失败码 → 类别映射；车队级聚合（同码占比、批次性判定）。
若 stderr 出现 `WARN: 未映射码`，说明码表未覆盖该码——在报告中标注该码需
人工确认，并提示维护者回填 RULES 与码表（两侧成对更新）。

### 第 3 步 · 领域知识补全（按需）

按 classified.json 里出现的类别，**只读对应的 reference**：

| 出现的失败类别 | 读取 |
|---|---|
| 刷写-ECU拒绝 / 刷写-传输 / 刷写-响应挂起 | `references/error_code_mapping.md` §3 + `references/ecu_matrix.md` 中涉事 ECU 的小节 |
| 下载/网络 / 包完整性 | `references/error_code_mapping.md` §1–§2 |
| 阶段卡滞（primary_code 形如 `STALL@X`） | `references/ota_flow.md` §2 超时预算表，对照卡滞阶段 |
| 激活/回滚 | `references/ota_flow.md` §4 + `error_code_mapping.md` §4 |
| 预条件 | `references/error_code_mapping.md` §3.0（可恢复失败，注意措辞） |
| 结果上报 | `references/error_code_mapping.md` §4.4 |

不要一次读完所有 reference。

### 第 4 步 · 根因裁决（你的核心工作）

基于证据链回答三个问题，写进报告：

1. **失败在哪一环**：以 `failed_stage` 为准（取自首个 ERROR 所在阶段）。
   ⚠️ 不要用 `furthest_stage` 回答这一问——失败会话末尾也有 REPORT 记录，
   该字段常为 REPORT，不代表升级走完了。
2. **为什么失败**：结合 reference 的排查动作 + 日志上下文做归因。
   证据不足以下结论时明确说"需要补充 X 数据"，列出取证清单——
   宁可给出"待定 + 取证方案"，不要给低置信度的确定性结论。
3. **个体还是批次**：`fleet.batch_suspected` 已给统计判定（同码占比 ≥60%
   且失败车数 ≥3）。你负责解释批次成因假设（同软件版本？同供应商 ECU 批次？
   同地域网络？同差分基线？）并给出每个假设的验证方法。

裁决时注意三个常见陷阱：

- `UDS_NRC_0x78` 单独出现是正常的响应挂起，不是故障；只有其后无恢复才是超时。
- 回滚成功（`ROLLBACK_TRIGGERED` 后有 slot A boot ok）说明保护机制生效，
  措辞上必须与"回滚失败（可能变砖）"区分开，不要吓到用户。
- 首个 ERROR 是主证据，后续 ERROR 常是它的伴生结果（如 0x31 之后的
  `SEG_TRANSFER_ABORT`），不要把伴生码当独立问题分别处置。

### 第 5 步 · 报告生成

```bash
python scripts/generate_summary.py classified.json -o report.md
```

脚本产出报告骨架（总览表 + 每车证据链），你在骨架的 `<!-- ANALYSIS -->`
标记处填写第 4 步的归因分析与建议，然后把完整报告交付用户。
classified.json 一并交付（用户的工单系统可直接消费）。

## 断点恢复

若 workspace 已存在 `parsed.json` 且其 `meta.files` 与本次输入文件一致，
跳过第 1 步直接进第 2 步；不一致则从头执行并覆盖。

## 错误处理与 fallback

- **parse_logs.py 非零退出**：stderr 有明确原因（路径不存在／文件为空）。
  编码问题（日志为 GBK）先 `iconv -f GBK -t UTF-8 in.log > out.log` 转换再重试。
- **日志时间跨度覆盖多次升级会话**：脚本按 session 自动切分，默认分析最近一次
  （`sessions_in_log` 字段给出总数）；用户没说关心哪次时，按默认分析并
  在报告中说明"该车日志内含 N 次会话，本次分析最近一次"。
- **云端与车端日志时间戳时区不一致**：以车端为准；若发现两侧时间线明显错位
  （相差接近整小时数），在报告中显式声明该不确定性，不要强行对齐后下结论。
- **完全无法定位（证据链断裂）**：交付物改为"下一步取证方案"——
  明确缺哪段日志、从哪个系统取、取证后如何复跑本流程。这是合格交付，
  不是失败；不要用推测填补证据空缺。

## 边界

- 升级过程伴生的 DTC 由本技能一并分析（作为刷写失败的证据），不要移交。
- 用户的问题演变为"规划下次怎么分批推送"→ 说明本技能只交付诊断结论，
  分批策略属 `ota-campaign-planning` 的领域，并提示切换。
- 车机应用崩溃（tombstone/ANR）不属本技能，移交 `ivi-crash-analysis`。