学习指南: 应用部分 2. 规格缺陷诊断

模块「应用部分 2. 规格缺陷诊断」中第 3 / 5 节课
您正在未登录状态下查看课程。 请登录,以保存进度并参加测试。

主题:应用部分 2. 规范缺陷诊断

难度等级:中级

预计学习时间:8-12 小时(理论:3 小时,实践:5-9 小时)

前置知识: 第一卷第 7 部分:否定性需求(negative requirements)

第一卷第 20 部分:SDD 反模式(SDD antipatterns)

第一卷第 11 部分:appointments-api 领域与 Hono JSX 入门

熟练掌握 YAML/JSON 和 JSON Schema

具备在 Plan Mode 下使用 Qwen Code 的经验

理解 SDD 生命周期:Specify → Plan → Tasks → Implement

学习目标: 能够独立地在事件分类规范中引入恰好一个受控缺陷,并将其归类为 cycle、priority_conflict 或 hidden_out_of_scope

通过可测量指标 ask_storm、stage_regress 和 phase_context_loss 诊断 Qwen Code 的卡顿点,并记录在 validation.md 中

制定可验证的覆盖规则(override)来解决优先级冲突,并将其转换为 Given/When/Then + JSON Schema

执行完整的 SDD 回路反向测试 Specify → Plan → Tasks → Implement,以验证修复的稳健性

创建 poisoned/fixed 规范对,在 validation.md 中仅通过一行恢复记录即可修复,且可迁移至毕业设计项目

概述:本学习指南介绍「受控缺陷规范」这一工程技术——一种故意在事件分类规范中引入单个缺陷的方法,用于检验智能体(Qwen Code)的诊断能力并练习需求恢复技术。该技术类似于变异测试,但应用于规范层面而非代码层面。核心原则:一次变异、一个症状、一个恢复标准。本章基于第一卷的材料(否定性需求和 SDD 反模式),并将其发展为可控实验方向:不再是随机故障,而是制造可预测、可测量、可修复的缺陷。教学案例为 appointments-api 路由的延迟增长;毕业设计案例为 high_memory_usage。工作成果是一种可复现的规范破坏与恢复技术,作为稳定的契约。

关键概念: 受控缺陷(controlled defect):在规范中有意引入的单个缺陷,其类别和位置均受限制。与随机错误或累积多个缺陷相对。主要规则:每次迭代仅一次变异、一个预期症状、一个恢复标准。用于检验智能体的诊断能力并练习恢复技术。

有毒规范(poisoned specification):带有单个受控缺陷的规范的教学标签。不应按字面理解:「毒」并非混乱,而是严格定量的变异。创建为 poisoned-spec.md,并在 fixed-spec.md 中修复,同时记录在 validation.md 中。

Poisoned/fixed 对:一对产物:poisoned-spec.md(含缺陷的规范)和 fixed-spec.md(修复后的规范)。两者之间的差异恰好是一个变异及其补丁。毕业设计的最小合格集包括缺陷类别、恢复行和冲突未复现的事实。

缺陷类别 — cycle:事件分类规范中状态之间的循环依赖。示例:WAIT_APPROVAL → VALIDATE_ESCALATION → WAIT_APPROVAL。智能体陷入循环,无法退出有限状态机。通过状态图循环搜索进行验证(find_spec_loops.py)。

缺陷类别 — priority conflict:两个具有相同优先级的规则导致互斥操作。示例:「30 秒内升级 P0」(priority=100)和「任何升级都需要人工审批」(priority=100)。智能体无法决定应用哪个规则。通过 check_rule_priority.py 进行验证。

缺陷类别 — hidden out of scope:需求强制执行的操作在 constraints 中被禁止。示例:在验收测试中创建 Jira 工单,但限制条件禁止 Jira。缺陷「隐藏」在语义中而非语法中。需要通过 JSON Schema 和验收测试进行验证。

指标 ask storm:诊断特征:智能体重复提出澄清请求但未出现新数据。每次会话中请求已在先前消息中提及的数据的新消息计为 +1。当 requirements.md 或 clarifications.md 中添加新字段时重置。首次通过时手动计数的启发式方法;可通过 qwen --output-format json 的转录解析器自动化。

指标 stage regress:诊断特征:SDD 当前阶段(specify/plan/tasks/implement)在没有在 validation.md 中明确记录原因的情况下回退到前一阶段。每次回退计为 +1。表明规范不稳定或需求中存在未解决的冲突。

指标 phase context loss:诊断特征:阶段上下文丢失,当智能体在新阶段引用当前 requirements.md 或 plan.md 中不存在的规则时。布尔值:真/假。表明规范在 SDD 各阶段之间未保持连续性。

覆盖规则(override):解决优先级冲突的正式策略。定义在时间边缘或临界性边缘哪个需求胜出。示例:p0_time_critical_override 高于 manual_gate_for_noncritical。必须可通过 JSON Schema 验证,并在验收测试中体现。

唯一真实来源:消除规范文本、JSON Schema 和验收测试之间差异的原则。YAML 中声明的优先级必须引用测试和 Schema 中的相同层次结构,不得有并行解释。

验证不变量:关键转换前后的状态固定。对于升级:转换前 — severity、deadline、owner_state;转换后 — channel、audit_record、reason_code。确保可追溯性,防止以失控为代价的形式上「解决」冲突。

SDD 回路反向测试:修复缺陷后对 Specify → Plan → Tasks → Implement 的完整验证。用于确认缺陷未从规则迁移到分解(Tasks)或从分解迁移到实现(Implement)。仅当连续两次运行无新的 ask_storm、stage_regress 和优先级冲突时才视为可靠。

validation.md 中的恢复行:修复后不再复现的事实的正式记录。示例:priority_conflict=false && escalation_path_resolved=P0 && audit_required=true。作为就绪标准和审查控制事实。

练习: 标题:练习 1:创建含优先级冲突的 poisoned-spec.md

问题:采用教学案例 appointment_latency。创建文件 poisoned-spec.md(或 specs/appointment-latency-poisoned.yaml),包含两条冲突规则:(1) P0 在 30 秒内升级,priority=100;(2) 任何升级需要人工审批,priority=100。两条规则必须为正式格式(YAML/JSON),而非注释。在启动智能体前记录预期症状。

解答:步骤 1:从第一卷第 11 部分复制基础规范。步骤 2:添加两条 priority=100 相同且导致互斥操作的规则。步骤 3:确保冲突在数据中可见:运行 python3 scripts/spec_ci/check_rule_priority.py — 应显示冲突。步骤 4:在 validation.md 中记录预期症状:ask_storm >= 4 || stage_regress >= 2 || escalation_path_resolved=false。步骤 5:在 Plan Mode 下启动 Qwen Code 且不修改文件,记录实际指标。

难度:初级

标题:练习 2:通过 find_spec_loops.py 诊断循环

问题:在规范中引入循环依赖:WAIT_APPROVAL → VALIDATE_ESCALATION → WAIT_APPROVAL。启动智能体并记录 cycle 的表现方式。使用 [项目脚本] find_spec_loops.py 进行可视化。比较智能体在 cycle 和 priority_conflict 下的行为:ask_storm 和 stage_regress 指标有何不同?

解答:步骤 1:在 poisoned-spec.md 中将线性转换替换为循环:VALIDATE_ESCALATION.when = 'escalation_attempted == true', then = 'goto WAIT_APPROVAL'。步骤 2:运行 find_spec_loops.py — 获得带反向边的 DOT 图。步骤 3:在 Plan Mode 下启动智能体,记录:cycle 时 stage_regress 占主导(智能体返回同一阶段),priority_conflict 时 ask_storm 占主导(智能体多次澄清同一问题)。步骤 4:在 validation.md 中记录差异:cycle 为 cycle_count > 0 && stage_regress >= 3,priority_conflict 为 ask_storm >= 4 && escalation_path_resolved=false。

难度:中级

标题:练习 3:通过覆盖规则和 JSON Schema 解决冲突

问题:通过 p0_time_critical_override 修复 appointment_latency 中的 priority_conflict。规则必须:(a) 在负责人不可用时允许 P0 自动升级;(b) 保留 human_audit_required=true 作为事后审计;(c) 使人工屏障对 P1-P3 保持阻塞。将解决方案转换为 JSON Schema,禁止返回隐藏的人工确认。

解答:步骤 1:在 fixed-spec.yaml 中创建 p0_time_critical_override:priority=100, when: severity=P0 && owner_unresponsive=true, then: escalation=critical_phone, human_audit_required=true。步骤 2:将 human_gate_noncritical 的 priority 降至 10(P1-P3)。步骤 3:在 JSON Schema 中添加 if-then 条件:若 severity=P0 && owner_unresponsive=true,则 required: [auto_escalation_channel, human_audit_required, reason_code],常量分别为 critical_phone、true、time_critical_override。步骤 4:运行 lint_spec.py — 检查原子性。步骤 5:运行 check_rule_priority.py — 确认冲突已消除。步骤 6:在 validation.md 中记录恢复行:priority_conflict=false && escalation_path_resolved=P0 && audit_required=true。

难度:中级

标题:练习 4:完整反向测试并迁移至毕业设计

问题:对修复后的规范执行 Specify → Plan → Tasks → Implement 反向测试。确认各阶段均未返回原始冲突。将结果迁移至 capstone/ 的 high_memory_usage 案例:将 priority_conflict 类别适配为 restart_pod 与人工审批之间的冲突。

解答:步骤 1:依次启动 Qwen Code:specify(requirements.md)、plan(plan.md)、tasks(tasks.md)、implement。每阶段后在 validation.md 中记录指标。步骤 2:若 Tasks 产生不兼容操作 — 缺陷迁移至分解,重做计划。若 Implement 通过但测试失败 — 可接受行为边界描述不完整。步骤 3:对于 capstone/high_memory_usage:defect_class=priority_conflict,有毒版本:memory_percent>=90 允许 restart_pod,但任何 restart_pod 需要相同 priority 的人工审批。步骤 4:修复版本:restart_pod 作为 stateless pod 的预批准操作,首次生产启动需要 human_review_for_first_run=true。步骤 5:验证:priority_conflict=false && action=restart_pod && human_review_for_first_run=true。

难度:高级

标题:练习 5:隐藏越界(hidden_out_of_scope)

问题:创建一条规范,其中需求强制创建 Jira 工单,但 constraints 禁止 Jira。缺陷必须「隐藏」——语法上规范正确,语义上违反约束。通过 phase_context_loss 进行诊断。

解答:步骤 1:在 constraints.md 中添加 forbidden_integrations: [jira]。步骤 2:在 poisoned-spec.md 中添加规则:when: severity=P2, then: create_ticket_in=jira。步骤 3:启动智能体 — 它可能形式上继续,但在 Implement 阶段引用 jira,而 jira 不在允许列表中。步骤 4:记录 phase_context_loss=true:智能体在 Implement 阶段引用当前 constraints 中不存在的规则。步骤 5:修复:将 jira 替换为允许渠道(如 internal_tracker)或在 constraints 中添加例外。步骤 6:通过 JSON Schema 验证:forbidden_integrations 应为受控列表的 enum,而 then 应引用该 enum。

难度:高级

案例研究: 标题:案例:appointments-api 延迟增长与生产团队中的 priority_conflict 诊断

场景:在线医生预约平台(第一卷第 11 部分的领域)。appointments-api 路由显示 p95 延迟增长至 2.5 秒。SRE 团队收到 severity=P0 告警。分类规范要求:(1) 30 秒内升级 P0;(2) 任何升级需要人工审批。两条规则均为 priority=100。值班工程师在飞机上,无法确认。作为事件规划器的 Qwen Code 陷入澄清循环。

挑战:智能体 12 次询问「请确认负责人是否可用」,尽管第一条消息中已注明 owner_unresponsive=true(ask_storm=12)。随后智能体从 Plan 阶段返回 Specify,提议「重新审查需求」(stage_regress=2)。升级未在 30 秒内发生,而是耗时 4 分钟。团队通过电话手动升级,损失了 SLA 和审计追踪。

解决方案:事件后,团队应用了受控缺陷规范技术。创建 poisoned-spec.md 复现冲突。在 fixed-spec.md 中引入 p0_time_critical_override:P0 且 owner_unresponsive=true 时立即通过 critical_phone 升级,human_audit_required 移至事后审计。P1-P3 保留人工屏障。JSON Schema 固定 auto_escalation_channel、human_audit_required、reason_code 字段的强制性。执行反向测试:Specify → Plan → Tasks → Implement — 指标 ask_storm=0、stage_regress=0、phase_context_loss=false。

结果:P0 响应时间从 4 分钟降至 23 秒。审计追踪恢复:所有自动升级均有 reason_code=time_critical_override。规范成为可重复测试:团队每月在教学模式下运行 poisoned/fixed 对。方法迁移至毕业设计项目 high_memory_usage,适配为 restart_pod 与人工审批。

经验教训: 相同 priority=100 的优先级冲突在正常工作时不会显现,但在压力场景(owner_unresponsive)中变得致命

ask_storm 和 stage_regress 指标可定量区分规范缺陷与「智能体不良行为」

覆盖规则必须改变可验证需求,而非仅文本解释 — 否则智能体将返回旧解释

完整回路反向测试是必要的:requirements.md 中的局部修复可能将缺陷迁移至 plan.md 或 tasks.md

JSON Schema 作为「唯一真实来源」可防止通过智能体的相邻步骤形成隐藏约定

相关概念: priority_conflict

ask_storm

stage_regress

p0_time_critical_override

SDD 回路反向测试

唯一真实来源

validation.md 中的恢复行

标题:案例:毕业设计项目中 high_memory_usage 的技术适配

场景:学生 SDD 课程的毕业设计。领域:云基础设施,告警 high_memory_usage(memory_percent >= 90 持续 10 分钟)。学生需要在新领域展示规范缺陷诊断能力,同时保留教学案例的缺陷类别。

挑战:直接复制 appointment_latency 不适用:不同实体(pod、重启、内存)、不同风险(stateful 与 stateless、重启时数据丢失)。需要适配 priority_conflict,同时保留结构:两条相同 priority 的规则导致互斥操作,以及通过 override 的正式解决。

解决方案:学生创建 poisoned-spec.md:memory_percent>=90 允许 restart_pod,但任何 restart_pod 需要人工审批,两者均为 priority=100。在 fixed-spec.md 中引入 stateless/stateful 区分:restart_pod 是 stateless pod 的预批准操作,首次生产启动需要 human_review_for_first_run=true。这保留了审计,但对已知配置解锁了自动操作。JSON Schema 要求 pod_type、first_run_flag、review_record 字段。恢复行:priority_conflict=false && action=restart_pod && human_review_for_first_run=true。

结果:评审确认通过:缺陷类别已识别,补丁改变可验证规则,反向测试干净。学生指出最大难点并非引入缺陷,而是严格限制为恰好一个:初次尝试同时在 pod 状态图中包含 cycle,导致诊断不可区分。

经验教训: 将缺陷类别迁移至新领域需要重新思考实体,但保留冲突结构

「每次迭代一个缺陷」的限制在实践中是最难遵守的规则;自然倾向「加强」教学案例会导致不可区分的追踪

human_review_for_first_run=true 是可扩展覆盖规则的示例:适用于 memory、appointment 及新领域

毕业设计评审重视的不是产物数量,而是精确度:恰好一个缺陷、一行恢复、可重复结果

相关概念: poisoned/fixed 对

priority_conflict

human_review_for_first_run

stateless 与 stateful

恢复行

毕业设计迁移

学习建议: 从手动计数指标开始(validation.md 中用铅笔记录),而非自动化。理解启发式方法比脚本更重要:你应该能感知 ask_storm 何时是规范缺陷,何时是外部世界上下文不完整

在启动智能体前创建 poisoned-spec.md 并提前记录预期症状。这防止事后合理化:「啊,它本来就该卡住」——这种逻辑剥夺了技术的可控性

使用教学最小集:首次通过用 appointment_latency,毕业设计再用 high_memory_usage。不要试图并行掌握两个领域 — 实体差异(延迟与内存、升级与重启)会分散对技术本身的学习

在启动 Qwen Code 前通过项目脚本(find_spec_loops.py、check_rule_priority.py)验证缺陷。若脚本未捕获冲突 — 缺陷隐藏在注释或自然语言中,而非正式规范内

反向测试时在每个阶段后记录指标,而非最后。缺陷可能迁移:Specify 干净 → Plan 干净 → Tasks 产生不兼容操作。典型迹象:Plan→Tasks 边界的 stage_regress

同时练习 Given/When/Then 和 JSON Schema 的转换,而非先后。它们解决问题的不同方面:GWT 是可验证场景,JSON Schema 禁止不可接受状态。缺少任一都会为智能体留下漏洞

课堂学习建议:两人一组 — 一人创建 poisoned-spec,另一人无提示诊断。分析后交换角色。这模拟了真实情况:规范作者对自己缺陷「盲目」

维护「变异日志」:记录所有缺陷引入尝试,包括失败的。常见错误:「智能体没卡住,但应该卡住」。这不是失败,而是数据:可能缺陷在注释中,或 priority 不同,或智能体使用了隐性知识。日志有助于校准直觉

不要推迟 ask_storm、stage_regress、phase_context_loss 指标「到以后」。首次通过时它们看似模糊,但正是它们将「智能体的奇怪回答」转化为诊断产物。在短会话(3-5 条消息)上练习

考核前自检:确保 poisoned 与 fixed 之间的 diff 恰好触及一条可验证规则。若 diff 仅在注释或文本解释中,修复不算数

额外资源: 第一卷第 7 部分(否定性需求):缺陷诊断所依据的基础理论。理解为何优先级冲突是失控的否定性需求所必需

第一卷第 20 部分(SDD 反模式):规范经典错误目录,作为变异的来源。Cycle、priority_conflict、hidden_out_of_scope 均衍生自这些反模式

第一卷第 11 部分(第二阶段项目):appointments-api 原始领域,Hono JSX 上的智能体页面。appointment_latency 教学案例的上下文

Examples/spec-ci/readme.md:可运行的基础规范网关(Spec CI)类比。自动检查需求和计划形式,接近本章的可运行类比

Book2/examples/templates/validation.md:验证记录表单模板。用于固定预期症状和恢复行

Github spec kit quickstart (https://github.github.io/spec-kit/quickstart.html):Specify → Plan → Tasks → Implement 各阶段的官方描述。本章引用 SDD 方法的外部规范

[项目脚本] find spec loops.py:搜索规范状态图循环的脚本。生成 DOT 图用于可视化

[项目脚本] check rule priority.py:检查 YAML 规范中优先级冲突的脚本。通过 priority 数值匹配捕获 priority_conflict

[项目脚本] lint spec.py:检查规范原子性的脚本。反向测试中用于验证 fixed 版本

Qwen --output-format json + 聚合脚本:自动化 ask_storm、stage_regress、phase_context_loss 指标的路径。教学通过时为转录解析器,高级阶段为 CI 指标

总结:本章的关键成就是将规范从愿望集合转变为稳健、可复现的契约。受控缺陷规范技术(poisoned/fixed 对)提供四个工具:(1) 每次迭代一个缺陷,附带可测量症状;(2) 通过 ask_storm、stage_regress、phase_context_loss 诊断卡顿;(3) 通过覆盖规则、Given/When/Then 和 JSON Schema 正式解决冲突;(4) 完整 SDD 回路反向测试验证稳健性。教学最小集 — appointment_latency 的 poisoned-spec.md、fixed-spec.md 和 validation.md 中的恢复行;毕业设计迁移 — 将相同 priority_conflict 类别应用于 high_memory_usage。下一章将这些规则整理为 constitution.md,作为首个项目公投。

我的笔记
0 / 10000

笔记保存在当前浏览器中。在其他设备上将不会显示。

课程菜单

课程

Production SDD for Qwen Code CLI. Part 2
进度 0 / 100