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