{"slug":"pdlc-implement","title":"pdlc-implement","summary":"按设计文档和已有测试用例实现代码（带前置守卫、自检、handoff）","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-23T18:54:23.772896Z","repo":{"url":"https://github.com/kanfu-panda/pdlc-skills","stars":15,"forks":2,"license":"MIT","updatedAt":"2026-09-23T15:59:31Z"},"bodyHtml":"<hr>\n<p>name: pdlc-implement\ndescription: 按设计文档和已有测试用例实现代码（带前置守卫、自检、handoff）\nargument-hint: &lt;功能描述或功能ID&gt;\nallowed-tools: Read, Write, Edit, Glob, Grep, Bash\nlayer: 2\nstage: impl\nproduces:</p>\n<h1>跟随项目既有源码布局，不限定固定目录</h1>\n<ul>\n<li>&lt;实现代码 · 项目既有布局&gt;\nrequires:</li>\n</ul>\n<h1>只依赖设计文档；测试的位置由 test-location.md 的规则动态定位，不硬编码路径</h1>\n<ul>\n<li>docs/02_design/\nnext_step: pdlc-review\nterminal_state: impl_done\nrecommended_model: sonnet\nrecommended_effort: medium</li>\n</ul>\n<hr>\n<h1>按设计文档实现代码</h1>\n<p>严格按照设计文档和已有的测试用例实现功能代码。</p>\n\n<p>⛔ <strong>IRON LAW · 不可违反的硬门禁</strong></p>\n<p>以下规则为<strong>不可协商</strong>的执行约束：</p>\n<ol>\n<li><strong>文件必须落盘</strong>：所有带编号（功能ID / 缺陷ID）的文档，必须作为实际文件写入磁盘，不可仅在对话中输出。</li>\n<li><strong>阶段必须落章</strong>：每个阶段完成后必须在状态机 <code>docs/.pdlc-state/&lt;feature-id&gt;.json</code> 追加 history，不可跳过。</li>\n<li><strong>测试必须存在</strong>：进入 <code>/pdlc-implement</code> 前，对应测试必须存在且处于红灯状态。违反则中止。</li>\n<li><strong>自检必须执行</strong>：段二自检为强制步骤，不得以\"已经很好了\"为由跳过。</li>\n<li><strong>防循环</strong>：段三修复为单次，不递归。无法自动修复的问题记录到报告，继续往下走。</li>\n<li><strong>状态必推进</strong>：成功执行某 phase 后 <code>current_stage</code> 必须变更。收尾时若发现 <code>current_stage</code> 未推进，视为失败并报错，<strong>不得静默返回</strong>（防止外层循环拿滞后的状态空转烧额度）。唯一例外：命中人工点主动 block 时，<code>current_stage</code> 保持不变但必须写 <code>last_phase_result.ok=false</code> + <code>blocked_reason</code>。</li>\n</ol>\n<p><strong>违反任一条 = 立即中止当前命令，输出违规详情，等待人工介入。</strong></p>\n\n\n<h2>非交互模式（<code>--autonomous</code>）</h2>\n<p>若本命令的参数含 <code>--autonomous</code>，本命令进入<strong>无人值守</strong>模式，按以下规则处理原本需要人应答的交互点。<strong>参数是唯一真源</strong>：不带 <code>--autonomous</code> 即为交互模式，一切照旧正常询问用户；绝不回读状态机 <code>run_mode</code> 兜底（「掉出 autonomous」是安全的失败方向）。</p>\n<ol>\n<li><strong>流程性确认</strong>（如「测试已绿是否继续」「是否覆盖已有文件」）→ <strong>不询问</strong>，按预设默认前进，并把决策追加到状态机 <code>history[].auto_decisions[]</code>：\n<pre><code>{ \"point\": \"&lt;确认点描述&gt;\", \"chose\": \"&lt;所选默认&gt;\", \"at\": \"&lt;ISO 8601&gt;\" }\n</code></pre>\n</li>\n<li><strong>真需人判断</strong>（PRD 关键取舍、评审「需人工确认」项、真实循环依赖等无法安全默认的点）→ <strong>不猜</strong>：\n<ul>\n<li><code>current_stage</code> 保持不变（不推进）</li>\n<li>写 <code>last_phase_result.ok = false</code> 且 <code>blocked_reason = \"&lt;原因&gt;\"</code></li>\n<li>末行输出哨兵：<code>&lt;&lt;&lt;PDLC blocked reason=\"&lt;原因&gt;\"&gt;&gt;&gt;</code></li>\n<li>立即结束命令，交还人类</li>\n</ul>\n</li>\n<li><strong>破坏性操作</strong>（发布 / 部署 / 打 tag / 触发 CI / DROP / force-push 等不可逆·外发操作）→ <code>--autonomous</code> <strong>无效</strong>，仍必须人工显式确认。</li>\n<li><strong>顺手的 sidecar 产物</strong>（如缺失时创建 <code>CHANGELOG.md</code>、补全文档 PDLC-TRACE 的创建时间等本阶段职责内、可安全默认的辅助改动）→ 视为流程性默认，<strong>直接做并记入 <code>auto_decisions[]</code></strong>；这类改动不新增外部副作用，不属破坏性操作。</li>\n</ol>\n<blockquote>\n<p>进入 autonomous 模式时，在状态机顶层写 <code>run_mode: \"autonomous\"</code> 仅供留痕（复盘区分人工 vs 循环产出）。</p>\n</blockquote>\n\n<h2>PDLC 前置守卫（不可跳过）</h2>\n<ol>\n<li>从用户输入提取功能名称关键词</li>\n<li>按下面的规则搜索与该功能相关的<strong>测试代码</strong>：</li>\n</ol>\n\n<h2>测试代码在哪（布局无关的定位规则）</h2>\n<blockquote>\n<p>⚠️ <strong>这条规则的要害</strong>：红灯守卫必须区分「<strong>项目没有测试</strong>」和「<strong>测试不在我预期的位置</strong>」。\n前者才该拦；后者拦了就是误伤——真实项目的测试布局千差万别（单体 <code>backend/tests/</code>、\n根级 <code>tests/</code>、Go 同包 <code>*_test.go</code>、Node 与源码同目录的 <code>*.test.tsx</code>…），\n按一份写死的路径清单去找、找不到就拦，会让 pdlc 在大量正常项目上直接卡死。</p>\n</blockquote>\n<p><strong>核心原则：优先问 runner，其次翻文件。</strong> 测试框架自己最清楚有哪些测试——\n让它报比我们去猜文件位置准得多，也和 pdlc「信退出码、不信目视检查」的哲学一致。\n尤其<strong>测试写在源文件里</strong>的语言（见下），翻文件根本找不到。</p>\n<p>按下列顺序定位，<strong>命中即停</strong>：</p>\n<h3>1. 项目自己的声明 + 向 runner 查询（最高优先级）</h3>\n<p>若存在 <code>docs/00_standards/test-commands.yml</code>，它的 <code>unit</code> / <code>e2e</code> 命令<strong>就是权威</strong>——\n项目已经明确告诉你测试怎么跑。<strong>用它去问 runner</strong>，而不是去翻目录：</p>\n<table>\n<thead>\n<tr>\n<th>runner</th>\n<th>列出全部测试</th>\n<th>只查某功能相关</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>cargo (Rust)</td>\n<td><code>cargo test -- --list</code></td>\n<td><code>cargo test &lt;关键词&gt; -- --list</code></td>\n</tr>\n<tr>\n<td>pytest</td>\n<td><code>pytest --collect-only -q</code></td>\n<td><code>pytest --collect-only -q -k &lt;关键词&gt;</code></td>\n</tr>\n<tr>\n<td>go test</td>\n<td><code>go test -list '.*' ./...</code></td>\n<td><code>go test -list '&lt;关键词&gt;' ./...</code></td>\n</tr>\n<tr>\n<td>vitest / jest</td>\n<td><code>npx vitest list</code> / <code>--listTests</code></td>\n<td><code>npx vitest list -t &lt;关键词&gt;</code></td>\n</tr>\n<tr>\n<td>gradle / maven</td>\n<td><code>--tests '*'</code> 干跑</td>\n<td><code>--tests '*&lt;关键词&gt;*'</code></td>\n</tr>\n</tbody>\n</table>\n<p><strong>查询结果为空 = 该功能没有测试</strong>（这是行为证据，比\"我没找到文件\"可靠得多）。</p>\n<h3>2. 测试写在源文件里的语言（<strong>必须靠内容匹配，文件名扫描无效</strong>）⭐</h3>\n<p>这类语言没有独立测试文件，只能按<strong>代码内标记</strong>搜：</p>\n<table>\n<thead>\n<tr>\n<th>语言 / 框架</th>\n<th>in-source 测试标记</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Rust</strong></td>\n<td><code>#[cfg(test)]</code>、<code>#[test]</code>、<code>mod tests</code></td>\n</tr>\n<tr>\n<td><strong>Vitest</strong>（in-source testing）</td>\n<td><code>import.meta.vitest</code></td>\n</tr>\n<tr>\n<td><strong>Python</strong> doctest</td>\n<td>docstring 里的 <code>&gt;&gt;&gt; </code></td>\n</tr>\n<tr>\n<td><strong>Elixir</strong> doctest</td>\n<td><code>@doc</code> 里的 <code>iex&gt;</code></td>\n</tr>\n<tr>\n<td><strong>Go</strong>（同包但独立文件）</td>\n<td><code>*_test.go</code> + <code>func Test</code></td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ <strong>Rust 尤其要注意</strong>：单元测试几乎总在源文件的 <code>#[cfg(test)] mod tests</code> 里，\n<code>tests/</code> 目录按 Cargo 约定只放<strong>集成测试</strong>。所以「<code>tests/</code> 目录不存在」在 Rust 项目里\n<strong>完全不能推出「没有单元测试」</strong>——照文件清单判红会稳定误伤所有 Rust 项目。</p>\n</blockquote>\n<h3>3. 常见布局约定（按项目实际技术栈挑，不要全试）</h3>\n<table>\n<thead>\n<tr>\n<th>生态</th>\n<th>常见测试位置</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Python</td>\n<td><code>tests/</code>、<code>backend/tests/</code>、<code>test/</code>、与源码同目录的 <code>test_*.py</code></td>\n</tr>\n<tr>\n<td>Node / TS</td>\n<td><code>tests/</code>、<code>__tests__/</code>、<code>src/**/__tests__/</code>、与源码同目录的 <code>*.test.ts(x)</code> / <code>*.spec.ts(x)</code></td>\n</tr>\n<tr>\n<td>Rust</td>\n<td>源文件内 <code>#[cfg(test)]</code>（单测）+ <code>tests/</code>（集成测试）</td>\n</tr>\n<tr>\n<td>Go</td>\n<td>与源码同包的 <code>*_test.go</code></td>\n</tr>\n<tr>\n<td>JVM</td>\n<td><code>src/test/java/</code>、<code>src/test/kotlin/</code></td>\n</tr>\n<tr>\n<td>Ruby</td>\n<td><code>spec/</code>、<code>test/</code></td>\n</tr>\n<tr>\n<td>微服务 / 单体仓</td>\n<td>上述任一可能出现在 <code>backend/</code>、<code>backend/services/&lt;名&gt;/</code>、<code>frontend/&lt;应用&gt;/</code> 之下</td>\n</tr>\n</tbody>\n</table>\n<h3>4. 文件名兜底扫描</h3>\n<p>前三步都没命中时，按文件名模式全仓搜（<code>*test*</code> / <code>*spec*</code>，排除 <code>node_modules</code>、\n<code>.venv</code>、<code>vendor</code>、<code>dist</code>、<code>build</code>、<code>target</code>、<code>.git</code>），再按功能关键词筛。</p>\n<h3>5. 判定</h3>\n<ul>\n<li><strong>任一步找到相关测试</strong> → 通过，进入下一步（<code>pdlc-implement</code> 还需确认红灯）</li>\n<li><strong>四步走完确实找不到任何测试</strong> → 这才是真红灯，按各命令的守卫规则中止</li>\n<li><strong>找到测试但与本功能无关</strong> → 按「本功能无测试」处理（同样是真红灯），但报告里要说明\n「项目有测试，只是没覆盖本功能」，别让用户以为项目裸奔</li>\n<li><strong>无法判定</strong>（如 runner 装不上、语言不认识）→ <strong>不要默认放行，也不要假装找到了</strong>：\n如实报「无法确认本功能是否有测试」并交还人类。<strong>「我判断不了」绝不等于「没问题」。</strong></li>\n</ul>\n<blockquote>\n<p>写测试时（<code>pdlc-tdd</code>）同样按本规则决定<strong>写到哪</strong>：跟随项目既有布局与惯例——\nRust 单测就写进源文件的 <code>#[cfg(test)] mod tests</code>，<strong>不要</strong>为了迎合某种预设结构\n新造一套平行的测试目录。</p>\n</blockquote>\n\n<ol start=\"3\">\n<li><strong>按上述四步走完仍未找到测试代码</strong> → 输出以下后立即中止：\n<pre><code>⛔ PDLC 守卫：未找到与「&lt;功能名&gt;」相关的测试代码。\n实现代码前必须先编写测试（TDD）。请先运行：\n\uD83D\uDC49 /pdlc-tdd &lt;功能描述&gt;\n</code></pre>\n</li>\n<li><strong>找到测试</strong> → 运行测试，确认<strong>红灯</strong>（失败）。若已全绿：\n<ul>\n<li>交互模式：提示\"测试已全部通过，可能代码已实现，请确认是否需要继续。\"</li>\n<li><code>--autonomous</code> 模式：视为流程性确认，默认<strong>跳过实现直接收尾</strong>（写 <code>auto_decisions[]</code> 留痕），<code>current_stage</code> 推进为 <code>impl</code>、<code>next_step=pdlc-review</code>、<code>last_phase_result.advanced_to=review</code>（下一阶段短名，非命令名）</li>\n</ul>\n</li>\n<li>提取功能ID（从设计文档或 PRD），继续</li>\n<li><strong>任务状态关联</strong>（如 <code>docs/06_tasks/</code> 存在任务文件）：\n<ul>\n<li>匹配含功能ID的任务文件</li>\n<li>⬜ 未开始 / \uD83D\uDD04 进行中的任务，标为 \uD83D\uDD04，追加 <code>&lt;!-- 开始时间: &lt;今日日期&gt; --&gt;</code></li>\n</ul>\n</li>\n</ol>\n<h2>段一：实现代码</h2>\n<ol>\n<li><strong>阅读设计文档</strong>：<code>docs/02_design/</code> 对应子目录下的文档，逐字理解</li>\n<li><strong>阅读测试用例</strong>：对应服务/应用下的测试代码，理解每条意图</li>\n<li><strong>阅读编码规范</strong>：<code>docs/00_standards/coding/</code>（未命中 → 提示 <code>consider /pdlc-standard add coding/&lt;topic&gt;</code>）</li>\n<li><strong>最少量实现</strong>：使所有测试通过的最小代码</li>\n<li><strong>运行测试</strong>：确认绿灯</li>\n<li><strong>重构优化</strong>：测试通过前提下优化代码结构</li>\n<li><strong>更新服务 CHANGELOG</strong></li>\n<li><strong>任务完结</strong>：匹配任务由 \uD83D\uDD04 改 ✅，追加 <code>&lt;!-- 完成时间: &lt;今日日期&gt; --&gt;</code></li>\n</ol>\n<h2>段二：自检（强制）</h2>\n\n<h2>段二：自检（强制）</h2>\n<p>重新阅读本次产出物，按质量关卡清单逐项检查。勾选已通过，标注未通过原因。</p>\n<blockquote>\n<p><strong>注意</strong>：自检清单的具体内容由各命令自行定义，本片段只规定结构。</p>\n</blockquote>\n<h2>段三：修复（单次，不递归）</h2>\n<p>针对自检段标注为未通过的项：</p>\n<ul>\n<li><strong>可自动修复</strong>：直接修复（如补缺字段、修正格式、补齐缺失段落）</li>\n<li><strong>修复后回验</strong>：再次运行自检，确认被修复项现在通过</li>\n<li><strong>无法自动修复</strong>：记录到自审报告，不再尝试，流程继续</li>\n</ul>\n<p>⚠️ 单次修复原则：若一轮修复后仍有项未通过，<strong>不再递归修复</strong>，防止死循环。</p>\n\n<h3>实现自检清单（必须全部检查）</h3>\n<ol>\n<li><strong>设计偏离检查</strong>：重读设计文档，确认没有遗漏接口或功能点\n<ul>\n<li>遗漏 → 补充实现并确认测试通过</li>\n<li>偏离 → 修正代码或补充设计说明</li>\n</ul>\n</li>\n<li><strong>编码规范快检</strong>：运行项目 lint 工具\n<ul>\n<li>可自动修复 → 直接修复</li>\n<li>修复后重跑测试确认不破坏功能</li>\n<li>lint fix 导致失败 → 回滚并记录人工处理</li>\n</ul>\n</li>\n<li><strong>覆盖率验证</strong>：覆盖率达标线<strong>以项目配置为准</strong>：优先取 <code>docs/00_standards/test-commands.yml</code> 的 coverage 命令阈值参数（那才是强制点，退出码即判定），其次 <code>quality-targets.yml</code>；两者都没有时按 &gt;= 80% 兜底。\n<ul>\n<li>不达标 → 补测试用例并确认通过</li>\n</ul>\n</li>\n</ol>\n<h2>段三：修复（单次，不递归）</h2>\n\n<h2>防循环规则</h2>\n<p>本命令所有的自检-修复循环均受以下约束：</p>\n<ol>\n<li><strong>单次检查</strong>：同一个自检清单在本次命令执行中只跑一次（起始 + 修复后验证共两次读）</li>\n<li><strong>单次修复</strong>：发现的问题只尝试修复一轮</li>\n<li><strong>不递归</strong>：修复后不再重新触发自检的全量重跑</li>\n<li><strong>失败降级</strong>：无法自动修复的问题 → 记录到自审报告 → 流程继续 → 最终报告标注待人工处理</li>\n</ol>\n<p>这是为了防止 agent 在\"修完再查、查完再修\"的往返中陷入死循环。</p>\n\n<h2>段四：更新状态机 + 交接</h2>\n\n<blockquote>\n<p><strong>本命令的状态机取值</strong>：阶段短名 <code>impl</code>（写进 <code>history[].stage</code> 与 <code>last_phase_result.stage</code>）；下一跳 <code>pdlc-review</code>（写进 <code>next_step</code>，交接时提示）。</p>\n</blockquote>\n\n\n<h2>状态机更新（段四必须执行）</h2>\n<p>本命令完成主产出后，必须更新状态机文件 <code>docs/.pdlc-state/&lt;feature-id&gt;.json</code>。</p>\n<h3>文件格式</h3>\n<pre><code>{\n  \"feature_id\": \"&lt;F/B ID&gt;\",\n  \"feature_name\": \"&lt;kebab-case&gt;\",\n  \"created_at\": \"&lt;首次创建时间 ISO 8601&gt;\",\n  \"current_stage\": \"&lt;当前阶段名&gt;\",\n  \"run_mode\": \"interactive | autonomous\",\n  \"history\": [\n    {\n      \"stage\": \"&lt;阶段名&gt;\",\n      \"done_at\": \"&lt;ISO 8601&gt;\",\n      \"produced\": [\"&lt;相对路径 1&gt;\", \"&lt;相对路径 2&gt;\"],\n      \"self_audit\": { \"passed\": &lt;N&gt;, \"failed\": &lt;N&gt;, \"manual\": &lt;N&gt; },\n      \"auto_decisions\": [\n        { \"point\": \"&lt;autonomous 下自动前进的确认点&gt;\", \"chose\": \"&lt;所选默认&gt;\", \"at\": \"&lt;ISO 8601&gt;\" }\n      ]\n    }\n  ],\n  \"last_phase_result\": {\n    \"stage\": \"&lt;本次阶段名&gt;\",\n    \"ok\": true,\n    \"advanced_to\": \"&lt;推进到的下一阶段 | null&gt;\",\n    \"checks\": {},\n    \"self_audit\": { \"failed\": 0 },\n    \"blocked_reason\": null,\n    \"run_mode\": \"interactive | autonomous\",\n    \"at\": \"&lt;ISO 8601&gt;\"\n  },\n  \"relations\": {\n    \"extends\": [],\n    \"depends_on\": [],\n    \"supersedes\": [],\n    \"resolves\": [],\n    \"conflicts_with\": [],\n    \"relates_to\": [],\n    \"_updated_at\": \"&lt;ISO 8601 | 省略&gt;\"\n  },\n  \"next_step\": \"&lt;下一跳命令名，如 pdlc-design；若流程结束则为 null&gt;\"\n}\n</code></pre>\n<blockquote>\n<p>⛔ 示例里的 <code>\"checks\": {}</code> 是「本阶段没有命令可跑」的样子，<strong>不是键名示范</strong>——键名与取值见下方 §1。</p>\n</blockquote>\n<blockquote>\n<p><strong><code>relations</code> 块（RFC#6，Phase 1 可选，Phase 2 推荐）</strong>：6 个 key 对应 6 种关系类型，各为 ID 数组，存<strong>出边</strong>。其中 <code>conflicts_with</code> / <code>relates_to</code> 是对称类型，两端都要写；其余四种有向，只写在源 feature 上。拿不准时用 <code>/pdlc-relate set</code> 写入，它会按规则校验。旧状态文件无此块时视为全空，向后兼容。入边由 <code>/pdlc-relate rebuild</code> 派生到 <code>_relations.json</code>，不在此块手维护。</p>\n</blockquote>\n<blockquote>\n<p>⛔ <strong>写状态机的四条硬约束</strong>——读侧（<code>/pdlc-status</code>、<code>/pdlc-retro</code>、<code>/pdlc-relate</code>）会逐条体检，\n违反的每一处都会出现在它们输出的最前面：</p>\n<ol>\n<li><strong>实例里不写 <code>terminal_state</code></strong>。skill frontmatter 的 <code>terminal_state:</code> 是「这个命令走完后应到达的终态名」，\n不是状态字段。判终态只看 <code>current_stage</code> 是否以 <code>_done</code> 结尾。</li>\n<li><strong><code>history[].stage</code> 写本命令的阶段短名</strong>（见本命令正文里「本命令的状态机取值」）——<code>pdlc-implement</code> 写 <code>impl</code>，\n不写 <code>implement</code> / <code>implementation</code>；<code>pdlc-prd</code> 写 <code>requirements</code>，不写 <code>prd</code>。</li>\n<li><strong>时间戳必须带时刻</strong>：<code>created_at</code> / <code>done_at</code> / <code>at</code> 一律写完整 ISO 8601（如 <code>2026-07-28T10:40:00+08:00</code>）。\n只写日期，同一天内的阶段耗时就全部算成 0——读侧只能记「不可测」。</li>\n<li><strong><code>next_step</code> 只写命令名或 <code>null</code></strong>，不附说明文字（如「pdlc-ship（等评审通过）」）。\n要说明原因，阻塞时写进 <code>last_phase_result.blocked_reason</code>。</li>\n</ol>\n</blockquote>\n<blockquote>\n<p>⛔ <strong><code>_done</code> 的含义是「已发布」，只由 <code>/pdlc-ship</code>（写 <code>ship_done</code>）与 <code>/pdlc-deploy</code>（写 <code>deploy_done</code>）写入。</strong>\n其它命令的 <code>current_stage</code> 一律写本命令的阶段短名，走完整条链路的编排命令（<code>/pdlc-feature</code>）也一样——\n它收尾时 <code>current_stage</code> 是最后一个阶段的短名，<code>next_step</code> 是 <code>pdlc-ship</code>。</p>\n<ul>\n<li>「评审通过、等待发布」就是 <code>current_stage</code> 为 <code>review</code>（或 <code>e2e</code> 等）且 <code>next_step</code> 为 <code>pdlc-ship</code>。\n循环相关文档里说的 <code>review_done</code> 指的就是这个状态，<strong>不是</strong>要写进 <code>current_stage</code> 的值。</li>\n<li>为什么：读侧判「已抵达终态」只看 <code>current_stage</code> 是否以 <code>_done</code> 结尾。评审通过就写 <code>_done</code>，\n<code>/pdlc-ship</code> 就分不清哪些功能已经发布过，发布说明会重复或漏收。</li>\n<li>旧版本写入的 <code>feature_done</code> / <code>fix_done</code> / <code>review_done</code> 分不清是否已发布，<code>/pdlc-ship</code> 会列出来请人确认。</li>\n</ul>\n</blockquote>\n<h3>更新流程</h3>\n<ol>\n<li><strong>文件不存在</strong> → 创建文件，写入初始结构（<code>history</code> 为含当前阶段的数组）</li>\n<li><strong>文件存在</strong> → 读取 JSON，追加当前阶段到 <code>history</code>，更新 <code>current_stage</code> 和 <code>next_step</code></li>\n<li><strong>写回文件</strong>：用 <code>jq</code> 或等效工具保持格式化</li>\n</ol>\n<p>⚠️ 若更新失败（文件损坏/权限问题），必须中止命令并在最终报告中报错。状态机不可跳过。</p>\n<h3><code>last_phase_result</code>（机器可读阶段结果，每个 phase 收尾必写）</h3>\n<p>顶层 <code>last_phase_result</code> 是循环判停的<strong>唯一真源</strong>，外层只需 <code>jq '.last_phase_result.ok'</code> 即可决定 继续 / 停止 / 交还人类。规则：</p>\n<ol>\n<li><p><strong><code>checks</code> 必须客观、真跑得来</strong>：只放<strong>真跑命令的退出码</strong>结果（命令取自 <code>docs/00_standards/test-commands.yml</code>，见 <code>test-commands-template.yml</code>），<strong>绝不用模型自评、绝不填占位</strong>。有测试的阶段用 <code>tests_pass</code> / <code>coverage_pass</code> / <code>lint_clean</code>（退出码 0 → <code>true</code>，非 0 → <code>false</code>）；stage 语义不同用对应键（如 tdd 段 <code>{ \"red_verified\": true }</code> 表示红灯已验证）。</p>\n<blockquote>\n<p>⛔ <strong>键名与类型都是契约的一部分</strong>：键名只能是 <code>tests_pass</code> / <code>coverage_pass</code> /\n<code>lint_clean</code> / <code>e2e_pass</code>（tdd 段 <code>red_verified</code>），值只能是<strong>布尔</strong>。\n最常见的两种错法：① 照抄 <code>test-commands.yml</code> 的 <code>unit</code> / <code>coverage</code> / <code>lint</code> / <code>e2e</code>\n——那是<strong>命令表</strong>的字段名，不是状态机的（跑 <code>unit</code> 得到的结论写进 <code>tests_pass</code>）；\n② 写成 <code>\"4 passed, 1 failed\"</code> 这类字符串摘要。两种都会让 <code>jq '.checks.tests_pass'</code>\n读回 <code>null</code>，消费方（发布闸门、质量报告、自主循环）只看到「无法判定」——\n<strong>你诚实跑出来的结果等于没写</strong>。三态怎么分见本命令正文里「跑 check 命令：退出码的三态语义」一节；正文里没有这一节的命令不跑 check 命令，<code>checks</code> 写 <code>{}</code>。</p>\n<p>⚠️ <strong>没有检查命令可跑的阶段（如 requirements/design 只产文档，或项目无 <code>test-commands.yml</code>）→ <code>checks: {}</code> 留空。绝不因为「本阶段成功」就把 <code>tests_pass</code>/<code>lint_clean</code> 等填 <code>true</code>——那是虚报，会污染跨工具共用的状态机、误导自主循环判停。</strong> 上面 schema 示例里 <code>checks</code> 之所以是空的，正是这个原因——<strong>空是\"没跑\"的意思，不是键名的示范</strong>。</p>\n</blockquote>\n</li>\n<li><p><strong><code>self_audit</code> 单列</strong>：只放自检未通过数，<strong>仅供参考，不作循环判停依据</strong>。</p>\n</li>\n<li><p><strong><code>ok</code> 的定义</strong>：本阶段全部 <code>checks</code> 通过且未命中 <code>blocked_reason</code> → <code>true</code>；否则 <code>false</code>。</p>\n</li>\n<li><p><strong>命名空间</strong>：<code>advanced_to</code> = <strong>下一阶段的短名</strong>，<strong>不是命令名、也不是本阶段的 <code>current_stage</code></strong>。三者关系：<code>stage</code>=本阶段短名、<code>current_stage</code>=本阶段完成后的当前短名、<code>advanced_to</code>=下一阶段短名、<code>next_step</code>=下一跳命令名。</p>\n<p>⛔ <strong>短名不是「命令名去掉 <code>pdlc-</code> 前缀」</strong>——<code>pdlc-implement</code> 的短名是 <strong><code>impl</code></strong>，不是 <code>implement</code>。别推导，查下表：</p>\n</li>\n</ol>\n\n<table>\n<thead>\n<tr>\n<th><code>next_step</code>（下一跳命令名）</th>\n<th><code>advanced_to</code>（下一阶段短名）</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>pdlc-tdd</code></td>\n<td><code>tdd</code></td>\n</tr>\n<tr>\n<td><code>pdlc-implement</code></td>\n<td><code>impl</code></td>\n</tr>\n<tr>\n<td><code>pdlc-review</code></td>\n<td><code>review</code></td>\n</tr>\n<tr>\n<td><code>pdlc-design</code></td>\n<td><code>design</code></td>\n</tr>\n<tr>\n<td><code>pdlc-ship</code></td>\n<td><code>ship</code></td>\n</tr>\n<tr>\n<td><code>pdlc-deploy</code></td>\n<td><code>deploy</code></td>\n</tr>\n</tbody>\n</table>\n\n<p><code>next_step</code> 为 <code>null</code>（终态或无后续）时 <code>advanced_to</code> 也是 <code>null</code>。</p>\n<blockquote>\n<p>\uD83D\uDCCC <strong>本表是唯一真源，且是被断言钉住的</strong>：每行的短名必须等于该 skill 自己 frontmatter\n里声明的 <code>stage:</code>，且任何 skill 的非 <code>null</code> <code>next_step</code> 都必须在表里有行——两个方向\n都由 <code>tests/frontmatter-check.sh</code> 检查，所以表不会和实现各自漂移。</p>\n<p>写错短名的后果与键名写错同类：消费方按契约名匹配，认不出就当没这个阶段。</p>\n</blockquote>\n<ol start=\"5\">\n<li><strong>推进一致</strong>：<code>ok=true</code> 时本阶段必须真的推进了 <code>current_stage</code>（与第 6 条 IRON LAW 呼应）；到达终态或无后续时 <code>advanced_to=null</code>。<code>ok=false</code>（含 blocked）时 <code>current_stage</code> 不变、<code>advanced_to=null</code>、<code>blocked_reason</code> 写明原因。</li>\n<li><strong><code>run_mode</code></strong>：镜像本次调用是否带 <code>--autonomous</code>（带了写 <code>autonomous</code>，没带写 <code>interactive</code>）。</li>\n</ol>\n\n<p><strong>本阶段状态机更新</strong>：</p>\n<ul>\n<li><code>current_stage</code>: <code>impl</code>、<code>next_step</code>: <code>pdlc-review</code> —— <strong>仅当本阶段成功时才这样写</strong>\n（所有 <code>checks</code> 通过且未命中 <code>blocked_reason</code>）。</li>\n<li><strong>失败/受阻时不得推进</strong>：<code>ok=false</code>（含 blocked）→ 按 <code>state-update.md</code> 规则 5，\n<code>current_stage</code> <strong>保持原值不变</strong>、<code>advanced_to=null</code>、<code>blocked_reason</code> 写明原因。\n<blockquote>\n<p>⚠️ 失败也照写 <code>current_stage: impl</code> 是常见错误：那会让 <code>current_stage</code> 不再表示\n「最后一个真正完成的阶段」，外层循环的 stuck-stop 因此失效。</p>\n</blockquote>\n</li>\n<li><strong>写 <code>last_phase_result</code></strong>：<code>checks.tests_pass</code> / <code>coverage_pass</code> / <code>lint_clean</code> 取自真跑 <code>unit</code> / <code>coverage</code> / <code>lint</code> 的退出码，<strong>不得用自检结果冒充</strong>。退出码语义与\"跑不了\"的处理见下（该文件不存在则回退项目既有约定，并提示 <code>consider 建立 docs/00_standards/test-commands.yml</code>）。</li>\n</ul>\n\n<h2>跑 check 命令：退出码的三态语义</h2>\n<p>命令取自 <code>docs/00_standards/test-commands.yml</code>（唯一真源）。逐条真跑，<strong>按退出码分三态</strong>——\n不是两态。这是 IRON LAW「checks 只认客观事实」在执行层的落法：</p>\n<table>\n<thead>\n<tr>\n<th>观察到的</th>\n<th>含义</th>\n<th>写进 <code>checks</code></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>退出码 <code>0</code></td>\n<td>通过</td>\n<td>对应键 = <code>true</code></td>\n</tr>\n<tr>\n<td>退出码非 0（命令<strong>跑起来了</strong>，只是没过）</td>\n<td>未通过</td>\n<td>对应键 = <code>false</code></td>\n</tr>\n<tr>\n<td>退出码 <code>127</code> / <code>command not found</code> / 脚本文件不存在 / 该项为空字符串</td>\n<td><strong>无法判定</strong></td>\n<td><strong>省略该键，或写 <code>null</code></strong>——<strong>绝不能是 <code>false</code></strong></td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⛔ <strong>唯一的红线是不许写 <code>false</code></strong>：那是<strong>会误导人的虚报</strong>——它说的是\"检查失败了\"，\n于是有人去查代码，但真正的问题是<strong>配置过期</strong>，代码可能完全没毛病。</p>\n<p><strong>省略键与 <code>null</code> 等价，两种都可以</strong>：对消费方而言无法区分（<code>jq '.checks.lint_clean'</code>\n在两种情况下都返回 <code>null</code>）。<code>null</code> 甚至更明确——省略是歧义的（\"没看\"还是\"看了判不出\"），\n<code>null</code> 明说\"看了，判不出\"。<strong>别在这上面纠结，力气花在不写 <code>false</code> 上。</strong></p>\n<p>这与「没有检查命令可跑的阶段 → <code>checks: {}</code>」同源。</p>\n</blockquote>\n<h2>「跑不了」＝ <code>test-commands.yml</code> 过期信号（顺带检测，零额外成本）</h2>\n<p>命令跑不起来，几乎总意味着<strong>这份 yml 已经跟不上项目了</strong>——脚本改名、runner 换了、\n工具从依赖里移除、子项目路径调整。真实项目里这类漂移是常态（例如某前端框架升级后\n移除了内置 lint 子命令，而 yml 里那条命令还在）。</p>\n<p>由于<strong>各阶段本来就在跑这些命令</strong>，这个信号是白捡的。检测到时：</p>\n<ol>\n<li>在本阶段的报告里单列一条：<strong>「<code>test-commands.yml</code> 疑似过期」</strong>，写明是哪一项、\n观察到什么（退出码 / 报错原文）、以及为什么判定为\"跑不了\"而非\"没通过\"。</li>\n<li>提示补救：<code>/pdlc-test-setup --refresh</code>（重新探测并给出 diff）。</li>\n<li><strong>不要自作主张改 yml</strong>——本阶段的职责是干活，不是改配置；只报告，不动手。</li>\n</ol>\n<h2>变更方向决定自动化程度（<code>--refresh</code> 时适用）</h2>\n<p>更新这份 yml 等于<strong>改变\"通过\"的定义</strong>，所以按<strong>方向</strong>区别对待：</p>\n<table>\n<thead>\n<tr>\n<th>方向</th>\n<th>例子</th>\n<th>处理</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>让闸门变严</strong></td>\n<td>空着的 <code>e2e</code> 现在能跑了、覆盖率阈值上调</td>\n<td><strong>可自动应用</strong>，报告留痕</td>\n</tr>\n<tr>\n<td><strong>平移替换</strong></td>\n<td>命令改名但语义相同，且新命令<strong>已验证能跑</strong></td>\n<td><strong>可自动应用</strong>，报告留痕</td>\n</tr>\n<tr>\n<td><strong>让闸门变松</strong></td>\n<td>删掉某条 check、把命令改成空、下调阈值</td>\n<td><strong>必须人确认</strong>，绝不自动</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>⚠️ 这条方向规则是防「自动修复把闸门修没了」：lint 命令坏掉时，<strong>把它留空</strong>是最省事的\n\"修法\"，结果闸门悄悄松了、报告还是绿的——比不更新更危险。\n<strong>变严可以自动，变松必须由人签字。</strong></p>\n</blockquote>\n\n\n<h2>段四：交接（Handoff）</h2>\n<p>命令完成后必须输出以下格式的最终消息：</p>\n<pre><code>✅ &lt;阶段名&gt; 完成：&lt;主要产出物路径&gt;\n\uD83D\uDCCA 自检：&lt;通过数&gt;/&lt;总数&gt; 通过（若有未通过，附要点）\n\uD83D\uDCE6 状态快照：docs/.pdlc-state/&lt;feature-id&gt;.json\n\uD83D\uDC49 下一步：/pdlc-&lt;next_step&gt;\n   （如果有分叉）或 /pdlc-&lt;alt&gt;（条件：&lt;选择依据&gt;）\n</code></pre>\n<p><strong>规则：</strong></p>\n<ul>\n<li>主流程命令（写状态机的命令；下一跳见正文里「本命令的状态机取值」）必须显式输出\"下一步\"，不可省略</li>\n<li>工具型命令（Layer 3）可以没有 <code>next_step</code>，此时输出 <code>\uD83D\uDC49 下一步：（本次流程结束，无后续）</code></li>\n<li>分叉场景必须说明<strong>选择条件</strong>，例如\"若需补充测试用例 → <code>/pdlc-tdd</code>；若测试已齐 → <code>/pdlc-review</code>\"</li>\n</ul>\n\n<p><strong>本命令的 handoff 输出：</strong></p>\n<pre><code>✅ 实现完成，自检通过\n  - 设计一致性：&lt;✅/部分&gt;\n  - lint 检查：&lt;✅/X 项已自动修复/X 项待人工&gt;\n  - 测试覆盖率：&lt;XX&gt;%\n\uD83D\uDCE6 状态快照：docs/.pdlc-state/&lt;feature-id&gt;.json\n\uD83D\uDC49 下一步：/pdlc-review &lt;feature-id&gt;\n</code></pre>\n<hr>\n<p><strong>实现目标</strong>: $ARGUMENTS</p>\n","files":[{"path":"SKILL.md","sizeBytes":26677,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-23T18:54:43.422165Z","sha256":"9752CCF0F63B4D1C8F457B385C6B2E8F21D5E0D516FE0E7549714FDCDF2427C8","sizeBytes":12081},"review":null,"source":{"repositoryUrl":"https://github.com/kanfu-panda/pdlc-skills","path":"skills/pdlc-implement","license":"MIT","commit":"3cd2f02ab45cb1cd48962e0f298ae4dad9fb442f","subtreeSha":"FF81387FC97E0994F97A633E9ECD10E553F743099A8F2705E303EA520152C48D","lastSyncedAt":"2026-09-23T18:54:21.123477Z"},"reviewedAt":"2026-09-23T18:55:49.949627Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/kanfu-panda/pdlc-skills/tree/main/skills/pdlc-implement"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install kanfu-panda-pdlc-skills@llmmart"},{"target":"git","command":"git clone https://github.com/kanfu-panda/pdlc-skills.git"}]}