Merge pull request 'feat(skill): beta 技能 diagnosing-bugs + 月度审阅与 evals 工具' (#19) from feat/diagnosing-bugs-and-review-tools into main
skill-gate / gate (push) Waiting to run

feat(skill): beta 技能 diagnosing-bugs + 月度审阅与 evals 工具
This commit was merged in pull request #19.
This commit is contained in:
2026-10-31 21:34:04 +00:00
11 changed files with 224 additions and 4 deletions
+7
View File
@@ -53,3 +53,10 @@
- 补齐剩余 24 个技能(dev 类为主)的 `evals/evals.json`(各 3 条)与 `docs/skills/<name>.md`(四段式)。
- `--coverage`:40 个 promoted+model-invoked 技能的 evals 与文档缺口 **24 → 0**。
### 继续推进(2026-11-01)
- 新增 beta 技能 `diagnosing-bugs`(难查 bug 诊断纪律:先建红循环再推理),补齐 evals 与四段式文档;路由表同步。
- 新增 `scripts/monthly-review.sh`:一条命令跑月度审阅(覆盖率 / 扫描 / 第三方 / catalog / description 异常)。
- 新增 `scripts/evals-status.py` 与 `reports/evals/TEMPLATE.md`:evals 覆盖率与回归报告模板。
- `skill-creator` 实战记录 #1:用标准流程新建 `diagnosing-bugs`(beta,待观察后晋升)。
+3 -2
View File
@@ -25,7 +25,8 @@
- 范围:上周改过的技能 + 3 个高风险技能(`dev-coding`、`dev-review`、`req-design`)。
- 每技能取 1 条关键用例,做「有技能 / 无技能」对比,按 rubric 打分。
- 结果记录到 `reports/evals/YYYY-Www.md`,进周报。
- 结果记录到 `reports/evals/YYYY-Www.md`(模板 `reports/evals/TEMPLATE.md`),进周报。
- 用 `python3 scripts/evals-status.py` 看哪些技能已有 evals、哪些已有回归报告。
- 连续两次无增量的技能 → 按 `SCOPE.md` 评估降级。
- 不做全量(61 技能 × 3 用例成本过高);全量只在治理大改时做。
@@ -34,7 +35,7 @@
- 两台机器 `--audit` 漂移必须为 0(beta/deprecated 除外)。
- 审 `catalog.json`:`description` 长度 <80 或 >600 的标黄;含「各种 / 等等 / 相关」这类泛化词的标出。
- 第三方技能(arkcli 等)有变动时,评估是否影响团队技能;跑一次 `./scripts/scan-installed.sh`。
- 跑 `python3 scripts/validate-skills.py --coverage`:报告缺 evals / 缺四段式文档的技能,按 `SCOPE.md` 的覆盖率路线图推进。
- 跑 `./scripts/monthly-review.sh` 一次出齐:覆盖率、本仓库扫描、第三方扫描、catalog 一致性、description 异常项。
## 每季度首月 1 日 10:30 — 治理复核
+16 -2
View File
@@ -7,13 +7,14 @@
"missing_evals": [],
"missing_docs": []
},
"generated_at": "2026-10-31T21:19:23Z",
"total": 61,
"generated_at": "2026-10-31T21:33:50Z",
"total": 62,
"counts": {
"promoted/user-invoked": 18,
"deprecated/user-invoked": 1,
"promoted/model-invoked": 40,
"beta/user-invoked": 1,
"beta/model-invoked": 1,
"deprecated/model-invoked": 1
},
"skills": [
@@ -420,6 +421,19 @@
"has_evals": true,
"has_docs": true
},
{
"name": "diagnosing-bugs",
"category": "dev",
"version": "0.1.0",
"status": "beta",
"invocation": "model-invoked",
"description": "难查 bug 的诊断纪律:先造出一条「现在就为这个 bug 变红」的紧反馈循环,再二分定位、最小验证、补回归测试。当 bug 难复现、间歇失败、或第一次看没头绪时使用。",
"description_len": 84,
"path": "skills-dev/diagnosing-bugs-plugin/skills/SKILL.md",
"digest": "d93fb95c073858cc",
"has_evals": true,
"has_docs": true
},
{
"name": "executing-plans",
"category": "dev",
+1
View File
@@ -21,6 +21,7 @@
| 设计 / 拆任务 | `req-design`、`dev-arch`、`db-migration` |
| 编码 | `dev-coding`、`karpathy-guidelines` |
| 测试 | `dev-test`、`req-test-gate` |
| 难查的 bug / 间歇失败 | `diagnosing-bugs`(先建红循环再推理) |
| 代码评审 | `dev-review`、`review-checklist` |
| 发布(Slark 仓库/Desktop) | `slark-cicd` |
| 发布(DSH 插件/宿主补丁) | `slark-dsh-cicd` |
+26
View File
@@ -0,0 +1,26 @@
# diagnosing-bugs
## What it does
给难查的 bug 一套诊断纪律:先造出「现在就为这个 bug 变红」的紧反馈循环,再二分定位、一次验一个假设、最小改动修复,最后补一条曾经红过的回归测试。
## When to reach for it
- 间歇失败、偶发问题,第一次看没头绪
- 已知两个好版本之间引入的回归(适合 git bisect)
- 修过几次没修好的 bug
一眼可见的拼写/配置错误不需要它,直接修。
## Common questions
- **为什么不能先猜着改?** 没有红循环就没有验证手段,改了也不知道是不是这次改动生效。
- **复现不出来怎么办?** 提高复现率(缩小输入、调整时序、加观测),或用 git bisect 从版本维度定位,而不是盲上。
- **修完就完了吗?** 不,必须补一条回归测试,并证明修复前它是红的。
- **和 dev-test 的区别?** dev-test 管测试怎么写;本技能管「怎么找到 bug」。
## It's working if
- 动手改代码前,先给出了一条现在为红的命令
- 每次改动只变一个变量,并能说出上次结果的差异
- 修复结论包含根因 + 回归测试 + 「曾经红过」的证据
+15
View File
@@ -0,0 +1,15 @@
# <YYYY-Www> 技能 evals 抽样回归
- 日期:YYYY-MM-DD
- 范围:上周改动过的技能 + 高风险技能(dev-coding / dev-review / req-design)
- 方法:每技能取 1 条关键用例,做「有技能 / 无技能」两组独立输出对比,按 rubric 打分(0–2)
| 技能 | 用例 | 有技能 | 无技能 | 差值 | 结论 |
| --- | --- | --- | --- | --- | --- |
| | | | | | |
## 结论与新发现
- 有效技能:
- 无增量技能(按 SCOPE 评估是否降级):
- 需要补的用例:
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""列出各技能的 evals 与是否已有回归报告(reports/evals/<name>.md)。"""
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
rows = []
for pj in sorted(ROOT.glob("skills-*/*-plugin/.claude-plugin/plugin.json")):
meta = json.loads(pj.read_text())
name = meta.get("install_name")
if not name:
continue
ev = next((pj.parent.parent / "skills").rglob("evals/evals.json"), None)
cases = 0
if ev:
try:
cases = len(json.loads(ev.read_text()).get("evals", []))
except Exception:
cases = 0
report = ROOT / "reports" / "evals" / f"{name}.md"
rows.append((name, meta.get("status", "promoted"), cases, report.is_file()))
with_evals = sum(1 for r in rows if r[2] > 0)
with_report = sum(1 for r in rows if r[3])
print(f"{'技能':32} {'status':10} {'用例':4} 回归报告")
for name, status, cases, has_report in rows:
if cases == 0:
continue
print(f"{name:32} {status:10} {cases:<4} {'有' if has_report else '-'}")
print(f"\n有 evals 的技能: {with_evals}/{len(rows)};已有回归报告: {with_report}/{with_evals}")
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# 月度技能审阅:一条命令跑完 MAINTENANCE 里的月度项。
# 用法: ./scripts/monthly-review.sh
set -uo pipefail
cd "$(git rev-parse --show-toplevel)" || exit 1
echo "== 技能月度审阅 $(date '+%F %H:%M') =="
echo; echo "-- 1. 覆盖率(promoted + model-invoked)--"
python3 scripts/validate-skills.py --coverage
echo; echo "-- 2. 本仓库安全扫描 --"
./scripts/scan-skill.sh | tail -2
echo; echo "-- 3. 第三方已装技能扫描 --"
./scripts/scan-installed.sh | tail -2
echo; echo "-- 4. catalog 是否最新 --"
python3 scripts/generate-catalog.py --check
echo; echo "-- 5. catalog 摘要与 description 异常项 --"
python3 - <<'PY'
import json
d = json.load(open('catalog.json'))
print("总数:", d['total'], "| 分布:", d['counts'])
bad = [(x['name'], x['description_len']) for x in d['skills']
if x['description_len'] < 60 or x['description_len'] > 600]
print("description 长度异常:", bad if bad else "无")
cov = d.get('coverage', {})
print(f"覆盖率: evals {cov.get('with_evals')}/{cov.get('required')},文档 {cov.get('with_docs')}/{cov.get('required')}")
PY
@@ -0,0 +1,11 @@
{
"name": "diagnosing-bugs-plugin",
"description": "难查 bug 的诊断纪律:先造出会变红的紧反馈循环,再二分定位、最小验证、补回归测试。",
"version": "0.1.0",
"author": { "name": "qiudl" },
"install_name": "diagnosing-bugs",
"install_type": "skill",
"dir_category": "dev",
"status": "beta",
"invocation": "model-invoked"
}
@@ -0,0 +1,62 @@
---
name: diagnosing-bugs
description: 难查 bug 的诊断纪律:先造出一条「现在就为这个 bug 变红」的紧反馈循环,再二分定位、最小验证、补回归测试。当 bug 难复现、间歇失败、或第一次看没头绪时使用。
metadata:
invocation: model-invoked
owner: qiudl
---
# 难查 bug 诊断
## 0. 一句话
**没有红循环就不推理**:先有一条几秒内能跑、且现在就为这个 bug 变红的命令,再开始猜。
## 1. 何时用
- 间歇性失败、偶发问题
- 第一次看没头绪、日志线索不足
- 已知两个好版本之间引入的回归
- 别人修过几次没修好的 bug
何时不用:一眼可见的拼写/配置错误、明确报错指向单行 → 直接修。
## 2. 铁律
1. **先复现**:能手动复现最好;不能就缩小到最小输入/最小步骤。
2. **建红循环**:一条命令(测试/脚本/curl),现在跑必须是红的,且失败原因就是这个 bug。
3. **一次只验一个假设**:改一个变量,跑一次,记录结果。
4. **修完补回归测试**:确认测试在修复前是红的(临时回退验证一次)。
## 3. 步骤
1. 收集信息:报错、日志、复现步骤、最近改动(`git log`/`git bisect`)。
2. 写最小复现:能稳定触发的最小输入或最小步骤。
3. 建立反馈循环:命令固定、几秒内出结果、失败信息可读。
4. 二分定位:git bisect / 输入二分 / 代码路径二分,把范围砍半。
5. 假设 → 最小改动 → 跑循环验证;不做"顺手重构"。
6. 回归测试:补一条覆盖该 bug 的测试,并证明它曾经红过。
7. 记录根因与预防(进复盘或 memory)。
## 4. 反模式
- 没复现就开始改代码
- 同时改多个地方,不知道哪个生效
- 靠"看了日志觉得是缓存问题"直接改
- 修完不补回归测试
- 间歇失败归因于"环境问题"就收工
## 5. 验证清单
- [ ] 有一个现在为红的命令(不是偶发)
- [ ] 每次改动只变一个变量,并有结果记录
- [ ] 修复后同一命令变绿
- [ ] 回归测试存在,且回退修复后它会红
- [ ] 根因已写清(不是"不知道,反正好了")
## 6. 与其他技能
- 需要写测试规范 → `dev-test`
- 需要判断是不是设计缺陷 → `defect-analysis`
- 修复后要评审 → `dev-review`
- 任务状态与证据 → `ai-proj`(REQ 未 released 不算完成)
@@ -0,0 +1,27 @@
{
"skill_name": "diagnosing-bugs",
"skill_version": "0.1.0",
"evals": [
{
"id": 1,
"kind": "happy_path",
"prompt": "这个接口偶尔返回 500,日志看不出原因,帮查一下",
"expected_output": "先要求/建立最小复现与一条现在为红的命令(测试或 curl 循环),说明偶发失败要先提高复现率,再二分定位;不在没有红循环时直接给修复方案",
"files": []
},
{
"id": 2,
"kind": "edge_case",
"prompt": "我看日志就感觉是缓存没失效,直接把缓存清一下就好",
"expected_output": "不直接改:把假设变成可验证实验(一条能证伪的命令),先证明是缓存问题再改,并说明如何确认修复",
"files": []
},
{
"id": 3,
"kind": "failure_recovery",
"prompt": "试了几次复现不出来,算了先上线吧",
"expected_output": "拒绝盲上:改为加观测(日志/埋点)、提高复现率(输入二分/时序调整)、或用 git bisect 定位引入点;明确记录未复现风险",
"files": []
}
]
}