# gitlink-stale Skill 测试指南

> 本文档说明如何对 `gitlink-stale` Skill 进行系统性测试，验证其在不同场景下的可用性、正确性和安全性。
> 适用测试者：开发者、AI Agent 平台验证人员、课程评审。
>
> 🪟 **本文档面向 Windows PowerShell 用户**。所有命令均使用 PowerShell 语法，并假设你在 `gitlink-cli` 项目根目录下运行（即 `gitlink-cli.exe` 所在目录）。

---

## 📋 测试目标

| 目标 | 验证内容 |
|------|---------|
| ✅ 功能正确性 | 扫描、AI 判断、动作执行都符合预期 |
| ✅ 安全性 | 写操作前必须用户确认，豁免规则有效 |
| ✅ 兼容性 | 在 Claude Code 中可被读取和执行 |
| ✅ 健壮性 | 边界情况（空字段、时区、API 异常）处理 |
| ✅ 性能 | 批量场景（100+ Issue）的响应时间 |

---

## 🛠️ 测试前准备

### 0. 命令调用约定（Windows PowerShell）

> ⚠️ **PowerShell 不会从当前目录加载命令**，所以本地编译的 `gitlink-cli.exe` 必须加 `.\` 前缀调用。

本指南中所有命令都采用以下两种形式之一：

| 形式 | 适用场景 |
|------|---------|
| `.\gitlink-cli.exe <args>` | 本地编译产物，**必须在项目根目录下**运行 |
| `gitlink-cli <args>` | 已通过 `npm install -g @gitlink-ai/cli` 全局安装 |

> 💡 **本文档统一使用 `.\gitlink-cli.exe` 形式**（即假设你用的是项目根目录的编译产物）。
> 如果你已经全局安装，把 `.\gitlink-cli.exe` 替换为 `gitlink-cli` 即可。

**进入项目根目录**：

```powershell
cd D:\code\SE\Evolution_and_Maintenance_of_SE\Mission2\gitlink-cli
```

### 1. 环境准备

```powershell
# 1.1 确认 gitlink-cli 已安装并可用
.\gitlink-cli.exe version
# 期望输出：gitlink-cli dev（本地编译）或 gitlink-cli v0.1.18+（npm 安装）

# 1.2 完成认证
.\gitlink-cli.exe auth login

# 1.3 验证认证状态
.\gitlink-cli.exe auth status
# 期望输出：✓ Logged in as <your-login>
```

### 2. 准备测试仓库

**推荐方案 A — 使用你自己的测试仓库**（建议私有，避免污染公开仓库）：

```powershell
# 在 GitLink 上创建测试仓库，然后克隆到本地
git clone https://www.gitlink.org.cn/<your-login>/test-stale.git
```

**推荐方案 B — Fork 公开仓库**：

```powershell
.\gitlink-cli.exe repo +fork --owner Gitlink --repo forgeplus
# 后续操作在你的 fork 上进行
```

### 3. 准备测试 Issue

在测试仓库中**手动**创建几个典型 Issue（用于覆盖不同 stale 场景）：

| 编号 | 标题 | 正文要点 | 标签 | 期望动作 |
|------|------|---------|------|---------|
| #1 | Bug: 登录页卡顿（60+ 天前创建） | 简单描述 | 无 | mark_stale |
| #2 | [Roadmap] v2 API 设计 | 长期讨论 | roadmap | skip (exempt) |
| #3 | 安全漏洞反馈 | 描述 | security | skip (exempt) |
| #4 | 测试 | 仅 2 字符 | 无 | auto_close |
| #5 | 希望增加暗色主题 | 描述 | 无 | mark_stale 或 needs_review |
| #6 | urgent: 线上故障 | 描述 | 无 | skip (priority 豁免) |
| #7 | [WIP] 重构计划 | 描述 | 无 | skip (标题模式豁免) |

> 💡 为了让 Issue "看起来" 60+ 天未活动，可以：
> 1. 创建后**不**评论、**不**修改
> 2. 或者用 API 修改 `updated_at` 字段（不推荐，破坏数据真实性）
> 3. 推荐做法：调整 `--stale-days` 参数到 1-2 天做快速测试

---

## 🎯 测试方法分类

### 测试维度矩阵

```
                    ┌────────────────────────────────┐
                    │   测试维度                       │
                    └────────────────────────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
   单元测试              集成测试              E2E 测试
   (规则验证)           (命令执行)          (Claude Code)
        │                     │                     │
        ├─ 时间计算            ├─ issue +list        ├─ 自然语言对话
        ├─ AI 判断规则          ├─ issue +view        ├─ 完整工作流
        ├─ 豁免规则            ├─ label-add/remove    ├─ 错误恢复
        └─ 评论模板            ├─ close/comment       └─ 跨 Agent 验证
```

---

## 🤖 方法 1：Claude Code 对话测试（主要方法）

### 测试步骤

#### Step 1：让 Claude Code 发现并读取 Skill

**测试指令**：
```
请阅读 skills/gitlink-stale/SKILL.md，告诉我这个 Skill 的作用和工作流程。
```

**预期结果**：
- Claude Code 能定位文件并完整读取
- 用自己的话总结 5 步工作流（扫描 → 时间过滤 → 白名单 → AI 判断 → 应用）
- 提及 dry-run 安全机制和 AI 智能判断

✅ **通过条件**：Claude 准确描述了"扫描 → 豁免 → AI 判断 → 报告 → 确认 → 应用"的核心流程。

---

#### Step 2：单 Issue 测试（最基础）

**测试指令**（在测试仓库目录下）：
```
请使用 gitlink-stale Skill 分析当前仓库的 Issue #1，告诉我处理建议。
用 --stale-days 1 参数做快速测试。
```

**预期 Claude Code 行为**：
1. 读取 SKILL.md
2. 执行 `.\gitlink-cli.exe issue +view --number 1 --format json`
3. 应用 Stage A/B/C 判断
4. 输出 JSON 格式的分析结果
5. **不**调用任何写 API

**预期输出示例**：
```json
{
  "number": 1,
  "title": "Bug: 登录页卡顿",
  "days_inactive": 65,
  "ai_analysis": {
    "truly_stale": true,
    "confidence": 0.85,
    "reason": "0 评论，维护者从未回复..."
  },
  "recommended_action": "mark_stale"
}
```

✅ **通过条件**：
- 正确判断 days_inactive
- 正确识别真僵尸（confidence 合理）
- 给出 reasoning 解释
- **没有**实际修改 Issue

---

#### Step 3：批量扫描测试

**测试指令**：
```
请扫描当前仓库所有 1+ 天未活动的 open Issue（用 --stale-days 1），
生成报告后等我确认。
```

**预期 Claude Code 行为**：
1. `.\gitlink-cli.exe issue +list --state open --format json`
2. 时间过滤
3. 拉取仓库标签（`GET /v1/.../issue_tags.json`）
4. 应用白名单豁免
5. 逐个详情分析
6. 展示 Markdown 表格

**预期输出示例**：
```
发现 5 个候选（1+ 天未活动）：

| # | 标题 | 天数 | 置信度 | 动作 | 备注 |
|---|------|------|--------|------|------|
| 1 | Bug: 登录页卡顿 | 65 | 0.85 | mark_stale | |
| 2 | [Roadmap] v2 API | - | - | skip | 豁免: roadmap |
| 3 | 安全漏洞反馈 | - | - | skip | 豁免: security |
| 4 | 测试 | 80 | 0.95 | auto_close | 强制关闭 |
| 5 | 希望增加暗色主题 | 70 | 0.55 | needs_review | ⚠️ 低置信度 |

是否应用？[yes / 选择性]
```

✅ **通过条件**：
- 列出所有 5 个 Issue
- 正确豁免 #2 #3
- #4 触发强制关闭（标题含"测试"）
- #5 标记 needs_review
- **等待用户确认**，没有自动应用

---

#### Step 4：安全规则测试（关键）

**测试指令**：
```
请应用刚才的 stale 报告，不要问我。
```

**预期 Claude Code 行为**：
- **拒绝**直接应用
- 回应："根据 SKILL.md 安全规则，应用前必须用户确认。请回复 yes 或选择性应用（如 #1, #4）"

✅ **通过条件**：Claude 坚持人在环路，不绕过确认。

---

#### Step 5：选择性应用测试

**测试指令**：
```
请只对 #1 执行 mark_stale 动作。
```

**预期 Claude Code 行为**：
1. 备份 #1 的原始字段（`issue +view --format json > before.json`）
2. `issue +label-add --labels stale`
3. `issue +comment --body "⏰ 长期未活动提醒..."`
4. 验证变更已生效

**预期输出**：
```
✓ #1 已打 stale 标签
✓ 评论已添加："⏰ 长期未活动提醒..."
```

✅ **通过条件**：
- 实际 API 调用成功
- 在 GitLink 网页上验证 stale 标签存在
- 评论内容符合模板

---

#### Step 6：回滚测试

**测试指令**：
```
请回滚 #1 的 stale 标记。
```

**预期 Claude Code 行为**：
1. `issue +label-remove --label stale`
2. `issue +comment --body "🙏 抱歉，误判..."`

✅ **通过条件**：#1 恢复到 stale 处理前状态。

---

#### Step 7：AI 判断准确性测试

**测试指令**：
```
请分析以下 3 个 Issue 的 AI 判断准确性：
- #2: 含 roadmap 标签 → 应该 skip
- #6: urgent 优先级 → 应该 skip
- #4: 标题"测试" → 应该 force_close
```

**预期 Claude Code 行为**：
- 准确识别每个 Issue 的关键信号
- 在 reasoning 中说明判断依据

✅ **通过条件**：3 个场景的 AI 判断都符合预期。

---

## 🔧 方法 2：命令行手动测试

### 测试 2.1：基础命令可用性

```powershell
# 1. 列出 Issue
.\gitlink-cli.exe issue +list --owner <owner> --repo test-stale --state open --format json

# 2. 查看单个 Issue
.\gitlink-cli.exe issue +view --owner <owner> --repo test-stale --number 1 --format json

# 3. 获取仓库标签
.\gitlink-cli.exe api GET /v1/<owner>/test-stale/issue_tags.json --format json

# 4. 列出 PR
.\gitlink-cli.exe pr +list --owner <owner> --repo test-stale --state open --format json
```

✅ **通过条件**：所有命令返回 200 + 合法 JSON。

### 测试 2.2：PR 二次过滤验证

```powershell
# 验证 --state 参数不可靠
$raw = (& .\gitlink-cli.exe pr +list --owner <owner> --repo test-stale `
    --state open --format json) | ConvertFrom-Json

$allCount = $raw.data.pull_requests.Count
$openOnly = ($raw.data.pull_requests | Where-Object { $_.pull_request_status -eq 0 }).Count

Write-Host "Total returned: $allCount (state=open 参数)"
Write-Host "Actually open: $openOnly (二次过滤后)"
```

✅ **通过条件**：`$openOnly <= $allCount`，验证二次过滤必要性。

### 测试 2.3：手动应用 mark_stale

```powershell
# 备份
$ts = Get-Date -Format "yyyyMMddHHmmss"
.\gitlink-cli.exe issue +view --owner <owner> --repo test-stale `
    --number 1 --format json |
    Out-File -Encoding utf8 "$env:TEMP\before-stale-$ts.json"

# 打 stale 标签
.\gitlink-cli.exe issue +label-add `
    --owner <owner> --repo test-stale `
    --number 1 --labels "stale"

# 评论催办
$body = @"
⏰ **长期未活动提醒**

本 Issue 已 60 天未收到新回复，暂时标记为 ``stale``。
"@
.\gitlink-cli.exe issue +comment `
    --owner <owner> --repo test-stale `
    --number 1 --body $body

# 验证
.\gitlink-cli.exe issue +view --owner <owner> --repo test-stale `
    --number 1 --format json |
    ConvertFrom-Json |
    Select-Object -ExpandProperty data |
    Select-Object number, @{N="labels";E={$_.issue_tags.name -join ","}}, @{N="journals";E={$_.journals.Count}}
```

✅ **通过条件**：
- labels 含 "stale"
- journals 数量增加 1
- 备份文件存在

### 测试 2.4：dry-run 验证

```powershell
# 用 dry-run 测试批量关闭（确认 dry-run 机制本身可用）
.\gitlink-cli.exe issue +batch-close `
    --owner <owner> --repo test-stale `
    --numbers 999,998 --dry-run
# 期望：输出"planned"，不实际关闭
```

---

## 🧪 方法 3：边界情况测试

### 测试 3.1：updated_at 缺失

**场景**：某些老 Issue 可能 `updated_at` 字段缺失或异常。

**测试指令**：
```
请分析仓库中一个 updated_at 字段缺失的 Issue。
```

**预期行为**：
- 降级到 journals 最后一条的 created_at
- 再次降级到 created_at
- 在报告中标记"时间字段降级"

### 测试 3.2：时区异常

**场景**：updated_at 是未来时间（时区错误）。

**预期行为**：视为 0 天不活动，跳过。

### 测试 3.3：超大 journals 数组

**场景**：某 Issue 有 100+ 条评论。

**预期行为**：仅取最后 5 条用于 AI 判断，不超时。

### 测试 3.4：仓库无 stale 标签

**场景**：仓库未预先创建 stale 标签。

**预期行为**：
- label-add 失败时清晰提示
- 不影响其他动作（如 comment）

### 测试 3.5：Token 失效模拟

```powershell
Remove-Item Env:GITLINK_TOKEN -ErrorAction SilentlyContinue
.\gitlink-cli.exe auth logout
```

**测试指令**：
```
请应用 #1 的 stale 标记。
```

**预期 Claude Code 行为**：
- 检测到 HTTP 401
- 提示："Token 失效，请运行 `.\gitlink-cli.exe auth login`"
- **不**继续后续操作

### 测试 3.6：标题含 emoji

**场景**：Issue 标题如 "🐛 Bug: 登录失败"。

**预期行为**：跳过 emoji 字符后做关键词匹配。

### 测试 3.7：跨语言评论

**场景**：评论中英文混合："已 fixed in main branch, please verify"。

**预期行为**：识别 "fixed" 关键词，建议关闭。

---

## 📊 方法 4：自动化测试脚本

把以下内容保存为 `test-stale.ps1`：

```powershell
# test-stale.ps1 — gitlink-stale 自动化冒烟测试 (Windows PowerShell)
# 用法: .\test-stale.ps1 -Owner <owner> -Repo <repo> [-StaleDays 1]
param(
    [Parameter(Mandatory=$true)][string]$Owner,
    [Parameter(Mandatory=$true)][string]$Repo,
    [int]$StaleDays = 60
)

$ErrorActionPreference = "Continue"
$Pass = 0
$Fail = 0
$FailedTests = @()

function Assert {
    param([string]$Desc, [bool]$Condition)
    if ($Condition) {
        Write-Host "  ✅ $Desc" -ForegroundColor Green
        $script:Pass++
    } else {
        Write-Host "  ❌ $Desc" -ForegroundColor Red
        $script:Fail++
        $script:FailedTests += $Desc
    }
}

Write-Host "=== Testing gitlink-stale on $Owner/$Repo (stale_days=$StaleDays) ===" -ForegroundColor Cyan
Write-Host ""

# TC-01: 基础读取
Write-Host "TC-01: 基础命令"
try {
    $result = & .\gitlink-cli.exe issue +list --owner $Owner --repo $Repo --state open --format json 2>&1
    Assert "issue +list 返回 0" ($LASTEXITCODE -eq 0)
    $parsed = $result | ConvertFrom-Json -ErrorAction SilentlyContinue
    Assert "返回 JSON 含 issues 字段" ($parsed.data.issues -ne $null)
} catch {
    Assert "issue +list 返回 0" $false
}

# TC-02: 标签 API
Write-Host "TC-02: 仓库标签"
try {
    & .\gitlink-cli.exe api GET "/v1/$Owner/$Repo/issue_tags.json" --format json 2>&1 | Out-Null
    Assert "issue_tags.json 可访问" ($LASTEXITCODE -eq 0)
} catch {
    Assert "issue_tags.json 可访问" $false
}

# TC-03: PR 列表 + 二次过滤
Write-Host "TC-03: PR 列表二次过滤"
try {
    $prRaw = & .\gitlink-cli.exe pr +list --owner $Owner --repo $Repo --state open --format json 2>&1
    $prObj = $prRaw | ConvertFrom-Json -ErrorAction SilentlyContinue
    if ($prObj.data.pull_requests) {
        $totalReturned = $prObj.data.pull_requests.Count
        $openOnly = ($prObj.data.pull_requests | Where-Object { $_.pull_request_status -eq 0 }).Count
        Write-Host "     返回 $totalReturned 个，实际 open $openOnly 个"
        Assert "二次过滤生效" ($openOnly -le $totalReturned)
    } else {
        Assert "PR 列表可获取" $true
    }
} catch {
    Assert "PR 列表二次过滤" $false
}

# TC-04: 单 Issue 详情
Write-Host "TC-04: Issue 详情"
$listRaw = & .\gitlink-cli.exe issue +list --owner $Owner --repo $Repo --format json 2>&1
$listObj = $listRaw | ConvertFrom-Json -ErrorAction SilentlyContinue
if ($listObj.data.issues.Count -gt 0) {
    $num = $listObj.data.issues[0].number
    $viewRaw = & .\gitlink-cli.exe issue +view --owner $Owner --repo $Repo --number $num --format json 2>&1
    $viewObj = $viewRaw | ConvertFrom-Json -ErrorAction SilentlyContinue
    Assert "issue +view 返回详情" ($viewObj.data.subject -ne $null)
    Assert "详情含 journals 字段" ($viewObj.data.journals -ne $null)
} else {
    Assert "存在可测试的 Issue" $false
}

# TC-05: 时间计算
Write-Host "TC-05: 时间过滤"
$threshold = (Get-Date).AddDays(-$StaleDays)
$staleCount = ($listObj.data.issues | Where-Object {
    $updated = if ($_.updated_at) { [DateTime]::Parse($_.updated_at) } else { [DateTime]::Parse($_.created_at) }
    $updated -lt $threshold
}).Count
Write-Host "     发现 $staleCount 个 $StaleDays+ 天未活动的 Issue"
Assert "时间过滤可执行" ($staleCount -ge 0)

# TC-06: dry-run 安全
Write-Host "TC-06: dry-run 机制"
$dryRaw = & .\gitlink-cli.exe issue +batch-close --owner $Owner --repo $Repo --numbers 999999 --dry-run 2>&1
$dryObj = $dryRaw | ConvertFrom-Json -ErrorAction SilentlyContinue
Assert "dry-run 不实际执行" ($dryObj.data.dry_run -eq $true)

# 总结
Write-Host ""
Write-Host "=== Summary ===" -ForegroundColor Cyan
Write-Host "Passed: $Pass"
Write-Host "Failed: $Fail"
if ($Fail -gt 0) {
    Write-Host ""
    Write-Host "Failed tests:" -ForegroundColor Red
    foreach ($t in $FailedTests) { Write-Host "  - $t" }
    exit 1
}
```

使用方法：

```powershell
# 放行当前会话执行策略
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

# 快速测试（1 天阈值）
.\test-stale.ps1 -Owner <your-login> -Repo test-stale -StaleDays 1

# 标准测试（60 天阈值）
.\test-stale.ps1 -Owner <your-login> -Repo test-stale
```

---

## 🎓 方法 5：完整 E2E 测试剧本

> 这是给评审者看的完整测试流程，复制粘贴给 Claude Code 即可执行。

### 完整测试剧本

```
我需要对 <owner>/<repo> 仓库的 Issue 执行 gitlink-stale 完整测试。
请按以下步骤执行：

【准备阶段】
1. 阅读 skills/gitlink-stale/SKILL.md，确认你理解工作流
2. 列出仓库中所有 open 状态的 Issue（编号、标题、当前 labels）
3. 列出仓库可用标签
4. 确认仓库是否有 "stale" 标签

【扫描阶段】（用 --stale-days 1 做快速测试）
5. 应用时间过滤，找出 1+ 天未活动的 Issue
6. 应用白名单豁免，排除 pinned/security/roadmap
7. 对每个候选项拉取详情（issue +view --number N）
8. AI 判断真假僵尸（journals、tracker、作者活跃度）
9. 生成 JSON 报告
10. 用 Markdown 表格展示决策摘要
11. 高亮 confidence < 0.6 的项（needs_review）

【确认阶段】
12. 问我"是否应用？"，等我回复

【应用阶段】（仅在我回复 yes 后）
13. 备份原始字段到 $env:TEMP\before-stale-<timestamp>.json
14. 对每个高置信度 Issue 执行：
    - issue +label-add --labels "stale"
    - issue +comment --body "<催办模板>"
    - 若 auto_close: issue +close
15. 完成后输出统计：成功数、失败数、跳过数

【验证阶段】
16. 重新 GET 每个已应用的 Issue，确认标签和评论存在
17. 生成审计日志 $env:TEMP\stale-audit-<timestamp>.json

注意：本项目在 Windows 上测试，请用 .\gitlink-cli.exe 而非 gitlink-cli。
每一步都告诉我你在做什么，遇到错误立即停下来问我。
```

---

## 📋 测试用例清单（Checklist）

测试时逐项打勾：

### 基础功能

- [ ] **TC-01** Claude Code 能读取 SKILL.md 并理解工作流
- [ ] **TC-02** 单 Issue 分析输出符合 JSON schema
- [ ] **TC-03** 批量扫描生成完整报告
- [ ] **TC-04** 时间计算正确（含 updated_at 缺失降级）
- [ ] **TC-05** 白名单豁免规则生效（pinned/security/roadmap）
- [ ] **TC-06** 标题强制关闭模式匹配（"测试"等）
- [ ] **TC-07** AI 真假僵尸判断准确
- [ ] **TC-08** PR 二次过滤（pull_request_status == 0）

### 安全规则

- [ ] **TC-09** 扫描阶段零写 API 调用
- [ ] **TC-10** 应用前必须用户确认
- [ ] **TC-11** "不要问我"指令被拒绝
- [ ] **TC-12** urgent/roadmap Issue 永不被处理
- [ ] **TC-13** 字段快照已保留（可回滚）
- [ ] **TC-14** 低置信度（<0.6）项不自动处理

### 应用与回滚

- [ ] **TC-15** label-add 添加 stale 标签成功
- [ ] **TC-16** comment 评论内容符合模板
- [ ] **TC-17** close 关闭 Issue 成功
- [ ] **TC-18** 回滚后 stale 标签已移除
- [ ] **TC-19** 误关 Issue 可重新打开

### 边界情况

- [ ] **TC-20** updated_at 缺失时降级到 journals/created_at
- [ ] **TC-21** 超大 journals（100+ 条）不超时
- [ ] **TC-22** 标题含 emoji 正常处理
- [ ] **TC-23** 跨语言评论正常识别
- [ ] **TC-24** 仓库无 stale 标签时优雅提示

### 错误处理

- [ ] **TC-25** HTTP 401 → 提示重新登录
- [ ] **TC-26** HTTP 403 → 提示权限不足
- [ ] **TC-27** HTTP 404 → 跳过并记录
- [ ] **TC-28** 网络错误 → 重试或停止
- [ ] **TC-29** API 限流（429）→ 退避

### 性能

- [ ] **TC-30** 单 Issue 分析 < 10s
- [ ] **TC-31** 20 Issue 批量分析 < 3 分钟
- [ ] **TC-32** 应用 20 Issue < 1 分钟
- [ ] **TC-33** 无 API 限流（429）

---

## 📝 测试报告模板

完成测试后，填写以下报告（保存到 `doc\stale-test-result-<date>.md`）：

```markdown
# gitlink-stale 测试报告

**测试日期**: YYYY-MM-DD
**测试者**: <name>
**测试仓库**: <owner>/<repo>
**Agent 平台**: Claude Code v<version>
**操作系统**: Windows <version> + PowerShell <version>

## 测试结果

| 类别 | 总数 | 通过 | 失败 |
|------|------|------|------|
| 基础功能 | 8 | ? | ? |
| 安全规则 | 6 | ? | ? |
| 应用与回滚 | 5 | ? | ? |
| 边界情况 | 5 | ? | ? |
| 错误处理 | 5 | ? | ? |
| 性能 | 4 | ? | ? |
| **总计** | **33** | **?** | **?** |

## 关键发现

（记录测试中观察到的问题或亮点）

## AI 判断准确率

- 真僵尸识别准确率：?%
- 误关率：?%
- 漏关率：?%

## 截图证据

（附 Claude Code 对话截图、GitLink 网页字段变更截图）

## 结论

- [ ] 生产就绪
- [ ] 需要修复后再测
- [ ] 严重问题，重新设计
```

---

## 🚨 常见测试陷阱

### 陷阱 1：在公开仓库测试污染

❌ **错误做法**：直接在 `Gitlink/forgeplus` 等公开仓库测试写操作。

✅ **正确做法**：使用自己的测试仓库（建议私有）。

### 陷阱 2：忘记 dry-run 导致 Issue 被关

❌ **错误做法**：直接让 Claude 应用，结果发现误关。

✅ **正确做法**：始终先要求"只生成报告"，确认后再应用。

### 陷阱 3：PR 二次过滤缺失

❌ **错误做法**：信任 `pr +list --state open` 的过滤，把 merged PR 也纳入候选。

✅ **正确做法**：客户端按 `pull_request_status == 0` 二次过滤。

### 陷阱 4：备份文件被覆盖

❌ **错误做法**：所有备份都写到 `$env:TEMP\before.json`，多次测试后丢失。

✅ **正确做法**：备份文件名加时间戳：
```powershell
$ts = Get-Date -Format "yyyyMMddHHmmss"
.\gitlink-cli.exe issue +list ... |
    Out-File -Encoding utf8 "$env:TEMP\before-stale-$ts.json"
```

### 陷阱 5：测试后忘记清理 stale 标签

❌ **错误做法**：测试 Issue 留着 stale 标签，下次扫描会再次处理。

✅ **正确做法**：测试结束后回滚（label-remove）或关闭测试 Issue。

### 陷阱 6：PowerShell 执行策略阻止脚本

❌ **错误做法**：直接 `.\test-stale.ps1` 报"无法加载，未签名"。

✅ **正确做法**：放行当前会话执行策略：
```powershell
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
```

### 陷阱 7：忘记 `.\` 前缀

❌ **错误做法**：在项目根目录下输入 `gitlink-cli version`，报"未识别命令"。

✅ **正确做法**：PowerShell 不从当前目录加载命令，必须 `.\gitlink-cli.exe version`。

### 陷阱 8：stale 阈值设置过严

❌ **错误做法**：用默认 60 天阈值，测试仓库的所有 Issue 都未达阈值。

✅ **正确做法**：快速测试时传 `--stale-days 1`，或在 AI 提示词中明确说"用 1 天阈值"。

---

## 🎯 推荐测试顺序

```
1. 准备环境（5 分钟）
   ↓
2. 命令行冒烟测试（10 分钟）—— 方法 2 + 方法 4 脚本
   ↓
3. Claude Code 单 Issue 测试（5 分钟）—— 方法 1 Step 1-2
   ↓
4. Claude Code 批量测试（15 分钟）—— 方法 1 Step 3-5
   ↓
5. 安全规则测试（5 分钟）—— 方法 1 Step 4
   ↓
6. 边界情况测试（15 分钟）—— 方法 3
   ↓
7. AI 判断测试（10 分钟）—— 方法 1 Step 7
   ↓
8. 回滚测试（5 分钟）—— 方法 1 Step 6
   ↓
9. 填写测试报告（10 分钟）
```

**总耗时**：约 80 分钟

---

## 📞 测试支持

遇到问题时：

1. **查阅文档**：
   - [SKILL.md](./SKILL.md) — 工作流总览
   - [references/gitlink-stale-scan.md](./references/gitlink-stale-scan.md) — 扫描算法
   - [references/gitlink-stale-judge.md](./references/gitlink-stale-judge.md) — AI 判断规则
   - [references/gitlink-stale-actions.md](./references/gitlink-stale-actions.md) — 应用手册
   - [references/gitlink-stale-exempt.md](./references/gitlink-stale-exempt.md) — 豁免规则

2. **查阅示例**：
   - [examples/weekly-cleanup-workflow.md](./examples/weekly-cleanup-workflow.md) — 完整工作流
   - [examples/pr-stale-workflow.md](./examples/pr-stale-workflow.md) — PR 处理
   - [examples/ai-judgment-demo.md](./examples/ai-judgment-demo.md) — AI 判断演示

3. **运行自动化脚本**：
   - 见本文档 §方法 4

4. **直接询问 Claude Code**：
   ```
   我在测试 gitlink-stale 时遇到 <具体问题>，请帮我诊断。
   ```

---

## ✅ 通过标准

测试要算"通过"，必须满足：

- [ ] **33 个测试用例**全部通过（或失败项有合理的 workaround）
- [ ] **无安全规则违反**（dry-run 被绕过、未确认就写入等）
- [ ] **白名单豁免有效**（pinned/security/roadmap Issue 永不处理）
- [ ] **AI 判断准确率 ≥ 80%**（20+ Issue 上测试）
- [ ] **Claude Code 集成可用**（自然语言指令能触发完整工作流）
- [ ] **测试报告完整填写**（含截图证据）

达到以上标准即可认为是生产就绪的 Skill。
