# Tilelang Op Test Design

> TileLang-Ascend 算子测试设计技能。支持多种场景：(1) 从 design.md 设计测试配置 (2) 从 examples/{op}/*.py 补充测试 (3) 手动提供算子信息生成测试 (4) 测试覆盖率分析。理解算子实现逻辑后智能判断测试策略。触发：设计算子测试、生成测试用例、补充测试、测试覆盖率不足。

- Skill: `tile-ai/tilelang-op-test-design` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add tile-ai/tilelang-op-test-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tile-ai/tilelang-op-test-design/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tile-ai (https://skillmd.com/u/tile-ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tile-ai/tilelang-op-test-design

---


# TileLang-Ascend 算子测试设计

---

## 1. 技能定位与支持场景

### 1.1 支持的多种场景

本技能支持 **4 种主要场景**：

| 场景 | 输入来源 | 适用时机 | 工作流程 |
|------|---------|---------|---------|
| **场景 A** | design.md | 算子设计阶段 | 从设计文档提取信息 → 智能判断测试策略 → 生成测试配置建议 |
| **场景 B** | examples/{op}/*.py | 算子已实现 | 从实现代码提取信息 → 分析现有测试 → 补充缺失用例 |
| **场景 C** | 用户口头描述 | 早期讨论阶段 | 用户交互收集信息 → 智能判断测试策略 → 生成测试模板 |
| **场景 D** | 现有测试分析 | 测试完善阶段 | 分析现有测试覆盖率 → 智能判断缺失场景 → 补充测试用例 |

---

### 1.2 场景触发关键词

| 场景 | 触发关键词示例 |
|------|---------------|
| **场景 A** | "为这个算子设计测试"、"根据 design.md 生成测试配置" |
| **场景 B** | "补充这个算子的测试"、"完善现有测试" |
| **场景 C** | "我想开发一个 softmax 算子，帮我设计测试"、"算子是 xxx，数学公式是 yyy" |
| **场景 D** | "分析测试覆盖率"、"现有测试不够全面，需要补充" |

---

## 2. 算子类别划分依据

### 2.1 划分依据来源

算子类别划分参考 **tilelang-op-design skill §4 算子特征分析决策树**，基于以下三个维度：

1. **计算类型（硬件特性）**
2. **复杂度级别（计算步骤）**
3. **数学公式特征（数学运算）**

---

### 2.2 计算类型划分（硬件特性）

**依据**：算子主要使用哪类硬件单元

| 计算类型 | 使用的硬件单元 | 数学公式特征 | 测试重点 |
|---------|--------------|-------------|---------|
| **纯 Cube** | Cube 核（矩阵乘单元） | 仅含 matmul / @ | 矩阵维度组合、block size |
| **纯 Vector** | Vector 核（向量单元） | 无 matmul，仅 element-wise/reduction | dtype 组合、shape 组合 |
| **混合（CV 融合）** | Cube + Vector 核 | matmul + element-wise 后处理 | 核间协作正确性。Developer 模式默认消除显式 workspace（`threads=2` + 片上直连），测试聚焦 CV 交互结果；Expert/混合或回退才涉及显式 workspace（GM 中转）+ 跨核同步 |

**判断方法**：理解算子实现逻辑后判断

---

### 2.3 复杂度级别划分（计算步骤）

**依据**：算子有多少个计算步骤

| 复杂度级别 | 计算步骤数 | 典型算子 | 测试特点 |
|-----------|----------|---------|---------|
| **单步（Single）** | 1 步 | Add, Mul, ReLU | 简单配置，快速验证 |
| **多步（Multi）** | 2~5 步 | Softmax, LayerNorm | 详细配置，多 dtype |
| **融合（Fusion）** | 多算子组合 | FlashAttention | 复杂配置，测试完整数据流 |

**判断方法**：分析数学公式或算法描述，理解计算步骤后判断

---

### 2.4 数学公式特征划分

**依据**：数学公式中的关键运算

| 数学公式特征 | 算子类别 | 测试策略 |
|-------------|---------|---------|
| 含 `matmul` / `@` / 矩阵乘 | **GEMM 类** | 三维参数（M/N/K），block size 组合多 |
| 含 `exp + sum + div` 组合 | **Softmax 类** | 多 dtype，精度按 dtype 不同 |
| 含 `mean + var + sqrt` 组合 | **Normalization 类** | eps 参数重要，多 dtype |
| 含 `sigmoid` / `relu` / `gelu` | **Activation 类** | 简单配置，逐元素验证 |
| 含 `sum(dim)` / `max(dim)` | **Reduction 类** | 归约维度重要 |

---

### 2.5 综合分类示例

| 算子 | 计算类型 | 复杂度 | 数学特征 | 综合类别 |
|------|---------|--------|---------|---------|
| **MatMul** | 纯 Cube | Single | matmul | GEMM（纯矩阵乘） |
| **Softmax** | 纯 Vector | Multi | exp+sum+div | Softmax（多步归一化） |
| **LayerNorm** | 纯 Vector | Multi | mean+var+sqrt | Normalization（多步归一化） |
| **SiLU** | 纯 Vector | Single | sigmoid | Activation（单步激活） |
| **FlashAttention** | 混合（CV） | Fusion | matmul+softmax+matmul | Fusion（融合算子） |

---

### 2.6 参数约束关系

**C-001：dtype 一致性约束**
大多数 TileLang 算子要求输入输出 tensor dtype 一致。

---

## 3. 算子类别识别方法

### 3.1 核心原则

**算子类别识别方法**：阅读设计文档/代码，理解算子实现逻辑后给出判断。

---

### 3.2 判断流程

```
步骤 1：阅读算子信息
    ├─ 场景 A：阅读 design.md §1.3 数学公式 + §1.4 算法描述
    ├─ 场景 B：阅读 examples/{op}/ 算子实现代码
    ├─ 场景 C：理解用户口头描述的数学公式
    └─ 场景 D：阅读现有测试代码，分析覆盖情况

步骤 2：理解实现逻辑
    ├─ 分析数学公式中的关键运算（matmul/exp/sum/reduce 等）
    ├─ 分析计算步骤数（单步/多步/融合）
    ├─ 分析硬件需求（Cube/Vector/混合）
    └─ 分析参数维度（M/N/K/dim 等）

步骤 3：给出判断
    ├─ 计算类型：纯 Cube / 纯 Vector / 混合
    ├─ 复杂度级别：Single / Multi / Fusion
    ├─ 数学特征：GEMM / Softmax / Activation / Reduction 等
    └─ 综合类别：GEMM（纯） / Softmax / Fusion 等

步骤 4：基于判断生成测试策略
    └─ 不同类别有不同的测试配置生成策略
```

---

### 3.3 判断示例

#### 示例 1：GEMM 算子判断

**阅读信息**：
```
数学公式：C = A @ B
算法描述：矩阵乘法，分块计算
```

**理解逻辑**：
- 公式中只有 `@`（矩阵乘）运算 → 纯 Cube 计算
- 只有 1 个计算步骤 → Single 复杂度
- 没有其他运算 → 纯 GEMM

**判断结果**：
```python
{
    "计算类型": "纯 Cube",
    "复杂度": "Single",
    "数学特征": "matmul",
    "综合类别": "GEMM（纯矩阵乘）",
    "测试策略": {
        "dtype_count": 2,
        "shape_count": 5,  # 多种 M/N/K 组合
        "block_count": 3,  # 多种 block size
        "三维参数": True,   # M/N/K
    }
}
```

---

#### 示例 2：Softmax 算子判断

**阅读信息**：
```
数学公式：softmax(x_i) = exp(x_i) / sum_j(exp(x_j))
算法描述：先计算 max，再 exp，再 sum，最后 div
```

**理解逻辑**：
- 公式中有 exp、sum、div，无 matmul → 纯 Vector 计算
- 有 4 个计算步骤（max → exp → sum → div） → Multi 复杂度
- 是典型的 softmax 公式 → Softmax 类

**判断结果**：
```python
{
    "计算类型": "纯 Vector",
    "复杂度": "Multi",
    "数学特征": "exp+sum+div",
    "综合类别": "Softmax（多步归一化）",
    "测试策略": {
        "dtype_count": 3,  # FP16/FP32/BF16
        "shape_count": 4,
        "block_count": 2,
        "精度按 dtype": True,  # 不同 dtype 精度不同
    }
}
```

---

#### 示例 3：FlashAttention 算子判断

**阅读信息**：
```
数学公式：Attention = softmax(Q @ K^T / sqrt(d)) @ V
算法描述：先 GEMM（Q,K），再 softmax，再 GEMM（attn,V）
```

**理解逻辑**：
- 公式中有两次 matmul + softmax → Cube + Vector 混合计算
- 有 3 个算子组合（GEMM + softmax + GEMM） → Fusion 复杂度
- 是典型的融合算子 → Fusion 类

**判断结果**：
```python
{
    "计算类型": "混合（CV 融合）",
    "复杂度": "Fusion",
    "数学特征": "matmul+softmax+matmul",
    "综合类别": "Fusion（融合算子）",
    "测试策略": {
        "dtype_count": 2,
        "shape_count": 3,
        "block_count": 2,
        "workspace配置": True,  # 仅 Expert/混合或回退写法；Developer 模式默认消除 workspace，此项为 False
    }
}
```

---

## 4. 多场景工作流程

### 4.1 场景 A：从 design.md 输入

**触发**："根据 design.md 设计测试"

**工作流程**：

```
Phase 1：信息提取（强制步骤）
    ├─ 定位 design.md 文件（examples/{op}/design.md）
    ├─ 提取 §1.3 数学公式
    ├─ 提取 §1.4 算法描述（计算步骤）
    ├─ 提取 §2 编程模式
    ├─ 提取 §4 输入输出规格（shape/dtype）
    ├─ 提取 §5 block size
    └─ 提取 §9.3 精度标准（未定义则阻塞，回 Stage 1 补齐）

Phase 2：理解判断
    ├─ 阅读数学公式，理解计算逻辑
    ├─ 判断计算类型（纯 Cube/Vector/混合）
    ├─ 判断复杂度（Single/Multi/Fusion）
    ├─ 判断数学特征（GEMM/Softmax/Activation等）
    └─ 给出综合类别判断

Phase 3：用户交互（补充决策）
    ├─ 询问测试重点（功能验证/全面测试/异常测试）
    ├─ 询问用例数量（快速冒烟/标准测试/全面测试）
    ├─ 询问不规则 shape（自然包含/重点测试/不需要）
    ├─ 询问特殊场景（空 tensor/极值/INF/NAN等）
    └─ 询问精度标准（如 §9.3 未定义）

Phase 3.5：闸门确认（可选，防止错误扩散）
    ├─ 展示测试配置摘要（dtype 组合、shape 组合、特殊场景）
    ├─ 询问用户："测试配置是否正确？是否继续生成测试代码？"
    ├─ 用户确认 → 进入 Phase 4
    └─ 用户否决 → 返回 Phase 2 重新判断
    └─ 适用场景：融合算子（Fusion 类）、多步复杂算子（Multi 复杂度）

Phase 4：生成测试配置
    ├─ 基于判断生成 L0 配置
    ├─ 基于判断生成 L1 配置（含不规则 shape）
    ├─ 基于用户交互生成 L2 配置
    └─ 基于用户交互生成 Boundary 配置

Phase 5：输出测试代码
    └─ 根据算子类别选择对应模板，生成测试代码
```

---

### 4.2 场景 B：从 examples/{op}/ 算子文件输入

**触发**："补充这个算子的测试"

**工作流程**：

```
Phase 1：信息提取（强制步骤）
    ├─ 定位 examples/{op}/ 算子文件（如 silu.py, flash_attn_bhsd.py）
    ├─ 阅读 Kernel 实现代码
    ├─ 提取函数签名（参数列表）
    ├─ 分析已有测试配置
    └─ 分析 pass_configs 配置

Phase 2：理解判断
    ├─ 阅读实现代码，理解计算逻辑
    ├─ 判断算子类别（直接判断）
    └─ 分析现有测试覆盖情况

Phase 3：用户交互（补充决策）
    ├─ 询问测试重点（补充功能测试/补充异常测试）
    ├─ 询问缺失场景（现有测试缺少哪些）
    └─ 询问用例数量

Phase 4：分析测试空白
    ├─ 对比现有测试 vs 理应有测试
    ├─ 识别缺失场景（dtype组合/shape组合/异常场景）
    └─ 生成补充配置

Phase 5：输出补充测试（填充现有 test_{op}.py 的桩体，不新建文件、不碰 kernel）
    ├─ 定位 generate 已生成的 test_{op}.py 中 test_{op}_l1/l2/boundary 三个桩函数
    ├─ 用真实分层用例替换桩体（参 §9.1）：
    │     L1 → 规则+不规则 shape（含尾块）；L2 → 非法输入（应被拒绝）；Boundary → INF/NAN/极值（合法）
    ├─ L1 用 _run_precision（[PRECISION_*]，阻塞）；L2 用 _run_exception（期望拒绝）、Boundary 用 _run_boundary（比精度，不过 WARN）（均 [BOUNDARY_*]，非阻塞）
    └─ 保持 main 分发器与 --level 接口不变（不改 generate 已写好的 main），kernel 仍从 {op}.py import
```

> **场景 B 输出形式（强约束）**：**只填充现有 `test_{op}.py`** 的三个桩函数体，不新建独立 test 文件、**不改 `{op}.py`（kernel）**。generate 在 first_impl 已生成 `test_{op}.py`（含 `from {op} import {op}`、`test_{op}_l1/l2/boundary` 桩 + 稳定的 `main` 分发器）；场景 B 只替换这三个桩函数的函数体，**不改 main、不改 `--level` 接口、不动 L0 与 kernel 文件**。替换后用 `python examples/{op}/test_{op}.py --level all` 跑全量验证。

---

### 4.3 场景 C：用户口头描述

**触发**："我想开发一个 softmax 算子，帮我设计测试"

**工作流程**：

```
Phase 1：用户交互收集信息
    ├─ 询问算子名称
    ├─ 询问数学公式（参考 tilelang-op-design 的交互方式）
    ├─ 询问输入输出规格
    ├─ 询问编程模式偏好
    └─ 询问其他信息（典型配置、性能目标等）

Phase 2：理解判断
    ├─ 基于数学公式理解计算逻辑
    ├─ 判断算子类别（直接判断）
    └─ 给出测试策略建议

Phase 3：生成测试配置
    └─ 基于判断和用户需求生成测试配置

Phase 4：输出测试模板
    └─ 生成测试代码模板（或输出到文件）
```

---

### 4.4 场景 D：测试覆盖率分析

**触发**："分析测试覆盖率，补充缺失用例"

**工作流程**：

```
Phase 1：分析现有测试
    ├─ 阅读现有测试代码
    ├─ 统计已覆盖的 dtype 组合
    ├─ 统计已覆盖的 shape 组合
    ├─ 统计已覆盖的异常场景
    └─ 统计已覆盖的边界场景

Phase 2：判断缺失场景
    ├─ 基于算子类别判断应覆盖的场景
    ├─ 对比现有测试 vs 应覆盖场景
    ├─ 识别缺失的 dtype 组合
    ├─ 识别缺失的 shape 组合（含不规则 shape）
    ├─ 识别缺失的异常场景
    └─ 识别缺失的边界场景

Phase 3：用户交互（确认补充）
    ├─ 展示缺失场景清单
    ├─ 询问是否全部补充或选择性补充
    └─ 询问用例数量

Phase 4：生成补充配置
    └─ 为缺失场景生成测试配置

Phase 5：输出补充测试代码
    └─ 输出补充测试函数
```

---

## 5. 测试分层体系（四层）

| 层级 | 名称 | 用例数 | 测试目标 | Shape 特点 |
|------|------|--------|---------|-----------|
| **L0** | 门槛测试 | ≤50 | 核心功能验证 | 规则 shape（快速冒烟） |
| **L1** | 功能测试 | 100-200 | 参数组合覆盖 | **规则 + 不规则 shape**（自然包含） |
| **L2** | 异常测试 | ≤20 | 非法输入拒绝验证（负向，不比精度） | 非法 shape / 不支持 dtype |
| **Boundary** | 边界测试 | ≤10 | 合法特殊值精度验证（比精度，不过报 WARN） | INF/NAN/极值/空 tensor |

---

## 6. 确定性 Shape 生成（强制非对齐必出）

**规则**：L1 的 shape 集合由 block 反推**确定性生成**，非对齐 / 尾块 / 质数 shape **默认必出**——不再用"是否需要不规则 shape"的软问法。用户只能在此基线上**加量**，不能减到 0。覆盖维度 ID 与判定见 `references/coverage-matrix.md`。

**生成公式**（给定主分块 `block=(bM, bN[, bK])`，`k` 为倍数）：
```python
def gen_l1_shapes(bM, bN, k=4):
    return {
        "D-SHAPE-ALIGNED":  (bM*k,            bN*k),             # block 整除（规则）
        "D-SHAPE-TAIL-1":   (bM*k + 1,        bN*k),             # 余数 1（最易暴露边界 bug）
        "D-SHAPE-TAIL-MID": (bM*k + bM//2,    bN*k + bN//2),     # 中间余数
        "D-SHAPE-PRIME":    (nearest_prime(bM*k), nearest_prime(bN*k)),  # 完全非对齐
        "D-SHAPE-EDGE":     (1, bN*k),                           # 退化（另配 (bM*k,1)/单元素）
    }
```

**类别特例**：
- **GEMM / 含 matmul**：上式扩到 K 轴——至少一条 `K=bK*k+1` 或质数 K，保证 M/N/K **三轴都出现过非对齐**（不能只非对齐 M）。
- **多维算子**：对 proto 支持的每个 rank（2D/3D/4D/5D…）重复「ALIGNED + 一条非对齐」，命中 `D-SHAPE-RANK-<r>`。
- **逐元素激活（无 tiling 边界）**：尾块与对齐路径等价，可对 `D-SHAPE-TAIL-*`/`PRIME` 走豁免（写入 `COVERAGE_NA`，见 §9）。

`nearest_prime(n)` 取 ≤ n 的最近质数，避免超出 proto 支持范围。

---

## 7. 用户交互流程（参考 tilelang-op-design）

### 交互规则（严格遵守）

参考 tilelang-op-design skill §2：

1. **每次只询问一个问题**
2. **按顺序依次询问**
3. **已提供的跳过**

---

### 交互示例

**步骤 1：测试重点**
```
请选择本次测试的重点：
[1] 功能验证（L0+L1） - 快速验证基本功能和参数组合
[2] 全面测试（L0+L1+L2+Boundary） - 完整测试，含异常和边界
[3] 仅补充异常测试（L2） - 现有测试已完善，仅补充异常场景
[4] 精度专项测试 - 重点验证不同 dtype 的精度标准
```

**步骤 2：用例数量**
```
请选择测试用例数量规模：
[1] 快速冒烟（L0≤10, L1≤50）
[2] 标准测试（L0≤50, L1=100-200）
[3] 全面测试（L0≤50, L1=200-300）
```

**步骤 3：不规则 shape 加量（非对齐为强制基线，不可关闭）**
```
不规则 shape（尾块/质数）已由 §6 确定性生成强制包含。请选择是否额外加量：
[1] 标准（推荐） - 仅 §6 强制基线（ALIGNED/TAIL-1/TAIL-MID/PRIME/EDGE 各 1）
[2] 重点加量 - 在强制基线上额外生成更多尾块/质数配置
```
> 说明：不再提供"不需要不规则 shape"选项——非对齐覆盖为覆盖矩阵强制维度，关闭会被 checker 判 MISS。

---

## 8. 完成报告

生成完成后输出报告：

```
## 测试代码生成报告

### 算子信息
- 算子名称: {op_name}
- 输入来源: design.md / examples/{op}/*.py / 用户描述 / 测试分析
- 输入场景: {场景 A/B/C/D}

### 判断结果
1. 计算类型: {纯 Cube / 纯 Vector / 混合} - 基于 {数学公式分析}
2. 复杂度级别: {Single / Multi / Fusion} - 基于 {计算步骤分析}
3. 数学特征: {GEMM / Softmax / Activation 等} - 基于 {关键运算分析}
4. 综合类别: {最终类别判断}

### 用户交互决策
- 测试重点: {用户选择}
- 用例数量: {用户选择}
- 不规则 shape: {用户选择}
- 特殊场景: {用户选择}

### 测试配置统计
- L0: {n} 个用例
- L1: {n} 个用例(规则={n}, 不规则={n})
- L2: {n} 个用例
- Boundary: {n} 个用例

### 覆盖矩阵（逐维度，来自 coverage_check.py）
| 维度 ID | 应覆盖 | 实际数量 | 状态 |
|---|---|---|---|
| D-DTYPE-fp16 | ≥1 | {n} | PASS |
| D-SHAPE-PRIME | ≥1 | {n} | PASS / MISS |
| D-VALRANGE-L | ≥1 | {n} | PASS / MISS |
| D-SPECIAL-INF | ≥1 | {n} | PASS / N/A（理由） |
| ... | ... | ... | ... |

**覆盖结论**：{x} PASS / {y} MISS / {z} N/A → {PASS 全绿 / FAIL 有未豁免 MISS}
> 有未豁免 MISS 时必须先补齐用例再交付，不得直接报 `[PRECISION_PASS]`。

### 输出文件
- 路径: {output_file}
```

---

## 9. 测试代码结构示例

### 9.1 标准测试结构

> 这是 **`test_{op}.py`** 的结构（kernel 在同目录 `{op}.py`，此处从中 import）。测试文件不含 kernel 定义。

```python
import argparse
import os
import sys

import tilelang
import torch

# 从同目录 kernel 文件导入被测 kernel
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from {op} import {op}   # noqa: E402

# ========== 精度标准定义（混合容差，详见 references/precision-standard.md）==========
def get_precision(dtype):
    """返回 (atol, rtol, max_abs_error_limit, required_matched_ratio)。
    浮点：混合容差；整型：精确匹配（0 误差）。"""
    fp_table = {
        # dtype       : (atol,   rtol,   max_abs_error_limit, required_matched_ratio)
        "float16":     (2**-14, 2**-9,  1e-1, 0.99),   # atol 6.10e-5, rtol 1.95e-3
        "bfloat16":    (2**-10, 2**-6,  1e0,  0.99),   # atol 9.77e-4, rtol 1.56e-2
        "float32":     (2**-16, 2**-10, 1e-2, 0.99),   # atol 1.53e-5, rtol 9.77e-4
        "hifloat32":   (2**-16, 2**-10, 1e-2, 0.99),
        "float8_e4m3": (2**-4,  2**-2,  1e0,  0.99),   # atol 0.0625, rtol 0.25
        "float8_e5m2": (2**-3,  2**-1,  1e-1, 0.99),   # atol 0.125,  rtol 0.5
    }
    int_types = {"int8", "int16", "int32", "int64", "uint8"}
    if dtype in int_types:
        return (0.0, 0.0, 0.0, 1.0)          # 整型：精确匹配，一个元素不符即 FAIL
    return fp_table.get(dtype, (2**-14, 2**-9, 1e-1, 0.99))

def check_precision(actual, golden, dtype):
    """精度判定：返回 (passed, matched_ratio, max_abs_error)。
    浮点双门限：matched_ratio ≥ required 且 max_abs_error ≤ max_abs_error_limit；
    整型逐元素精确相等；inf/nan 位置做结构比对，不计入数值容差。"""
    atol, rtol, max_abs_limit, required_ratio = get_precision(dtype)
    a = actual.detach().cpu()
    g = golden.detach().cpu()
    if atol == 0.0 and rtol == 0.0:                      # 整型精确匹配
        mism = (a != g).sum().item()
        total = max(a.numel(), 1)
        return mism == 0, 1.0 - mism / total, (0.0 if mism == 0 else float("inf"))
    a = a.float()
    g = g.float()
    special = ~torch.isfinite(g)                         # inf/nan 位置结构比对
    if special.any():
        if not torch.equal(torch.isnan(a[special]), torch.isnan(g[special])) or \
           not torch.equal(torch.isinf(a[special]), torch.isinf(g[special])):
            return False, 0.0, float("inf")
    m = torch.isfinite(g)                                # golden 有限值位置全比：actual 若为 inf/nan 则计为不达标
    if m.sum().item() == 0:
        return True, 1.0, 0.0
    abs_err = (a[m] - g[m]).abs()                        # actual 为 inf/nan 处 abs_err=inf/nan → 逐元素判 False 且拉高 max_abs
    matched_ratio = (abs_err <= (atol + rtol * g[m].abs())).float().mean().item()
    max_abs_error = abs_err.max().item()
    passed = (matched_ratio >= required_ratio) and (max_abs_error <= max_abs_limit)
    return passed, matched_ratio, max_abs_error

# ========== Golden 函数定义 ==========
def golden_{op}(input_data):
    # 根据算子数学公式实现
    pass

# ========== L0/L1：阻塞层（精度），失败打 [PRECISION_FAIL] 计入退出码 ==========
def _run_precision(level, shape, dtype, block):
    """L0/L1 单用例：通过打 [PRECISION_PASS]，失败打 [PRECISION_FAIL] 并返回 False。"""
    try:
        # 运行 kernel + golden 对比 → out, ref
        passed, ratio, max_abs = check_precision(out, ref, dtype)
        tag = "PASS" if passed else "FAIL"
        print(f"[PRECISION_{tag}] {level} shape={shape} dtype={dtype} "
              f"matched_ratio={ratio:.4f} max_abs={max_abs:.3e}")
        return passed
    except Exception as e:
        print(f"[PRECISION_FAIL] {level} shape={shape} dtype={dtype}: {e}")
        return False

# ========== L2：异常测试（负向，非阻塞）——非法输入应被拒绝 ==========
def _run_exception(name, fn):
    """L2 单用例：fn() 喂非法输入，期望被算子拒绝。
    抛异常 → [BOUNDARY_PASS]（正确拒绝）；未抛 → [BOUNDARY_WARN]（应拒绝却静默接受）。均非阻塞。"""
    try:
        fn()
    except Exception as e:
        print(f"[BOUNDARY_PASS] l2 {name}: 正确拒绝 ({type(e).__name__})")
        return
    print(f"[BOUNDARY_WARN] l2 {name}: 非法输入未被拒绝（静默接受）")

# ========== Boundary：边界/特殊值（精度，非阻塞）——合法极值需满足精度验收标准 ==========
def _run_boundary(name, dtype, fn):
    """Boundary 单用例：合法特殊值（INF/NAN/极值/空 tensor），fn() 返回 (out, ref)。
    按精度验收标准比对（check_precision，与 L0/L1 同一套 dtype 阈值）：
    精度过 → [BOUNDARY_PASS]；精度不过或抛异常 → [BOUNDARY_WARN]。均非阻塞，不计入退出码。"""
    try:
        out, ref = fn()
        passed, ratio, max_abs = check_precision(out, ref, dtype)
        tag = "PASS" if passed else "WARN"
        print(f"[BOUNDARY_{tag}] boundary {name} dtype={dtype} "
              f"matched_ratio={ratio:.4f} max_abs={max_abs:.3e}")
    except Exception as e:
        print(f"[BOUNDARY_WARN] boundary {name} dtype={dtype}: {e}")

# ========== L0 测试：门槛测试（规则 shape，block 整除）==========
def test_{op}_l0():
    """L0 门槛测试：快速冒烟（来自 DESIGN.md §9.2 L0 计划）。返回是否全过。"""
    test_configs = [
        ("float16", {shape}, {block}),
        ("float32", {shape}, {block}),
    ]
    ok = True
    for dtype, shape, block in test_configs:
        ok &= _run_precision("l0", shape, dtype, block)
    return ok

# ========== 覆盖标注（机器可校验，详见 references/coverage-matrix.md）==========
# 每条 L1 用例带 tags=命中的覆盖维度 ID；coverage_check.py 反查命中集合。
# (shape, dtype, block, value_range, tags)
L1_CASES = [
    ((512, 512),        "float16",  {block}, (-1, 1),   ["D-DTYPE-fp16","D-SHAPE-ALIGNED","D-VALRANGE-S"]),
    ((512, 512),        "float32",  {block}, (-10, 10), ["D-DTYPE-fp32","D-SHAPE-ALIGNED","D-VALRANGE-M"]),
    ((512, 512),        "bfloat16", {block}, (-1, 1),   ["D-DTYPE-bf16","D-SHAPE-ALIGNED"]),
    ((513, 512),        "float16",  {block}, (-1, 1),   ["D-SHAPE-TAIL-1"]),           # 余数1
    ((512+64, 512+64),  "float16",  {block}, (-1, 1),   ["D-SHAPE-TAIL-MID"]),         # 中间余数
    ((509, 503),        "bfloat16", {block}, (-1, 1),   ["D-SHAPE-PRIME"]),            # 质数非对齐
    ((1, 512),          "float16",  {block}, (-1, 1),   ["D-SHAPE-EDGE"]),             # 退化
    ((512, 512),        "float16",  {block}, (-50, 50), ["D-VALRANGE-L"]),             # 大值域
    ((512, 512),        "float16",  {block}, (-5, 10),  ["D-VALRANGE-ASYM"]),          # 非对称
]
# 覆盖汇总（coverage_check.py 与上面 tags 二选一，建议同时给出便于核对）
COVERAGE_MANIFEST = {}      # 由 tags 自动汇总，或手填各维度计数
COVERAGE_NA = {}            # 合理缺失的豁免：{"D-SPECIAL-INF": "纯整数算子无浮点特殊值"}

# ========== L1 测试：功能测试（确定性非对齐 shape，见 §6）==========
def test_{op}_l1():
    """L1 功能测试：参数组合覆盖，⭐ 强制含尾块/质数 shape。返回是否全过。"""
    ok = True
    for shape, dtype, block, vrange, tags in L1_CASES:
        ok &= _run_precision("l1", shape, dtype, block)  # 可用 vrange 控制输入分布
    return ok

# ========== L2 测试：异常测试（负向，非阻塞）——非法输入应被拒绝 ==========
def test_{op}_l2():
    """L2 异常测试：不支持的 dtype / 非法 shape 应被算子拒绝。
    正确抛异常 = PASS，静默接受 = WARN。仅记录，不阻塞。"""
    _run_exception("unsupported_dtype", lambda: ...)  # 喂不支持的 dtype，期望报错
    _run_exception("illegal_shape",     lambda: ...)  # 喂非法 shape，期望报错

# ========== Boundary 测试：边界/特殊值（精度，非阻塞）==========
def test_{op}_boundary():
    """Boundary 测试：INF/NAN/极值/空 tensor（合法输入），按精度验收标准比对；
    精度不过打 [BOUNDARY_WARN]，不阻塞。每个 lambda 造特殊值输入 → 跑 kernel + golden → 返回 (out, ref)。"""
    _run_boundary("inf",   {dtype}, lambda: ...)  # 造含 inf 输入 → (out, ref)
    _run_boundary("nan",   {dtype}, lambda: ...)  # 造含 nan 输入 → (out, ref)
    _run_boundary("empty", {dtype}, lambda: ...)  # 造空 tensor 输入 → (out, ref)

# ========== 主函数：--level 分发 + 退出码 ==========
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--level", default="all",
                        choices=["l0", "l1", "l2", "boundary", "all"])
    args = parser.parse_args()

    tilelang.disable_cache()
    torch.manual_seed(0)

    blocking_ok = True  # 仅 L0/L1 计入退出码
    if args.level in ("l0", "all"):
        blocking_ok &= test_{op}_l0()
    if args.level in ("l1", "all"):
        blocking_ok &= test_{op}_l1()
    if args.level in ("l2", "all"):
        test_{op}_l2()         # 非阻塞
    if args.level in ("boundary", "all"):
        test_{op}_boundary()   # 非阻塞

    if blocking_ok:
        print("Test Passed!")  # L0/L1 全过；bench_test.sh 据此判定
        sys.exit(0)
    sys.exit(1)

if __name__ == "__main__":
    main()
```

> **导入**：`test_{op}.py` 顶部需 `import argparse, os, sys`（连同 `tilelang` / `torch`），并 `sys.path.insert(0, ...)` + `from {op} import {op}` 导入 kernel。**kernel 定义在 `{op}.py`，测试文件不含 kernel。**
> **场景 B 扩展时**：保留 generate 生成的 `main` 分发器与 `--level` 接口不变，仅把 `test_{op}.py` 里 `test_{op}_l1/l2/boundary` 的桩体替换为上述真实实现（见 §4.2）；**不改 `{op}.py`**。

---

### 9.2 关键设计要点

| 要点 | 说明 |
|------|------|
| **精度标准** | 混合容差：按 **dtype** 取 (atol, rtol, max_abs_error_limit, required_matched_ratio)，与算子类别无关；整型 0 误差精确匹配（详见 references/precision-standard.md） |
| **Golden 函数** | 根据数学公式实现，可用 PyTorch 标准实现 |
| **L0 测试** | 规则 shape，快速冒烟（≤10 用例） |
| **L1 测试** | 规则 + 不规则 shape，自然包含尾块（100-200 用例） |
| **L2 测试** | 负向测试：非法 dtype / shape 应被拒绝——**正确抛异常 = PASS，静默接受 = WARN**；用 `_run_exception`，不比精度（无合法 golden），≤20 用例，非阻塞 |
| **Boundary 测试** | 合法特殊值（INF/NAN/极值/空 tensor）——用 `_run_boundary` 跑 kernel+golden，**按精度验收标准（check_precision）比对，精度不过 = WARN**，≤10 用例，非阻塞 |
| **分层标记** | L0/L1 → `[PRECISION_PASS]`/`[PRECISION_FAIL]`（阻塞，计入退出码）；L2/Boundary → `[BOUNDARY_PASS]`/`[BOUNDARY_WARN]`（非阻塞，不改退出码） |
| **退出码** | L0/L1 全过 → 打印 `"Test Passed!"` 且 `exit(0)`；L0/L1 任一失败 → `exit(1)`；L2/Boundary 失败不影响退出码 |
| **--level 分发** | main 支持 `--level {l0,l1,l2,boundary,all}`；精度收敛跑 `l0`，扩展后跑 `all` |
| **异常隔离** | L2 用 `_run_exception`（期望拒绝，抛异常 = PASS）、Boundary 用 `_run_boundary`（比精度，精度不过 = WARN）；两者都 `try/except` 包裹、非阻塞、失败后继续，不得中断后续用例 |
| **覆盖标注** | 每条 L1 用例带 `tags=`（命中的 `D-*` 维度 ID）；文件含 `COVERAGE_MANIFEST` / `COVERAGE_NA`。无标注 → checker 判 MISS |
| **覆盖门禁** | 扩展完成后必须跑 `scripts/coverage_check.py test_{op}.py`；任一**强制维度** MISS → 退出码 1，等同自检失败，须补齐用例后再判 `[PRECISION_PASS]`（见 §10.1） |

---

## 10. 覆盖门禁与总结

### 10.1 覆盖自检门禁（强制步骤）

生成 / 扩展用例后，**必须**执行覆盖自检，确保"skill 描述的每类场景"真正落进了 `test_{op}.py`：

```
步骤 1：判定应覆盖维度
    └─ 用 references/operator-category.md 判出算子类别
    └─ 查 references/coverage-matrix.md 第二节得到「强制维度集」
    └─ 结合 proto.yaml 的 dtype/attr/shape 范围实例化各维度最小数量

步骤 2：生成带标注的用例
    └─ 每条 L1 用例带 tags（命中的 D-* 维度 ID）
    └─ 写 COVERAGE_MANIFEST（计数）+ COVERAGE_NA（合理缺失 + 理由）
    └─ shape 集合遵循 §6 确定性生成（非对齐必出）

步骤 3：跑 checker
    └─ python scripts/coverage_check.py examples/{op}/test_{op}.py --proto examples/{op}/proto.yaml
    └─ 打印逐维度 PASS / MISS / N/A 覆盖矩阵

步骤 4：判定
    └─ 任一【强制维度】MISS（未豁免，或对强制项写了豁免）→ 退出码 1
       视为自检失败：补齐缺失维度的用例 → 重跑 checker，直至全 PASS/N/A
    └─ 全 PASS / N/A → 退出码 0，方可交付 / 报 [PRECISION_PASS]
```

> **与 orchestrator 衔接**：场景 B（developer agent Stage 2 扩展 L1/L2/Boundary）完成后，覆盖门禁与 `[PRECISION_PASS]` 并列为交付前置条件——覆盖矩阵有未豁免 MISS 时不得返回 `[PRECISION_PASS]`。详见 developer agent「分层测试与扩展流程」与 AGENTS.md Stage 2 门禁。

### 10.2 总结

#### 核心要点

1. **支持多种场景**：不只是 design.md，还支持 examples/{op}/*.py、用户描述、测试分析
2. **算子类别划分依据科学**：基于硬件特性、计算步骤、数学公式三个维度
3. **算子类别识别方法正确**：理解实现逻辑后判断
4. **覆盖从"描述性"转"契约式"**：非对齐等场景由 §6 确定性生成 + 覆盖矩阵强制 + checker 门禁三重保证，杜绝"漏场景"

#### 技能文件结构

```
tilelang-op-test-design/
├── SKILL.md                    # 主文档（多场景 + 判断 + 覆盖门禁）
├── scripts/
│   └── coverage_check.py       # 覆盖自检 checker（应覆盖 vs 实际覆盖）
└── references/
    ├── operator-category.md    # 算子类别划分依据（详细）
    ├── precision-standard.md   # 精度标准体系
    └── coverage-matrix.md      # 测试覆盖矩阵（强制契约：维度 ID / 谓词 / 最小数量）
```

**说明**：
- SKILL.md 包含完整方法论、测试代码结构示例（§9）、覆盖门禁（§10.1）
- references/operator-category.md 提供算子类别划分详细说明
- references/precision-standard.md 提供混合容差精度标准体系（按 dtype 的 atol/rtol/max_abs_error_limit/required_matched_ratio；整型 0 误差精确匹配）
- references/coverage-matrix.md 提供覆盖维度强制契约，是 coverage_check.py 的判定依据
