{"id":"943f479f-b93f-4d61-bf18-7a9979467675","shortId":"tJX2AQ","kind":"skill","title":"forge-review","tagline":"上线前 PR 审查。分析当前分支与基础分支的 diff，检查 SQL 安全、竞态条件、\nLLM 信任边界、枚举完整性等测试捕获不到的结构性问题。发现问题直接修复。","description":"# /forge-review：代码审查\n\n## 前置脚本（每次先运行）\n\n```bash\n_BRANCH=$(git branch --show-current 2>/dev/null || echo \"unknown\")\necho \"当前分支: $_BRANCH\"\n```\n\n---\n\n## AskUserQuestion 格式规范\n\n每次提问结构：\n1. **重新聚焦**：当前项目、分支、正在审查的内容\n2. **通俗解释**：高中生能懂的语言，说清楚\"做什么\"\n3. **给出建议**：`推荐：选择[X]，因为[一句话原因]`，标注完整度\n4. **列出选项**：`A) B) C)` + 工作量估算\n\n---\n\n## 第0步：确定基础分支\n\n按顺序判断此 PR 合并到哪个分支：\n\n```bash\n# 1. 检查是否已有 PR\ngh pr view --json baseRefName -q .baseRefName 2>/dev/null\n\n# 2. 没有 PR 则获取仓库默认分支\ngh repo view --json defaultBranchRef -q .defaultBranchRef.name 2>/dev/null\n\n# 3. 都失败则回退到 main\n```\n\n打印出基础分支名称，后续所有 `git diff`、`git fetch`、`git merge` 等命令中用实际分支名替换\"基础分支\"。\n\n---\n\n## 第1步：检查分支状态\n\n```bash\ngit branch --show-current\ngit fetch origin <基础分支> --quiet && git diff origin/<基础分支> --stat\n```\n\n如果在基础分支上，或没有 diff，输出：**\"没有可审查的内容——你在基础分支上或没有变更。\"** 并停止。\n\n---\n\n## 第2步：获取完整 diff\n\n```bash\ngit fetch origin <基础分支> --quiet\ngit diff origin/<基础分支>\n```\n\n**在评论之前先读完完整 diff。** 不要标记 diff 中已经修复的问题。\n\n---\n\n## 第3步：两轮审查\n\n### 第一轮（严重问题）\n\n逐项检查以下类别，对每个 diff 文件详细分析：\n\n#### 1. SQL 与数据安全\n**检查**：\n- 用户输入是否直接拼入 SQL？（注入风险）\n- 原始 SQL 查询是否使用了参数化？\n- 批量更新/删除是否有 `WHERE` 条件？（全表操作风险）\n- 事务边界是否正确？（部分成功状态）\n- 软删除记录是否在所有查询中被过滤了？\n\n**报告格式**：`[严重] 文件:行号 — 问题描述 → 修复建议`\n\n#### 2. 竞态条件与并发\n**检查**：\n- 先读后写操作是否有并发安全问题？（检查-再-操作 TOCTOU）\n- 数据库操作是否需要乐观锁/悲观锁？\n- 共享状态是否在多个请求间安全？\n- 缓存失效是否有竞态？\n\n**特别注意**：状态转换（如 `draft → published`）必须用数据库级约束，不能只依赖应用层检查。\n\n#### 3. LLM 输出信任边界\n**检查**：\n- LLM 生成的内容在写入数据库前是否经过验证/清洗？\n- LLM 输出是否直接用于 SQL 构建或系统命令？\n- 是否对 LLM 输出的类型和格式做了断言？\n- Prompt 中是否包含了敏感数据（密钥、PII）？\n\n#### 4. 枚举与值完整性\n**检查**：\n- 新增枚举值/状态/类型时，所有引用了同级值的文件是否都处理了新值？\n\n**重要**：枚举完整性**必须读取 diff 以外的代码**。当 diff 新增了枚举值，用 Grep 找出所有引用了同级值的文件，Read 这些文件检查新值是否被处理。\n\n### 第二轮（信息性问题）\n\n#### 5. 条件副作用\n**检查**：\n- 副作用（发邮件、写日志、扣费用）是否在 `if` 语句的所有分支中都正确处理？\n- 删除或禁用功能时，是否清理了对应的副作用触发器？\n\n#### 6. 魔法数字与字符串耦合\n**检查**：\n- 是否有应该提取为常量的重复数字/字符串？\n- 硬编码的限制值（如 `100`、`1000`）是否有注释说明含义？\n\n#### 7. 死代码与一致性\n**检查**：\n- 是否有明显无法执行的代码路径？\n- 同一逻辑的命名方式是否在整个文件中一致？\n\n#### 8. 测试缺口\n**检查**：\n- 新的分支逻辑有没有对应测试？\n- 错误路径有没有测试？\n- 是否存在只测试了 Happy Path 但跳过了边界情况？\n\n#### 9. 前端/视图层\n**检查**：\n- 用户输入是否经过 HTML 转义？（XSS 风险）\n- 是否有 `dangerouslySetInnerHTML` 或 `v-html` 使用了未清洗的数据？\n- 长文本/图片/空状态是否有兜底处理？\n\n---\n\n## 第4步：修复优先原则\n\n**每个发现都要有行动——不只是报告。**\n\n输出摘要头：`上线前审查：N 个问题（X 严重，Y 信息性）`\n\n### 自动修复（AUTO-FIX）\n机械性、无争议的修复直接应用。每个输出：\n`[已自动修复] 文件:行号 — 问题 → 修复内容`\n\n**适合自动修复的典型问题**：\n- 添加缺失的 WHERE 条件（无歧义的全表操作）\n- 移除 `outline: none` / `!important`\n- 添加明显缺失的类型检查\n- 修复 HTML 转义问题\n\n### 需要确认（ASK）\n需要判断或有真实权衡的问题，**批量放入一次 AskUserQuestion**（≤3个时可单独提问）：\n\n```\n我已自动修复了 5 个问题。2 个需要你的判断：\n\n1. [严重] app/models/order.rb:42 — 状态转换竞态条件\n   修复：在 UPDATE 中添加 WHERE status = 'pending'\n   → A) 按建议修复  B) 跳过\n\n2. [信息性] app/services/ai_writer.rb:88 — AI 输出未经类型验证就写入数据库\n   修复：添加 JSON Schema 验证\n   → A) 按建议修复  B) 跳过\n\n推荐：两个都修——#1是真实竞态，#2防止静默数据损坏。\n```\n\n---\n\n## 第5步：TODOS 交叉检查\n\n读取仓库根目录的 `TODOS.md`（如果存在）：\n- 此 PR 是否解决了某个 TODO？如果是，标注出来。\n- 此 PR 是否创建了需要变成 TODO 的工作？如果是，标记为信息性发现。\n\n---\n\n## 第6步：文档过时检查\n\n对比 diff 与根目录下的文档文件（README.md、ARCHITECTURE.md、CLAUDE.md 等）：\n- 如果代码改动影响了文档描述的功能，但文档没有在此分支更新，标记为信息性发现：\n  \"文档可能过时：[文件] 描述了 [功能]，但本分支修改了相关代码。考虑运行 `/forge-ship` 后更新文档。\"\n\n---\n\n## 重要规则\n\n- **先读完完整 diff，再评论。** 不标记 diff 中已修复的问题。\n- **修复优先，不只是报告。** AUTO-FIX 直接应用，ASK 等用户确认。\n- **简洁。** 一行问题，一行修复建议。\n- **只标记真实问题。** 正常代码直接跳过。\n- **绝不提交、推送或创建 PR**——那是 `/forge-ship` 的工作。","tags":["forge","review","skills","yike-gunshi","agent-skills","ai-development","claude-code","skill-md","skillsmp"],"capabilities":["skill","source-yike-gunshi","skill-forge-review","topic-agent-skills","topic-ai-development","topic-claude-code","topic-forge","topic-skill-md","topic-skillsmp"],"categories":["forge-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/yike-gunshi/forge-skills/forge-review","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add yike-gunshi/forge-skills","source_repo":"https://github.com/yike-gunshi/forge-skills","install_from":"skills.sh"}},"qualityScore":"0.455","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 11 github stars · SKILL.md body (3,198 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-25T19:02:45.235Z","embedding":null,"createdAt":"2026-04-24T07:03:38.841Z","updatedAt":"2026-04-25T19:02:45.235Z","lastSeenAt":"2026-04-25T19:02:45.235Z","tsv":"'/dev/null':29,79,92 '/forge-review':17 '/forge-ship':416,442 '1':38,68,157,344 '100':260 '1000':261 '1是真实竞态':377 '2':28,43,78,80,91,181,342,360 '2防止静默数据损坏':378 '3':48,93,201 '3个时可单独提问':338 '4':56,219 '42':347 '5':241,340 '6':253 '7':263 '8':268 '88':363 '9':277 'ai':364 'app/models/order.rb':346 'app/services/ai_writer.rb':362 'architecture.md':404 'ask':334,431 'askuserquest':35,337 'auto':310,428 'auto-fix':309,427 'b':59,358,373 'baserefnam':75,77 'bash':21,67,108,134 'branch':22,24,34,110 'c':60 'claude.md':405 'current':27,113 'dangerouslysetinnerhtml':287 'defaultbranchref':88 'defaultbranchref.name':90 'diff':8,99,120,126,133,141,145,147,155,229,232,401,420,423 'draft':197 'echo':30,32 'fetch':101,115,136 'fix':311,429 'forg':2 'forge-review':1 'gh':71,84 'git':23,98,100,102,109,114,119,135,140 'grep':235 'happi':274 'html':282,291,331 'import':328 'json':74,87,368 'llm':13,202,205,208,213 'main':95 'merg':103 'n':302 'none':327 'origin':116,121,137,142 'outlin':326 'path':275 'pend':355 'pii':218 'pr':5,65,70,72,82,386,392,440 'prompt':215 'publish':198 'q':76,89 'quiet':118,139 'read':237 'readme.md':403 'repo':85 'review':3 'schema':369 'show':26,112 'show-curr':25,111 'skill' 'skill-forge-review' 'source-yike-gunshi' 'sql':10,158,162,165,210 'stat':123 'status':354 'toctou':189 'todo':380,388,394 'todos.md':383 'topic-agent-skills' 'topic-ai-development' 'topic-claude-code' 'topic-forge' 'topic-skill-md' 'topic-skillsmp' 'unknown':31 'updat':351 'v':290 'v-html':289 'view':73,86 'x':52,304 'xss':284 'y':306 '一句话原因':54 '一行修复建议':435 '一行问题':434 '上线前':4 '上线前审查':301 '不只是报告':299,426 '不标记':422 '不能只依赖应用层检查':200 '不要标记':146 '与数据安全':159 '与根目录下的文档文件':402 '两个都修':376 '两轮审查':150 '严重':176,305,345 '严重问题':152 '个问题':303,341 '个需要你的判断':343 '中已修复的问题':424 '中已经修复的问题':148 '中是否包含了敏感数据':216 '中添加':352 '事务边界是否正确':172 '交叉检查':381 '代码审查':18 '以外的代码':230 '但文档没有在此分支更新':408 '但本分支修改了相关代码':414 '但跳过了边界情况':276 '你在基础分支上或没有变更':129 '使用了未清洗的数据':292 '信任边界':14 '信息性':307,361 '信息性问题':240 '修复':330,349,366 '修复优先':425 '修复优先原则':297 '修复内容':319 '修复建议':180 '做什么':47 '先读后写操作是否有并发安全问题':184 '先读完完整':419 '全表操作风险':171 '共享状态是否在多个请求间安全':192 '再':187 '再评论':421 '写日志':246 '分支':41 '分析当前分支与基础分支的':7 '列出选项':57 '则获取仓库默认分支':83 '删除或禁用功能时':251 '删除是否有':168 '前端':278 '前置脚本':19 '副作用':244 '功能':413 '原始':164 '发现问题直接修复':16 '发邮件':245 '只标记真实问题':436 '合并到哪个分支':66 '同一逻辑的命名方式是否在整个文件中一致':267 '后更新文档':417 '后续所有':97 '因为':53 '图片':294 '在':350 '在评论之前先读完完整':144 '基础分支':105,117,122,138,143 '如':196,259 '如果代码改动影响了文档描述的功能':407 '如果在基础分支上':124 '如果存在':384 '如果是':389,396 '字符串':257 '安全':11 '审查':6 '密钥':217 '对每个':154 '对比':400 '工作量估算':61 '已自动修复':315 '并停止':130 '当':231 '当前分支':33 '当前项目':40 '必须用数据库级约束':199 '必须读取':228 '悲观锁':191 '我已自动修复了':339 '或':288 '或没有':125 '所有引用了同级值的文件是否都处理了新值':225 '打印出基础分支名称':96 '扣费用':247 '批量放入一次':336 '批量更新':167 '找出所有引用了同级值的文件':236 '报告格式':175 '按建议修复':357,372 '按顺序判断此':64 '推荐':50,375 '推送或创建':439 '描述了':412 '操作':188 '数据库操作是否需要乐观锁':190 '文件':177,316,411 '文件详细分析':156 '文档可能过时':410 '文档过时检查':399 '新增了枚举值':233 '新增枚举值':222 '新的分支逻辑有没有对应测试':271 '无争议的修复直接应用':313 '无歧义的全表操作':324 '是否创建了需要变成':393 '是否在':248 '是否存在只测试了':273 '是否对':212 '是否有':286 '是否有应该提取为常量的重复数字':256 '是否有明显无法执行的代码路径':266 '是否有注释说明含义':262 '是否清理了对应的副作用触发器':252 '是否解决了某个':387 '机械性':312 '条件':170,323 '条件副作用':242 '构建或系统命令':211 '枚举与值完整性':220 '枚举完整性':227 '枚举完整性等测试捕获不到的结构性问题':15 '查询是否使用了参数化':166 '标注出来':390 '标注完整度':55 '标记为信息性发现':397,409 '格式规范':36 '检查':9,160,183,186,204,221,243,255,265,270,280 '检查-再-操作':185 '检查分支状态':107 '检查是否已有':69 '正在审查的内容':42 '正常代码直接跳过':437 '此':385,391 '死代码与一致性':264 '每个发现都要有行动':298 '每个输出':314 '每次先运行':20 '每次提问结构':37 '没有':81 '没有可审查的内容':128 '注入风险':163 '测试缺口':269 '添加':367 '添加明显缺失的类型检查':329 '添加缺失的':321 '清洗':207 '特别注意':194 '状态':223 '状态转换':195 '状态转换竞态条件':348 '生成的内容在写入数据库前是否经过验证':206 '用':234 '用户输入是否直接拼入':161 '用户输入是否经过':281 '的工作':395,443 '直接应用':430 '硬编码的限制值':258 '确定基础分支':63 '移除':325 '空状态是否有兜底处理':295 '竞态条件':12 '竞态条件与并发':182 '第0步':62 '第1步':106 '第2步':131 '第3步':149 '第4步':296 '第5步':379 '第6步':398 '第一轮':151 '第二轮':239 '等':406 '等命令中用实际分支名替换':104 '等用户确认':432 '简洁':433 '类型时':224 '给出建议':49 '绝不提交':438 '缓存失效是否有竞态':193 '考虑运行':415 '自动修复':308 '获取完整':132 '行号':178,317 '视图层':279 '语句的所有分支中都正确处理':250 '说清楚':46 '读取仓库根目录的':382 '跳过':359,374 '转义':283 '转义问题':332 '软删除记录是否在所有查询中被过滤了':174 '输出':127 '输出信任边界':203 '输出摘要头':300 '输出是否直接用于':209 '输出未经类型验证就写入数据库':365 '输出的类型和格式做了断言':214 '这些文件检查新值是否被处理':238 '适合自动修复的典型问题':320 '选择':51 '逐项检查以下类别':153 '通俗解释':44 '那是':441 '部分成功状态':173 '都失败则回退到':94 '重新聚焦':39 '重要':226 '重要规则':418 '错误路径有没有测试':272 '长文本':293 '问题':318 '问题描述':179 '需要判断或有真实权衡的问题':335 '需要确认':333 '风险':285 '验证':370 '高中生能懂的语言':45 '魔法数字与字符串耦合':254","prices":[{"id":"2dd62e88-aacc-4e30-b9a0-f286168a3838","listingId":"943f479f-b93f-4d61-bf18-7a9979467675","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"yike-gunshi","category":"forge-skills","install_from":"skills.sh"},"createdAt":"2026-04-24T07:03:38.841Z"}],"sources":[{"listingId":"943f479f-b93f-4d61-bf18-7a9979467675","source":"github","sourceId":"yike-gunshi/forge-skills/forge-review","sourceUrl":"https://github.com/yike-gunshi/forge-skills/tree/main/skills/forge-review","isPrimary":false,"firstSeenAt":"2026-04-24T07:03:38.841Z","lastSeenAt":"2026-04-25T19:02:45.235Z"}],"details":{"listingId":"943f479f-b93f-4d61-bf18-7a9979467675","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"yike-gunshi","slug":"forge-review","github":{"repo":"yike-gunshi/forge-skills","stars":11,"topics":["agent-skills","ai-development","claude-code","forge","skill-md","skillsmp"],"license":"mit","html_url":"https://github.com/yike-gunshi/forge-skills","pushed_at":"2026-04-25T10:22:48Z","description":"Forge — 文档驱动的 AI 辅助开发框架 | Document-driven AI development framework with 14 Skills covering brainstorm → PRD → design → engineering → QA → review → ship → retrospective","skill_md_sha":"a5d4e0555b8e57e8277e5d14ad3f80bcefbcb95a","skill_md_path":"skills/forge-review/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/yike-gunshi/forge-skills/tree/main/skills/forge-review"},"layout":"multi","source":"github","category":"forge-skills","frontmatter":{"name":"forge-review","description":"上线前 PR 审查。分析当前分支与基础分支的 diff，检查 SQL 安全、竞态条件、\nLLM 信任边界、枚举完整性等测试捕获不到的结构性问题。发现问题直接修复。"},"skills_sh_url":"https://skills.sh/yike-gunshi/forge-skills/forge-review"},"updatedAt":"2026-04-25T19:02:45.235Z"}}