Skip to content

Commit 2a246bc

Browse files
committed
refactor(planning-docs): 统一迁移索引与变更图输出契约
1 parent 7168d28 commit 2a246bc

10 files changed

Lines changed: 114 additions & 25 deletions

File tree

plugins/aisee-plugin/references/planning-doc-frontmatter.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- Design Spec
1313
- Design Assets 索引 / brief
1414
- Implementation Brief
15+
- Spec Migration 索引 / 草案
1516
- Reflect
1617

1718
不适用于:
@@ -28,7 +29,7 @@
2829

2930
```yaml
3031
title: "文档标题"
31-
doc_type: "srs | ui-content | architecture | design-spec | design-assets | implementation-brief | reflect"
32+
doc_type: "srs | ui-content | architecture | design-spec | design-assets | implementation-brief | spec-migration | reflect"
3233
status: "draft | active | superseded | archived"
3334
date: "YYYY-MM-DD"
3435
scope: "项目 / 模块 / 功能 / change"

plugins/aisee-plugin/skills/aisee-change-plan/SKILL.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ description: 将已确认需求、轻量修复、技术调研或项目事实映
1414
- 选择每个 change 的 schema。
1515
- 在输出 `/opsx:new` 前做 schema availability preflight:优先读取 `aisee schemas list/check --json` 或项目内 `openspec/schemas/<schema>/schema.yaml` 状态。
1616
- 规划 change 边界、依赖顺序和并行关系。
17+
- 使用 Mermaid 语法块输出依赖顺序和并行关系,作为长期可读性 contract。
1718
- 输出 source-map seed,仅当所选 schema 生成 `source-map.md`
1819
- 输出可复制的 `/opsx:new "<change>" --schema <schema>` 命令,并把它视为后续 author / implementation 的 schema metadata 合同。
1920
- 保存 change plan 到 `aisee/docs/change-plan/`

plugins/aisee-plugin/skills/aisee-change-plan/evals/evals.json

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
"邀请链接过期规则仍是待确认业务规则。"
2020
]
2121
},
22-
"expected_output": "输出 change 边界、依赖、复杂度、In Scope/Out of Scope 和执行顺序。所有命令必须使用 /opsx:new \"<change>\" --schema <schema>,不得输出 /opsx:propose。应保留 architecture 中的 RBAC 复用事实和邀请链接规则待确认项,并说明后续通过 aisee:change-author(必要时配合 /opsx:continue)按 schema 补齐 artifacts;不得建议使用旧的 change design skill 作为固定后续步骤。",
22+
"expected_output": "输出 change 边界、依赖、复杂度、In Scope/Out of Scope 和执行顺序。依赖顺序和并行关系必须使用 Mermaid 语法块表达。所有命令必须使用 /opsx:new \"<change>\" --schema <schema>,不得输出 /opsx:propose。应保留 architecture 中的 RBAC 复用事实和邀请链接规则待确认项,并说明后续通过 aisee:change-author(必要时配合 /opsx:continue)按 schema 补齐 artifacts;不得建议使用旧的 change design skill 作为固定后续步骤。",
2323
"expected_outputs": [
2424
"输出可独立交付的 change 边界、依赖、复杂度、In Scope/Out of Scope 和执行顺序。",
25+
"使用 Mermaid 语法块表达依赖顺序和并行关系。",
2526
"使用 /opsx:new \"<change>\" --schema <schema>。",
2627
"保留 RBAC 复用事实和邀请链接过期规则待确认项。",
2728
"说明后续通过 aisee:change-author 或 /opsx:continue 补齐 artifacts。"
@@ -32,6 +33,7 @@
3233
],
3334
"must_include": [
3435
"change 边界",
36+
"Mermaid 依赖图",
3537
"依赖顺序",
3638
"source-map seed",
3739
"/opsx:new 命令"
@@ -61,17 +63,18 @@
6163
"已有项目、权限和列表页存在。"
6264
]
6365
},
64-
"expected_output": "判断这是单个小 change,不为了流程而规划多个 change。输出一个 change 详情块和单条 /opsx:new 命令,不得输出 /opsx:propose,也不得新增未确认的后端、数据库或 UI 需求。",
66+
"expected_output": "判断这是单个小 change,不为了流程而规划多个 change。输出一个 change 详情块、单节点 Mermaid 依赖图和单条 /opsx:new 命令,不得输出 /opsx:propose,也不得新增未确认的后端、数据库或 UI 需求。",
6567
"expected_outputs": [
6668
"判断为单个小 change。",
67-
"输出一个 change 详情块和单条 /opsx:new 命令。",
69+
"输出一个 change 详情块、单节点 Mermaid 依赖图和单条 /opsx:new 命令。",
6870
"说明不需要为了流程拆成多个 change。"
6971
],
7072
"must_ask": [
7173
"状态枚举是否已有并可复用?"
7274
],
7375
"must_include": [
7476
"单 change 判断",
77+
"Mermaid 依赖图",
7578
"Out of Scope",
7679
"/opsx:new 命令"
7780
],
@@ -100,18 +103,19 @@
100103
"输入章节混合了非需求内容。"
101104
]
102105
},
103-
"expected_output": "不得把背景、UI 页面、API 设计、数据库设计、测试计划或上线计划规划成同名 change。应围绕退款处理、退款报表、退款状态查看等可独立交付能力规划 change,并在整体理由中说明输入章节被拒绝或合并为边界提示。每个 change 必须包含 FR 引用、Out of Scopesource-map seed。",
106+
"expected_output": "不得把背景、UI 页面、API 设计、数据库设计、测试计划或上线计划规划成同名 change。应围绕退款处理、退款报表、退款状态查看等可独立交付能力规划 change,并在整体理由中说明输入章节被拒绝或合并为边界提示。每个 change 必须包含 FR 引用、Out of Scopesource-map seed 和 Mermaid 依赖图",
104107
"expected_outputs": [
105108
"拒绝把背景、UI 页面、API 设计、数据库设计、测试计划或上线计划作为 change 边界。",
106109
"围绕退款处理、退款报表、退款状态查看规划 change。",
107-
"每个 change 包含 FR 引用、Out of Scopesource-map seed。"
110+
"每个 change 包含 FR 引用、Out of Scopesource-map seed 和 Mermaid 依赖图"
108111
],
109112
"must_ask": [
110113
"退款处理、报表和状态查看是否需要同批交付?",
111114
"客服、财务、用户权限边界是否已确认?"
112115
],
113116
"must_include": [
114117
"FR 引用",
118+
"Mermaid 依赖图",
115119
"Out of Scope",
116120
"source-map seed",
117121
"拒绝源章节直接作为边界的说明"
@@ -140,7 +144,7 @@
140144
"库存一致性策略影响 change 边界和实现路径。"
141145
]
142146
},
143-
"expected_output": "必须保留 [ARCHITECTURE-DECISION-REQUIRED],不得替用户选择库存一致性方案。若该决策影响独立交付边界,应输出需要先补 Architecture 决策的 blocker 或将其作为首个风险验证/决策 change,而不是直接规划具体实现边界。",
147+
"expected_output": "必须保留 [ARCHITECTURE-DECISION-REQUIRED],不得替用户选择库存一致性方案。若该决策影响独立交付边界,应输出需要先补 Architecture 决策的 blocker 或将其作为首个风险验证/决策 change,而不是直接规划具体实现边界。依赖关系如需展示,必须使用 Mermaid 语法块。",
144148
"expected_outputs": [
145149
"保留 [ARCHITECTURE-DECISION-REQUIRED]。",
146150
"把库存一致性策略作为 blocker 或首个风险验证/决策 change。",
@@ -152,6 +156,7 @@
152156
],
153157
"must_include": [
154158
"[ARCHITECTURE-DECISION-REQUIRED]",
159+
"Mermaid 依赖图",
155160
"blocker 或决策 change",
156161
"受影响 FR"
157162
],
@@ -179,7 +184,7 @@
179184
"硬件/嵌入式体系暂未完整纳入软件主线,但 schema pack 已有 device schema。"
180185
]
181186
},
182-
"expected_output": "应选择或建议 aisee-device-spec-driven,输出设备类 source-map seed,包含 HW/FW/RT/VER 或 TBD in 对应 contract。不得输出 Web/API/DB 字段或把 I2C/UART/RTOS 等技术资源直接作为 change 边界;板级引脚和传感器型号未确认应作为 blocker 或 Open Question。",
187+
"expected_output": "应选择或建议 aisee-device-spec-driven,输出设备类 source-map seed,包含 HW/FW/RT/VER 或 TBD in 对应 contract。依赖顺序和并行关系如需展示,必须使用 Mermaid 语法块。不得输出 Web/API/DB 字段或把 I2C/UART/RTOS 等技术资源直接作为 change 边界;板级引脚和传感器型号未确认应作为 blocker 或 Open Question。",
183188
"expected_outputs": [
184189
"选择或建议 aisee-device-spec-driven。",
185190
"输出设备类 source-map seed,包含 HW/FW/RT/VER 或 TBD in 对应 contract。",

plugins/aisee-plugin/skills/aisee-change-plan/references/change-boundary-algorithm.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Out of Scope:
5050

5151
- 如需共享 contract、事件类型、数据模型、设备协议或配置约定,优先规划一个 S 级前置 change。
5252
- 对每个并行 change 复查可独立交付。
53-
- 在依赖图中明确标记并行组
53+
- 在 Mermaid 依赖图中用同一 phase 的 `subgraph` 明确标记并行组
5454

5555
## 4. 粒度与数量
5656

plugins/aisee-plugin/skills/aisee-change-plan/references/output-template.md

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
## 输出顺序
66

77
1. 摘要
8-
2. 依赖图
8+
2. Mermaid 依赖图
99
3. Change 详情
1010
4. 全部命令
1111
5. 整体理由
@@ -18,24 +18,31 @@ N 个 changes · M 个 phases · 预计总计 X 周 · Y 个可并行
1818

1919
任何估计为 XL(>14 天)的 change 都要标记风险。
2020

21-
## 依赖图
21+
## Mermaid 依赖图
2222

23-
简单依赖链使用 ASCII
23+
依赖顺序和并行关系统一使用 Mermaid 语法块表达
2424

25-
```text
26-
Phase 1(顺序执行):
27-
[change-name-1] -> [change-name-2]
25+
```mermaid
26+
flowchart TD
27+
subgraph "Phase 1"
28+
change_1["change-name-1"]
29+
end
30+
31+
subgraph "Phase 2"
32+
change_2["change-name-2"]
33+
change_3["change-name-3"]
34+
end
2835
29-
Phase 2(Phase 1 后可并行):
30-
[change-name-3]
31-
[change-name-4]
36+
change_1 --> change_2
37+
change_1 --> change_3
3238
```
3339

34-
复杂依赖追加表格
40+
规则
3541

36-
| Change | 依赖 | 可并行 |
37-
|---|---|---|
38-
| change-name-3 | change-name-2 | change-name-4 |
42+
- 节点标签使用 change 名称。
43+
- phase 使用 `subgraph "Phase N"` 标记。
44+
- 并行 change 放在同一个 phase subgraph 中,不额外用表格重复表达。
45+
- 如果只有单个 change,仍保留 Mermaid 语法块,并只画一个节点。
3946

4047
## Change 详情模板
4148

plugins/aisee-plugin/skills/aisee-spec-migrate/assets/migration-index-template.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@
33
用于生成 `aisee/docs/spec-migration/<YYYY-MM-DD>-<slug>/00-index.md`
44

55
```markdown
6+
---
7+
title: "OpenSpec Baseline Migration:{project/module}"
8+
doc_type: "spec-migration"
9+
status: "draft"
10+
date: "{date}"
11+
scope: "{project/module/path}"
12+
owner: "{作者或团队}"
13+
source_refs:
14+
- "{repo-relative source path or source ref}"
15+
change_refs: []
16+
---
17+
618
# OpenSpec Baseline Migration:{project/module}
719

820
**文档编号**:SM-{YYYY-MM-DD}-{slug}
9-
**状态**:草稿 / 已写入 baseline / 待确认
10-
**范围**:{project/module/path}
11-
**创建日期**:{date}
21+
**版本**:v1.0
22+
**迁移范围**:{project/module/path}
1223

1324
---
1425

src/aisee_cli/planning_docs.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"design-spec",
1919
"design-assets",
2020
"implementation-brief",
21+
"spec-migration",
2122
"reflect",
2223
}
2324
VALID_STATUSES = {"draft", "active", "superseded", "archived"}
@@ -32,6 +33,8 @@
3233
"docs/design-spec/": "design-spec",
3334
"aisee/docs/design-assets/": "design-assets",
3435
"docs/design-assets/": "design-assets",
36+
"aisee/docs/spec-migration/": "spec-migration",
37+
"docs/spec-migration/": "spec-migration",
3538
"aisee/docs/reflect/": "reflect",
3639
"docs/reflect/": "reflect",
3740
"aisee/cache/implementation-bridge/": "implementation-brief",
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
5+
6+
ROOT = Path(__file__).resolve().parents[1]
7+
8+
9+
def test_change_plan_uses_mermaid_for_dependency_graph_contract() -> None:
10+
output_template = (ROOT / "plugins/aisee-plugin/skills/aisee-change-plan/references/output-template.md").read_text(encoding="utf-8")
11+
skill_text = (ROOT / "plugins/aisee-plugin/skills/aisee-change-plan/SKILL.md").read_text(encoding="utf-8")
12+
algorithm_text = (ROOT / "plugins/aisee-plugin/skills/aisee-change-plan/references/change-boundary-algorithm.md").read_text(encoding="utf-8")
13+
14+
assert "## Mermaid 依赖图" in output_template
15+
assert "```mermaid" in output_template
16+
assert "flowchart TD" in output_template
17+
assert "简单依赖链使用 ASCII" not in output_template
18+
assert "| Change | 依赖 | 可并行 |" not in output_template
19+
assert "使用 Mermaid 语法块输出依赖顺序和并行关系" in skill_text
20+
assert "在 Mermaid 依赖图中用同一 phase 的 `subgraph` 明确标记并行组" in algorithm_text

tests/test_doctor_flow_schema.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,36 @@ def test_doctor_reports_invalid_change_refs_in_planning_docs(tmp_path: Path) ->
317317
assert any(item["code"] == "PLANNING_DOC_STALE_ACTIVE" for item in data["issues"])
318318

319319

320+
def test_doctor_recognizes_spec_migration_docs_as_planning_docs(tmp_path: Path) -> None:
321+
create_open_project(tmp_path)
322+
write(
323+
tmp_path / "aisee" / "docs" / "spec-migration" / "2026-06-12-auth" / "00-index.md",
324+
"""---
325+
title: "OpenSpec Baseline Migration:Auth"
326+
doc_type: "spec-migration"
327+
status: "draft"
328+
date: "2026-06-12"
329+
scope: "auth"
330+
owner: "Aisee"
331+
source_refs:
332+
- "README.md"
333+
change_refs: []
334+
---
335+
336+
# OpenSpec Baseline Migration:Auth
337+
""",
338+
)
339+
340+
data = run_json(tmp_path, "doctor", "--json")
341+
342+
assert any(item["path"].endswith("aisee/docs/spec-migration/2026-06-12-auth/00-index.md") for item in data["aisee"]["planning_docs"]["items"])
343+
assert not any(
344+
item["code"] == "PLANNING_DOC_TYPE_INVALID"
345+
and item["path"].endswith("aisee/docs/spec-migration/2026-06-12-auth/00-index.md")
346+
for item in data["issues"]
347+
)
348+
349+
320350
def test_bootstrap_plan_is_read_only(tmp_path: Path) -> None:
321351
data = run_json(tmp_path, "bootstrap", "--plan", "--json")
322352

tests/test_skill_cli_preflight.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def test_planning_doc_frontmatter_contract_exists_and_representative_templates_r
3535
"plugins/aisee-plugin/skills/aisee-design-spec/assets/design-spec-template-standard.md": 'doc_type: "design-spec"',
3636
"plugins/aisee-plugin/skills/aisee-design-assets/assets/design-assets-index-template.md": 'doc_type: "design-assets"',
3737
"plugins/aisee-plugin/skills/aisee-implementation-bridge/references/brief-template.md": 'doc_type: "implementation-brief"',
38+
"plugins/aisee-plugin/skills/aisee-spec-migrate/assets/migration-index-template.md": 'doc_type: "spec-migration"',
3839
"plugins/aisee-plugin/skills/aisee-reflect/references/output-templates.md": 'doc_type: "reflect"',
3940
}
4041
for relative_path, marker in expected.items():
@@ -158,6 +159,16 @@ def test_architecture_skill_keeps_change_plan_hints_fact_based() -> None:
158159
assert marker not in text
159160

160161

162+
def test_spec_migrate_template_uses_frontmatter_without_duplicate_header_metadata() -> None:
163+
text = (ROOT / "plugins/aisee-plugin/skills/aisee-spec-migrate/assets/migration-index-template.md").read_text(encoding="utf-8")
164+
165+
assert 'doc_type: "spec-migration"' in text
166+
assert "source_refs:" in text
167+
assert "change_refs:" in text
168+
assert "**状态**:" not in text
169+
assert "**创建日期**:" not in text
170+
171+
161172
def test_cli_outputs_keep_marketplace_recovery_hints() -> None:
162173
import sys
163174

0 commit comments

Comments
 (0)