---
phase: 02-correctness
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - .github/workflows/miri.yml
  - tests/edge_cases.rs
  - tests/sqllog_additional.rs
  - tests/parser_iterator.rs
  - tests/parser_errors.rs
  - tests/integration_test.rs
autonomous: true
requirements:
  - CORR-02

must_haves:
  truths:
    - "CI push 到 main 时自动运行 Miri，覆盖 unsafe 解码路径"
    - "Miri 作业成功完成，无 UB 报告"
    - "使用 mmap 的测试被 #[cfg(not(miri))] 标注，Miri 下不运行"
    - "performance_metrics.rs 10 条测试在 Miri 下全部通过"
  artifacts:
    - path: ".github/workflows/miri.yml"
      provides: "Miri CI 作业"
      contains: "cargo miri test"
    - path: "tests/edge_cases.rs"
      provides: "#[cfg(not(miri))] 标注 mmap 测试"
    - path: "tests/sqllog_additional.rs"
      provides: "#[cfg(not(miri))] 标注 mmap 测试"
    - path: "tests/parser_iterator.rs"
      provides: "#[cfg(not(miri))] 标注所有测试"
    - path: "tests/parser_errors.rs"
      provides: "#[cfg(not(miri))] 标注所有测试"
    - path: "tests/integration_test.rs"
      provides: "#[cfg(not(miri))] 标注所有测试"
  key_links:
    - from: ".github/workflows/miri.yml"
      to: "tests/performance_metrics.rs"
      via: "cargo miri test --test performance_metrics"
      pattern: "cargo miri test"
---

<objective>
将 Miri 加入 CI，覆盖 unsafe 解码路径；为所有使用 mmap 的测试添加 #[cfg(not(miri))] 标注以避免 Miri 不支持的操作。

Purpose: CORR-02 确保 unsafe 块在每次 PR 和 push 时被 Miri 静态检查，防止 UB 悄悄引入。
Output: .github/workflows/miri.yml 新 CI 作业；5 个测试文件添加 cfg 标注；cargo miri test --test performance_metrics 本地可通过。
</objective>

<execution_context>
@/Users/guang/.claude/get-shit-done/workflows/execute-plan.md
@/Users/guang/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/ROADMAP.md
@.planning/phases/02-correctness/02-RESEARCH.md
@.github/workflows/benchmark.yml
</context>

<interfaces>
<!-- 需要了解的关键信息，从研究文档提取 -->

需要标注 #[cfg(not(miri))] 的测试：

| 文件 | 需要标注的测试函数 |
|------|------------------|
| tests/edge_cases.rs | `probable_record_start_line_and_iterator_singleline_detection` |
| tests/sqllog_additional.rs | `file_encoding_detection_gb18030`, `file_encoding_detection_utf8`，以及 Task 1 新增的 `encoding_detection_gb18030_after_64kb_boundary` |
| tests/parser_iterator.rs | 所有测试函数（全部使用 LogParser + tempfile） |
| tests/parser_errors.rs | 所有测试函数（全部使用 LogParser + tempfile） |
| tests/integration_test.rs | 所有测试函数（全部使用 LogParser + tempfile） |

不需要标注（全部 Miri 兼容）：
- tests/performance_metrics.rs — 使用 parse_record，无 mmap

benchmark.yml 结构参考（用于保持 CI 风格一致）：
```yaml
name: Benchmark
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
env:
  CARGO_TERM_COLOR: always
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
  benchmark:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: actions/cache@v5
```

Miri 运行命令（已本地验证）：
```
MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test --test performance_metrics --test sqllog_additional --test edge_cases
```
</interfaces>

<tasks>

<task type="auto">
  <name>Task 1: 为所有 mmap 测试添加 #[cfg(not(miri))] 标注</name>
  <files>tests/edge_cases.rs, tests/sqllog_additional.rs, tests/parser_iterator.rs, tests/parser_errors.rs, tests/integration_test.rs</files>
  <read_first>
    - tests/edge_cases.rs（找到 `probable_record_start_line_and_iterator_singleline_detection` 函数，在 `#[test]` 后一行插入）
    - tests/sqllog_additional.rs（找到 `file_encoding_detection_gb18030` 和 `file_encoding_detection_utf8`，以及 02-01-PLAN 新增的 `encoding_detection_gb18030_after_64kb_boundary`）
    - tests/parser_iterator.rs（列出所有 `#[test]` 函数，全部标注）
    - tests/parser_errors.rs（列出所有 `#[test]` 函数，全部标注）
    - tests/integration_test.rs（列出所有 `#[test]` 函数，全部标注）
  </read_first>
  <action>
**标注规则：** 在每个目标测试函数的 `#[test]` 属性后，紧接着插入 `#[cfg(not(miri))]`。
顺序必须是：
```rust
#[test]
#[cfg(not(miri))]
fn test_function_name() {
```

**edge_cases.rs** — 只标注 1 个函数：
- `probable_record_start_line_and_iterator_singleline_detection`

**sqllog_additional.rs** — 标注 3 个函数：
- `file_encoding_detection_gb18030`
- `file_encoding_detection_utf8`
- `encoding_detection_gb18030_after_64kb_boundary`（02-01-PLAN 新增，如已有 #[cfg(not(miri))] 则跳过）

**parser_iterator.rs** — 标注所有 `#[test]` 函数（逐一检查，不要遗漏）

**parser_errors.rs** — 标注所有 `#[test]` 函数

**integration_test.rs** — 标注所有 `#[test]` 函数

**验证标注正确性（不用 mmap 的不能标注）：**
在每个文件中，只标注实际使用 `LogParser::from_path` 或 `NamedTempFile` 的测试。
不使用 mmap 的测试（如只调用 `parse_record`）不得标注。

**本地验证命令（在标注后运行）：**
```
cargo test
```
确认标注后常规测试（非 Miri）全部通过，标注不影响正常运行。
  </action>
  <verify>
    <automated>cargo test</automated>
  </verify>
  <done>
    - 五个测试文件中所有使用 LogParser/tempfile 的测试函数都有 `#[cfg(not(miri))]`
    - `cargo test` 全部通过（标注不应导致任何测试消失）
    - `grep -rn 'cfg(not(miri))' tests/` 至少命中 10 处
  </done>
</task>

<task type="auto">
  <name>Task 2: 创建 Miri CI 作业</name>
  <files>.github/workflows/miri.yml</files>
  <read_first>
    - .github/workflows/benchmark.yml（参考 CI 结构、actions 版本、cache 配置风格）
  </read_first>
  <action>
创建 `.github/workflows/miri.yml`，内容如下（严格按照研究文档中的结构，保持与 benchmark.yml 风格一致）：

```yaml
name: Miri

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  CARGO_TERM_COLOR: always
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
  miri:
    name: Miri unsafe check
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Install nightly + Miri
        uses: dtolnay/rust-toolchain@nightly
        with:
          components: miri

      - name: Cache cargo registry
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-miri-${{ hashFiles('**/Cargo.lock') }}

      - name: Run Miri (unsafe decode paths)
        run: cargo miri test --test performance_metrics --test sqllog_additional --test edge_cases
        env:
          MIRIFLAGS: "-Zmiri-disable-isolation"
```

注意事项：
- 不包含 schedule 触发（仅 push + pull_request，避免浪费 CI 分钟）
- cache key 使用 `miri-` 前缀区别于 benchmark.yml 的 `cargo-` 前缀
- MIRIFLAGS 在 step 级别的 env 中设置（非全局），仅影响 Miri 运行步骤
- `--test sqllog_additional --test edge_cases` 中的 mmap 测试会被 #[cfg(not(miri))] 自动跳过
  </action>
  <verify>
    <automated>cat .github/workflows/miri.yml | grep -E "cargo miri test|MIRIFLAGS|dtolnay/rust-toolchain@nightly"</automated>
  </verify>
  <done>
    - `.github/workflows/miri.yml` 文件存在
    - 文件包含 `cargo miri test --test performance_metrics --test sqllog_additional --test edge_cases`
    - 文件包含 `MIRIFLAGS: "-Zmiri-disable-isolation"`
    - 文件包含 `dtolnay/rust-toolchain@nightly` 及 `components: miri`
    - 触发条件为 push + pull_request（不含 schedule）
  </done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| CI 环境 → nightly 工具链 | Miri 依赖 nightly；dtolnay/rust-toolchain@nightly 固定来源 |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-02-04 | Tampering | Miri CI 作业 | mitigate | 每次 PR 强制运行 Miri，UB 在合并前暴露 |
| T-02-05 | Denial of Service | Miri 运行耗时 | accept | ~4 min 总计（compile 2 min + test 2 min）；仅覆盖必要测试文件，无冗余 |
</threat_model>

<verification>
1. `cat .github/workflows/miri.yml` — 文件存在且结构正确
2. `grep -c 'cfg(not(miri))' tests/edge_cases.rs tests/sqllog_additional.rs tests/parser_iterator.rs tests/parser_errors.rs tests/integration_test.rs` — 每个文件至少 1 处命中
3. `cargo test` — 全部通过（标注正确，非 Miri 环境下不影响测试运行）
4. `grep 'mmap.len().min' tests/` — 无输出（确认没有遗漏标注含 mmap 的测试）
5. 本地可选：`MIRIFLAGS="-Zmiri-disable-isolation" cargo +nightly miri test --test performance_metrics` — 10/10 PASS
</verification>

<success_criteria>
- .github/workflows/miri.yml 存在，CI 风格与 benchmark.yml 一致
- `cargo miri test --test performance_metrics` 在本地（nightly）通过
- 五个测试文件的 mmap 测试均有 #[cfg(not(miri))] 标注
- `cargo test` 全部通过（无回归）
</success_criteria>

<output>
完成后在 `.planning/phases/02-correctness/02-02-SUMMARY.md` 记录：
- 创建的文件：.github/workflows/miri.yml
- 标注的测试函数列表（每个文件分别列出）
- 本地 cargo test 输出摘要
- 是否本地运行了 Miri（可选，记录结果）
</output>
