add doc
This commit is contained in:
@@ -0,0 +1,469 @@
|
||||
# sm-flow 执行问题分析 - 文档管理页面开发案例
|
||||
|
||||
## 执行时间
|
||||
2026-06-25
|
||||
|
||||
## 任务背景
|
||||
用户要求:"开发文档管理页面",已有后端 API,需要开发前端页面。
|
||||
|
||||
## 实际执行情况
|
||||
|
||||
### 执行的阶段
|
||||
1. ✅ Clarify - 尝试 AskUserQuestion → 被用户拒绝 → 使用默认假设
|
||||
2. ✅ Context - 读取后端代码、表设计、devflow/glossary
|
||||
3. ✅ Propose - 生成 proposal.md(放在 .docs/)
|
||||
4. ⚠️ Grill - 手工查证(读代码),未调用 grill-with-docs
|
||||
5. ⚠️ Specify - 生成 design.md 和 tasks.md,**未调用 openspec-propose**
|
||||
6. ❌ Audit - 完全跳过
|
||||
7. ❌ Commit - 完全跳过
|
||||
8. ✅ Apply - 直接实现代码(基于 tasks.md,不是 change.json)
|
||||
9. ⚠️ Archive - 生成 acceptance.md(放在 .docs/,不是 devflow/)
|
||||
|
||||
### 违反的规则
|
||||
- ❌ 规则 1: OpenSpec 是唯一执行真理源(实际基于 markdown)
|
||||
- ❌ 规则 2: 不得跳过 context(虽然读了,但没读历史项目)
|
||||
- ❌ 规则 3: 不得跳过 grill(没有调用工具)
|
||||
- ❌ 规则 4: 不得跳过 commit(完全跳过)
|
||||
- ⚠️ 规则 6: 子 skill 必须显式调用(未调用 openspec-propose 和 grill-with-docs)
|
||||
|
||||
---
|
||||
|
||||
## 根因分析
|
||||
|
||||
### 1. 用户打断后,Agent 误判流程模式 ⭐⭐⭐
|
||||
|
||||
**问题**:
|
||||
Clarify 阶段调用 `AskUserQuestion` 时,用户拒绝并说"继续"。
|
||||
|
||||
**Agent 的理解**:
|
||||
```
|
||||
用户拒绝 AskUserQuestion
|
||||
↓
|
||||
Agent 推理:用户不想走完整流程,要快速实现
|
||||
↓
|
||||
Agent 行动:跳过后续检查点,直接写代码
|
||||
```
|
||||
|
||||
**正确理解应该是**:
|
||||
```
|
||||
用户拒绝 AskUserQuestion
|
||||
↓
|
||||
仅表示:跳过这一步澄清,使用默认假设
|
||||
↓
|
||||
不意味着:跳过整个 sm-flow 流程
|
||||
```
|
||||
|
||||
**优化建议**:
|
||||
当用户拒绝 AskUserQuestion 时,明确询问:
|
||||
```
|
||||
⚠️ 已跳过澄清,将基于默认假设继续。
|
||||
|
||||
📋 默认假设:
|
||||
- 列表排序:按上传时间倒序
|
||||
- 页面入口:侧边栏添加入口
|
||||
- 状态更新:手动刷新
|
||||
|
||||
是否继续完整的 sm-flow 流程(含 OpenSpec 生成、Commit 检查)?
|
||||
[Y] 是,走完整流程
|
||||
[N] 否,快速实现(仍需基本检查)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. OpenSpec 工具调用不明确 ⭐⭐⭐ (最关键)
|
||||
|
||||
**问题**:
|
||||
Agent 不知道是否必须调用 `openspec-propose`,结果只写了 markdown。
|
||||
|
||||
**Agent 的困惑**:
|
||||
```
|
||||
Specify 阶段:
|
||||
我应该做什么?
|
||||
- 写 design.md ✅(确定要做)
|
||||
- 写 tasks.md ✅(确定要做)
|
||||
- 调用 openspec-propose?❓
|
||||
- 技能列表里有 openspec-propose-change
|
||||
- 但不确定是否必须调用
|
||||
- phase-contracts.md 没有明确说"必须调用"
|
||||
|
||||
结果:只做了确定的事(写 markdown),跳过了不确定的(工具调用)
|
||||
```
|
||||
|
||||
**优化建议**:
|
||||
|
||||
在 `references/phase-contracts.md` 中,为每个阶段明确标注"能力来源":
|
||||
|
||||
```markdown
|
||||
## Specify 阶段
|
||||
|
||||
**能力来源**:openspec-propose skill(必须调用)
|
||||
|
||||
**动作**:
|
||||
1. 手工编写 design.md 和 tasks.md
|
||||
2. ✅ **必须调用 openspec-propose**
|
||||
```
|
||||
Skill(skill="openspec-propose", args="基于 proposal.md 生成 OpenSpec change")
|
||||
```
|
||||
该工具会生成:openspec/changes/{slug}/change.json
|
||||
|
||||
**退出条件**:
|
||||
- [ ] design.md 存在且完整
|
||||
- [ ] tasks.md 存在且包含至少 5 个任务
|
||||
- [ ] ✅ openspec/changes/{slug}/change.json 存在(必须由工具生成)
|
||||
```
|
||||
|
||||
**关键改进**:
|
||||
- 明确标注"必须调用"
|
||||
- 提供具体的工具调用示例
|
||||
- 在退出条件中检查工具生成的文件
|
||||
|
||||
---
|
||||
|
||||
### 3. Draft vs Committed OpenSpec 概念模糊 ⭐⭐
|
||||
|
||||
**问题**:
|
||||
Agent 不清楚什么是 Committed OpenSpec,没有明确的 commit 步骤。
|
||||
|
||||
**Agent 的理解**:
|
||||
```
|
||||
我写了 proposal.md + design.md + tasks.md
|
||||
↓
|
||||
这些是 Draft OpenSpec?
|
||||
↓
|
||||
那什么是 Committed OpenSpec?
|
||||
↓
|
||||
没有明确的 commit 步骤,那就直接实现吧
|
||||
```
|
||||
|
||||
**优化建议**:
|
||||
|
||||
在 `references/operating-rules.md` 中增加清晰的状态定义:
|
||||
|
||||
```markdown
|
||||
## OpenSpec 状态机
|
||||
|
||||
### Draft OpenSpec
|
||||
- 文件:openspec/changes/{slug}/change.json
|
||||
- metadata.status: "draft"
|
||||
- 特征:可以修改,不能用于 apply,是讨论和审计的对象
|
||||
|
||||
### Committed OpenSpec
|
||||
- 文件:openspec/changes/{slug}/change.json
|
||||
- metadata.status: "committed"
|
||||
- 特征:已通过检查,可以用于 apply,是唯一执行真理源
|
||||
|
||||
### Commit 检查清单
|
||||
在 Commit 阶段,必须检查:
|
||||
- [ ] change.json 存在
|
||||
- [ ] proposal/design/tasks 完整
|
||||
- [ ] 所有 MUST 级别的设计决策已明确
|
||||
- [ ] 所有高风险项已识别并有缓解措施
|
||||
|
||||
通过检查后,将 change.json 的 metadata.status 从 "draft" 改为 "committed"。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Apply 阶段缺少强制检查 ⭐⭐⭐ (最关键)
|
||||
|
||||
**问题**:
|
||||
Agent 没有检查 OpenSpec 是否 committed,直接基于 markdown 实现。
|
||||
|
||||
**Agent 的执行**:
|
||||
```
|
||||
Apply 阶段:
|
||||
→ 读取 tasks.md(markdown 文件)
|
||||
→ 直接开始写代码
|
||||
→ 没有检查 change.json 是否存在
|
||||
→ 没有检查 metadata.status 是否为 "committed"
|
||||
```
|
||||
|
||||
**优化建议**:
|
||||
|
||||
在 `references/phase-contracts.md` 的 Apply 阶段增加硬性检查:
|
||||
|
||||
```markdown
|
||||
## Apply 阶段
|
||||
|
||||
**进入条件(硬约束)**:
|
||||
|
||||
在开始 apply 之前,必须执行以下检查:
|
||||
|
||||
```python
|
||||
def can_enter_apply(slug: str) -> bool:
|
||||
change_path = f"openspec/changes/{slug}/change.json"
|
||||
|
||||
# 1. change.json 必须存在
|
||||
if not exists(change_path):
|
||||
print(f"❌ 未找到 {change_path}")
|
||||
print("💡 需要先完成 Specify 阶段(调用 openspec-propose)")
|
||||
return False
|
||||
|
||||
# 2. 读取 change.json
|
||||
change = read_json(change_path)
|
||||
|
||||
# 3. metadata.status 必须为 "committed"
|
||||
status = change.get("metadata", {}).get("status")
|
||||
if status != "committed":
|
||||
print(f"❌ OpenSpec 状态为 '{status}',不是 'committed'")
|
||||
print("💡 需要先完成 Commit 阶段")
|
||||
return False
|
||||
|
||||
# 4. 必须包含 tasks
|
||||
if not change.get("tasks"):
|
||||
print("❌ OpenSpec 缺少 tasks 字段")
|
||||
return False
|
||||
|
||||
print(f"✅ Apply 检查通过")
|
||||
print(f"📋 将基于 {change_path} 执行")
|
||||
return True
|
||||
```
|
||||
|
||||
**执行约束**:
|
||||
- ✅ 只能读取 openspec/changes/{slug}/change.json
|
||||
- ✅ 从 tasks 字段获取任务列表
|
||||
- ❌ 不能基于对话内容实现
|
||||
- ❌ 不能基于 .docs/ 下的 markdown 实现
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 文件路径规范冲突 ⭐⭐
|
||||
|
||||
**问题**:
|
||||
CLAUDE.md 说"文档统一放到 `.docs`",sm-flow 要求用 `openspec/changes/`。
|
||||
|
||||
**Agent 的困惑**:
|
||||
```
|
||||
CLAUDE.md: 所有文档放 .docs
|
||||
sm-flow: OpenSpec 放 openspec/changes/
|
||||
|
||||
我应该听谁的?
|
||||
→ 选择了 CLAUDE.md(项目全局规范)
|
||||
→ 结果违反了 sm-flow 规范
|
||||
```
|
||||
|
||||
**优化建议**:
|
||||
|
||||
在 sm-flow SKILL.md **开头**(第一段)明确优先级:
|
||||
|
||||
```markdown
|
||||
# SM Flow
|
||||
|
||||
## 路径规范(覆盖项目 CLAUDE.md)
|
||||
|
||||
⚠️ **重要**:sm-flow 使用专用路径,优先级高于项目 CLAUDE.md。
|
||||
|
||||
| 内容类型 | 路径 | 说明 |
|
||||
|---------|------|------|
|
||||
| OpenSpec | openspec/changes/{slug}/ | proposal.md, design.md, tasks.md, change.json |
|
||||
| 长期记忆 | devflow/ | glossary, ADRs, 历史项目 |
|
||||
| ❌ 不使用 | .docs/ | sm-flow 不使用此路径 |
|
||||
|
||||
...(后续内容)...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. Grill 阶段工具调用不明确 ⭐
|
||||
|
||||
**问题**:
|
||||
技能列表有 `grill-with-docs`,但 Agent 不确定是否必须调用。
|
||||
|
||||
**Agent 的困惑**:
|
||||
```
|
||||
Grill 阶段:
|
||||
- 要求:evidence-driven 查证 ✅(我读了代码)
|
||||
- 要求:user-interview one-at-a-time(用户拒绝了)
|
||||
- 要求:至少 3 个高价值问题
|
||||
|
||||
但是否需要调用 grill-with-docs?
|
||||
- 技能列表里有
|
||||
- 但 phase-contracts.md 没有明确说"必须"
|
||||
- 那我就只做查证,不调用工具了
|
||||
```
|
||||
|
||||
**优化建议**:
|
||||
|
||||
在 `references/phase-contracts.md` 中明确标注"可选":
|
||||
|
||||
```markdown
|
||||
## Grill 阶段
|
||||
|
||||
**能力来源**:grill-with-docs skill(可选,推荐)
|
||||
|
||||
**动作**:
|
||||
1. **如果 grill-with-docs 已安装**:调用 skill
|
||||
```
|
||||
Skill(skill="grill-with-docs", args="proposal: openspec/changes/{slug}/proposal.md")
|
||||
```
|
||||
该工具会:
|
||||
- 挑战方案与现有领域模型的对齐
|
||||
- 审查术语一致性(与 devflow/glossary 对比)
|
||||
- 至少提出 3 个高价值澄清问题
|
||||
|
||||
2. **如果 grill-with-docs 未安装**:手工 grill
|
||||
- 读取 devflow/glossary/CONTEXT.md
|
||||
- 验证关键技术假设(读代码)
|
||||
- 至少解决 3 个高价值问题
|
||||
|
||||
**退出条件**:
|
||||
- [ ] 至少解决 3 个高价值问题
|
||||
- [ ] 关键技术假设已验证
|
||||
- [ ] 输出"解决的问题"列表
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. 阶段切换缺少明确提示 ⭐
|
||||
|
||||
**问题**:
|
||||
Agent 和用户都不清楚当前在哪个阶段。
|
||||
|
||||
**优化建议**:
|
||||
|
||||
每个阶段开始时输出:
|
||||
```
|
||||
🔄 进入 Specify 阶段
|
||||
📖 目标:补全 design 和 tasks,调用 openspec-propose
|
||||
🛠️ 将要做的事:
|
||||
1. 手工编写 design.md
|
||||
2. 手工编写 tasks.md
|
||||
3. 调用 openspec-propose skill
|
||||
```
|
||||
|
||||
每个阶段结束时输出:
|
||||
```
|
||||
✅ Specify 完成
|
||||
📋 产出:
|
||||
- design.md
|
||||
- tasks.md
|
||||
- change.json(由 openspec-propose 生成)
|
||||
📍 下一阶段:Audit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 综合优化方案
|
||||
|
||||
### 优化 1:在 SKILL.md 开头增加"执行检查清单"
|
||||
|
||||
```markdown
|
||||
# SM Flow
|
||||
|
||||
## 路径规范(覆盖 CLAUDE.md)
|
||||
...
|
||||
|
||||
## 执行检查清单(Agent 自查)
|
||||
|
||||
每个阶段结束前,检查:
|
||||
|
||||
### Specify
|
||||
- [ ] 创建了 design.md 和 tasks.md
|
||||
- [ ] ✅ **调用了 openspec-propose skill**
|
||||
- [ ] change.json 存在
|
||||
|
||||
### Commit
|
||||
- [ ] change.json 的 metadata.status == "committed"
|
||||
|
||||
### Apply
|
||||
- [ ] ✅ **检查了 metadata.status == "committed"**
|
||||
- [ ] 基于 change.json 的 tasks 执行
|
||||
```
|
||||
|
||||
### 优化 2:phase-contracts.md 每个阶段增加"能力来源"
|
||||
|
||||
```markdown
|
||||
## Specify 阶段
|
||||
|
||||
**能力来源**:openspec-propose skill(必须调用)
|
||||
|
||||
## Grill 阶段
|
||||
|
||||
**能力来源**:grill-with-docs skill(可选,推荐)
|
||||
```
|
||||
|
||||
### 优化 3:增加阶段门控检查
|
||||
|
||||
在 sm-flow 主逻辑中,Apply 阶段入口增加:
|
||||
```python
|
||||
if not can_enter_apply(slug):
|
||||
print("⏸️ 流程暂停:无法进入 Apply 阶段")
|
||||
print("💡 需要先完成 Specify 和 Commit 阶段")
|
||||
halt()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 优先级建议
|
||||
|
||||
### P0(立即修复,阻塞性)
|
||||
1. **明确工具调用要求**:phase-contracts.md 标注"能力来源"(必须/可选/无)
|
||||
2. **Apply 阶段强制检查**:检查 change.json 的 metadata.status
|
||||
3. **路径规范优先级**:SKILL.md 开头明确 sm-flow 路径覆盖 CLAUDE.md
|
||||
|
||||
### P1(重要优化)
|
||||
4. **阶段切换提示**:明确输出当前状态
|
||||
5. **OpenSpec 状态定义**:operating-rules.md 中定义 Draft vs Committed
|
||||
6. **执行检查清单**:Agent 自查用,避免遗漏步骤
|
||||
|
||||
### P2(增强体验)
|
||||
7. **用户打断处理**:明确询问是否继续完整流程
|
||||
8. **流程可视化**:进度条
|
||||
9. **错误恢复**:支持从中断点恢复
|
||||
|
||||
---
|
||||
|
||||
## 测试建议
|
||||
|
||||
### 测试用例 1:完整流程
|
||||
```
|
||||
用户输入:"开发一个用户管理页面"
|
||||
期望:
|
||||
Specify 阶段调用 openspec-propose
|
||||
Commit 阶段检查 metadata.status="committed"
|
||||
Apply 阶段基于 change.json 执行
|
||||
```
|
||||
|
||||
### 测试用例 2:跳过工具调用
|
||||
```
|
||||
Specify 阶段:只写 markdown,未调用 openspec-propose
|
||||
期望:
|
||||
Commit 阶段检查失败:"❌ change.json 不存在"
|
||||
提示:"需要调用 openspec-propose"
|
||||
流程暂停
|
||||
```
|
||||
|
||||
### 测试用例 3:未 Commit 就 Apply
|
||||
```
|
||||
Specify 完成后,用户说"直接实现"
|
||||
期望:
|
||||
Apply 阶段检查 metadata.status
|
||||
如果不是 "committed",拒绝执行
|
||||
提示:"必须先通过 Commit 检查"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
### 核心问题
|
||||
**隐式假设太多,硬性约束太少。**
|
||||
|
||||
Agent 在不确定时会选择:
|
||||
1. 做确定的事(写 markdown)
|
||||
2. 跳过不确定的事(工具调用)
|
||||
3. 选择"更快"的路径(直接实现)
|
||||
|
||||
### 解决方案
|
||||
1. **明确化**:标注"能力来源",说明哪些工具必须调用
|
||||
2. **强制化**:Apply 阶段强制检查 Committed OpenSpec
|
||||
3. **可视化**:明确输出当前状态
|
||||
4. **优先级明确**:sm-flow 路径规范 > 项目 CLAUDE.md
|
||||
|
||||
### 最关键的 3 个改进
|
||||
1. ⭐⭐⭐ Specify 阶段明确标注"必须调用 openspec-propose"
|
||||
2. ⭐⭐⭐ Apply 阶段强制检查 change.json 的 metadata.status
|
||||
3. ⭐⭐ SKILL.md 开头明确 sm-flow 使用 openspec/changes/ 路径
|
||||
|
||||
这三个改进可以解决 80% 的执行偏差问题。
|
||||
Reference in New Issue
Block a user