@namewta/speculo 0.7.6 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +5 -6
  2. package/dist/src/cli.js +18 -13
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/config.d.ts +20 -0
  5. package/dist/src/config.js +94 -0
  6. package/dist/src/config.js.map +1 -0
  7. package/dist/src/index.d.ts +3 -2
  8. package/dist/src/index.js +56 -27
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/manifest.d.ts +20 -0
  11. package/dist/src/manifest.js +57 -0
  12. package/dist/src/manifest.js.map +1 -0
  13. package/dist/src/refresh.d.ts +30 -0
  14. package/dist/src/refresh.js +465 -0
  15. package/dist/src/refresh.js.map +1 -0
  16. package/dist/src/structured.d.ts +12 -0
  17. package/dist/src/structured.js +236 -0
  18. package/dist/src/structured.js.map +1 -0
  19. package/package.json +2 -2
  20. package/template/.speculo/README.md +12 -11
  21. package/template/.speculo/refresh-contract.json +30 -0
  22. package/template/canonical/canonical-specdev-engineering-cognitive-mentor.md +1 -0
  23. package/template/canonical/canonical-specdev-goal-plan.md +1 -0
  24. package/template/canonical/canonical-specdev-grill-with-docs.md +1 -0
  25. package/template/canonical/canonical-specdev-spec.md +1 -0
  26. package/template/canonical/canonical-specdev-tickets.md +1 -0
  27. package/template/skills/github-npm-ops/references/preflight-checklist.md +1 -1
  28. package/template/workflows/person/runtime-contract.json +9 -0
  29. package/template/workflows/specdev/E-eli5/E-eli5.md +35 -0
  30. package/template/workflows/specdev/I-init-setup/I-init-setup.md +1 -1
  31. package/template/workflows/specdev/INDEX.md +15 -12
  32. package/template/workflows/specdev/common/rules/artifact-contract.md +1 -0
  33. package/template/workflows/specdev/common/tools/README.md +1 -1
  34. package/template/workflows/specdev/common/tools/validate-specdev.mjs +28 -0
  35. package/template/workflows/specdev/runtime-contract.json +26 -0
  36. package/dist/src/migrations.d.ts +0 -23
  37. package/dist/src/migrations.js +0 -1202
  38. package/dist/src/migrations.js.map +0 -1
  39. package/template/commands/migrate-runtime-state.md +0 -43
  40. package/template/skills/migrate-runtime-state/SKILL.md +0 -93
  41. package/template/skills/migrate-runtime-state/references/migration-contract.md +0 -64
  42. package/template/skills/migrate-runtime-state/scripts/migrate-runtime-state.mjs +0 -916
@@ -0,0 +1,236 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { assertJsonObject } from "./config.js";
4
+ import { pathExists } from "./utils.js";
5
+ const CHANGE_NAME = /^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$/;
6
+ async function readObject(path, label) {
7
+ let value;
8
+ try {
9
+ value = JSON.parse(await readFile(path, "utf8"));
10
+ }
11
+ catch (error) {
12
+ throw new Error(label + " is not valid JSON: " + String(error));
13
+ }
14
+ assertJsonObject(value, label);
15
+ return value;
16
+ }
17
+ function object(value) {
18
+ return value !== null && typeof value === "object" && !Array.isArray(value)
19
+ ? value
20
+ : {};
21
+ }
22
+ function positiveInteger(value, fallback) {
23
+ return Number.isInteger(value) && Number(value) >= 1 ? Number(value) : fallback;
24
+ }
25
+ export function migrateSpecdevConfig(local, defaults) {
26
+ const version = Number(local.schema_version);
27
+ if (version === 5)
28
+ return { value: local, migrated: false };
29
+ if (version !== 3 && version !== 4) {
30
+ throw new Error("SpecDev config supports schema v3, v4, or v5; found " + String(local.schema_version));
31
+ }
32
+ const localGit = object(local.git);
33
+ const localExecution = object(local.execution);
34
+ const defaultGit = object(defaults.git);
35
+ const defaultExecution = object(defaults.execution);
36
+ const allowedRoot = new Set([
37
+ "schema_version", "interaction_language", "artifact_language", "git",
38
+ "execution", "verification", "planning",
39
+ ]);
40
+ const unknownRoot = Object.keys(local).filter((key) => !allowedRoot.has(key));
41
+ if (unknownRoot.length > 0)
42
+ throw new Error("SpecDev config has unmapped root fields: " + unknownRoot.join(", "));
43
+ const legacyLimit = positiveInteger(localExecution.max_implementation_agents ?? localExecution.max_parallel, positiveInteger(defaultExecution.max_implementation_agents, 3));
44
+ return {
45
+ migrated: true,
46
+ value: {
47
+ schema_version: 5,
48
+ interaction_language: local.interaction_language ?? defaults.interaction_language,
49
+ artifact_language: local.artifact_language ?? defaults.artifact_language,
50
+ git: {
51
+ default_branch: typeof localGit.default_branch === "string" || localGit.default_branch === null
52
+ ? localGit.default_branch
53
+ : defaultGit.default_branch ?? null,
54
+ },
55
+ execution: {
56
+ max_implementation_agents: legacyLimit,
57
+ max_integration_attempts: positiveInteger(localExecution.max_integration_attempts, positiveInteger(defaultExecution.max_integration_attempts, 3)),
58
+ deep_ticket_human_approval: typeof localExecution.deep_ticket_human_approval === "boolean"
59
+ ? localExecution.deep_ticket_human_approval
60
+ : defaultExecution.deep_ticket_human_approval,
61
+ shared_path_owner: typeof localExecution.shared_path_owner === "string"
62
+ ? localExecution.shared_path_owner
63
+ : defaultExecution.shared_path_owner,
64
+ },
65
+ verification: Object.keys(object(local.verification)).length > 0 ? local.verification : defaults.verification,
66
+ planning: Object.keys(object(local.planning)).length > 0 ? local.planning : defaults.planning,
67
+ },
68
+ };
69
+ }
70
+ export function validateSpecdevConfig(config) {
71
+ if (config.schema_version !== 5)
72
+ throw new Error("SpecDev config schema_version must be 5");
73
+ if (typeof config.interaction_language !== "string" || typeof config.artifact_language !== "string") {
74
+ throw new Error("SpecDev config language values must be strings");
75
+ }
76
+ const git = object(config.git);
77
+ if (!(git.default_branch === null || typeof git.default_branch === "string")) {
78
+ throw new Error("SpecDev config git.default_branch must be a string or null");
79
+ }
80
+ const execution = object(config.execution);
81
+ for (const key of ["max_implementation_agents", "max_integration_attempts"]) {
82
+ if (!Number.isInteger(execution[key]) || Number(execution[key]) < 1) {
83
+ throw new Error("SpecDev config execution." + key + " must be a positive integer");
84
+ }
85
+ }
86
+ if (typeof execution.deep_ticket_human_approval !== "boolean" || typeof execution.shared_path_owner !== "string") {
87
+ throw new Error("SpecDev config execution settings are incomplete");
88
+ }
89
+ }
90
+ function authorization(scope) {
91
+ return { status: "not-authorized", source: null, granted_at: null, scope };
92
+ }
93
+ function normalizeChangeStatus(previous, globalEntry) {
94
+ const version = Number(previous.schema_version);
95
+ if (![3, 4, 5, 6].includes(version)) {
96
+ throw new Error("change status supports schema v3-v6; found " + String(previous.schema_version));
97
+ }
98
+ if (previous.artifact !== "change-status" || typeof previous.change !== "string" || !CHANGE_NAME.test(previous.change)) {
99
+ throw new Error("change status has an invalid artifact or change name");
100
+ }
101
+ const worktrees = Array.isArray(previous.worktrees) ? previous.worktrees : [];
102
+ if (version <= 3 && worktrees.length > 0) {
103
+ throw new Error("schema v3 worktree state requires an explicit migration decision");
104
+ }
105
+ if (version === 6)
106
+ return previous;
107
+ const now = typeof previous.updated_at === "string"
108
+ ? previous.updated_at
109
+ : typeof previous.created_at === "string" ? previous.created_at : new Date().toISOString();
110
+ const status = String(previous.change_status);
111
+ const change = previous.change;
112
+ const base = version === 3 ? {
113
+ schema_version: 4,
114
+ artifact: "change-status",
115
+ change,
116
+ change_status: status,
117
+ current_work: typeof previous.current_work === "string" ? previous.current_work : null,
118
+ created_at: typeof previous.created_at === "string" ? previous.created_at : now,
119
+ updated_at: now,
120
+ completed_at: typeof previous.completed_at === "string" ? previous.completed_at : null,
121
+ archived: status === "archived",
122
+ archive_path: status === "archived" ? `<Path>{roots.state}/specdev/archive/${change.slice(0, 7)}/${change}</Path>` : null,
123
+ blockers: Array.isArray(previous.blockers) ? previous.blockers : [],
124
+ deviations: Array.isArray(previous.deviations) ? previous.deviations : [],
125
+ worktrees: [],
126
+ } : previous;
127
+ const upgraded = Number(base.schema_version) === 4 ? {
128
+ ...base,
129
+ schema_version: 5,
130
+ current_work: typeof base.current_work === "string" ? base.current_work : globalEntry?.current_work ?? null,
131
+ works_run: Array.isArray(globalEntry?.works_run) ? globalEntry.works_run : [],
132
+ claimed_investigations: Array.isArray(globalEntry?.claimed_investigations) ? globalEntry.claimed_investigations : [],
133
+ execution_authorization: {
134
+ implementation_commit: authorization("Ticket implementation commits"),
135
+ local_candidate_integration: authorization("Lead-owned local integration and parent update"),
136
+ source_cleanup: authorization("Source worktree and branch cleanup"),
137
+ },
138
+ leadership: { current: "unassigned", epoch: 1, assigned_at: now, history: [] },
139
+ } : base;
140
+ return { ...upgraded, schema_version: 6 };
141
+ }
142
+ function migrateGoalPlan(text, attempts) {
143
+ if (!/^---\s*$/m.test(text))
144
+ return text;
145
+ let next = text;
146
+ if (/^schema_version:\s*4\s*$/m.test(next))
147
+ next = next.replace(/^schema_version:\s*4\s*$/m, "schema_version: 5");
148
+ if (/^schema_version:\s*5\s*$/m.test(next)) {
149
+ next = next
150
+ .replace(/^schema_version:\s*5\s*$/m, "schema_version: 6")
151
+ .replace(/^(implementation_agent_limit:\s*[^\n]+)$/m, `$1\nintegration_attempt_limit: ${attempts}`);
152
+ }
153
+ return next;
154
+ }
155
+ async function rewriteIfChanged(path, value, reason, changes) {
156
+ const before = await readFile(path);
157
+ if (before.equals(Buffer.from(value)))
158
+ return;
159
+ changes.push({ path, before, reason });
160
+ await writeFile(path, value, "utf8");
161
+ }
162
+ async function migrateSpecdevState(stagedRoot) {
163
+ const changes = [];
164
+ const stateRoot = join(stagedRoot, ".speculo", "specdev");
165
+ const statusPath = join(stateRoot, "status.json");
166
+ if (!(await pathExists(statusPath)))
167
+ return changes;
168
+ const status = await readObject(statusPath, ".speculo/specdev/status.json");
169
+ if (![4, 5].includes(Number(status.schema_version)) || status.workflow !== "specdev" || !Array.isArray(status.active) || !Array.isArray(status.archived)) {
170
+ throw new Error("SpecDev status must use schema v4/v5 with active and archived arrays");
171
+ }
172
+ const active = status.active.map((entry) => {
173
+ assertJsonObject(entry, "SpecDev active status entry");
174
+ if (typeof entry.change !== "string" || !CHANGE_NAME.test(entry.change))
175
+ throw new Error("SpecDev active change name is invalid");
176
+ return entry;
177
+ });
178
+ const archived = status.archived.map((entry) => {
179
+ if (typeof entry !== "string" || !CHANGE_NAME.test(entry))
180
+ throw new Error("SpecDev archived change name is invalid");
181
+ return entry;
182
+ });
183
+ const activeNames = new Set(active.map((entry) => String(entry.change)));
184
+ if (activeNames.size !== active.length || new Set(archived).size !== archived.length || archived.some((name) => activeNames.has(name))) {
185
+ throw new Error("SpecDev status contains duplicate or overlapping change names");
186
+ }
187
+ if (status.schema_version === 4) {
188
+ await rewriteIfChanged(statusPath, JSON.stringify({
189
+ schema_version: 5,
190
+ workflow: "specdev",
191
+ active,
192
+ archived,
193
+ }, null, 2) + "\n", "upgrade SpecDev global status schema v4 to v5", changes);
194
+ }
195
+ let attempts = 3;
196
+ const configPath = join(stateRoot, "config.json");
197
+ if (await pathExists(configPath)) {
198
+ const config = await readObject(configPath, ".speculo/specdev/config.json");
199
+ attempts = positiveInteger(object(config.execution).max_integration_attempts, 3);
200
+ }
201
+ const indexed = [
202
+ ...active.map((entry) => ({ path: join(stateRoot, "changes", String(entry.change), ".status.json"), entry })),
203
+ ...archived.map((name) => ({ path: join(stateRoot, "archive", name.slice(0, 7), name, ".status.json"), entry: null })),
204
+ ];
205
+ for (const item of indexed) {
206
+ if (!(await pathExists(item.path)))
207
+ throw new Error("indexed SpecDev change is missing " + item.path);
208
+ const previous = await readObject(item.path, item.path);
209
+ const normalized = normalizeChangeStatus(previous, item.entry);
210
+ await rewriteIfChanged(item.path, JSON.stringify(normalized, null, 2) + "\n", "upgrade SpecDev change status schema", changes);
211
+ const goalPlanPath = join(dirname(item.path), "goal-plan.md");
212
+ if (await pathExists(goalPlanPath)) {
213
+ const goalPlan = await readFile(goalPlanPath, "utf8");
214
+ await rewriteIfChanged(goalPlanPath, migrateGoalPlan(goalPlan, attempts), "upgrade Goal Plan schema", changes);
215
+ }
216
+ }
217
+ return changes;
218
+ }
219
+ async function validatePersonState(stagedRoot) {
220
+ const statusPath = join(stagedRoot, ".speculo", "person", "status.json");
221
+ if (!(await pathExists(statusPath)))
222
+ return;
223
+ const status = await readObject(statusPath, ".speculo/person/status.json");
224
+ if (status.schema_version !== 1 || status.workflow !== "person" || !Array.isArray(status.active)) {
225
+ throw new Error("Person status must use schema v1 with an active array");
226
+ }
227
+ }
228
+ export async function migrateStructuredRuntime(stagedRoot, selectedWorkflowIds) {
229
+ const changes = [];
230
+ if (selectedWorkflowIds.includes("specdev"))
231
+ changes.push(...await migrateSpecdevState(stagedRoot));
232
+ if (selectedWorkflowIds.includes("person"))
233
+ await validatePersonState(stagedRoot);
234
+ return changes;
235
+ }
236
+ //# sourceMappingURL=structured.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured.js","sourceRoot":"","sources":["../../src/structured.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@namewta/speculo",
3
- "version": "0.7.6",
3
+ "version": "0.8.1",
4
4
  "description": "Workflow-packaged specification-driven development assets with state-safe refresh tooling.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  "pretest": "pnpm build",
14
14
  "generate-canonical": "node scripts/generate-specdev-canonical.mjs",
15
15
  "validate-source-parity": "node scripts/check-specdev-source-parity.mjs",
16
- "validate-assets": "node scripts/check-specdev-source-parity.mjs && node scripts/generate-specdev-canonical.mjs --check && node scripts/validate-framework-assets.mjs && node scripts/check-template-links.mjs",
16
+ "validate-assets": "node scripts/check-specdev-source-parity.mjs && node scripts/generate-specdev-canonical.mjs --check && node scripts/validate-refresh-contracts.mjs && node scripts/validate-framework-assets.mjs && node scripts/check-template-links.mjs",
17
17
  "check": "pnpm test && pnpm validate-assets",
18
18
  "verify-bin": "node scripts/verify-bin.mjs",
19
19
  "prepack": "pnpm build",
@@ -4,21 +4,22 @@
4
4
 
5
5
  ## 刷新契约
6
6
 
7
- 重新运行 `speculo init` 会以当前模板刷新 commands、skills 与选中的 workflow 静态资产,并对 v0.7+ 运行时执行兼容检查。兼容时递归合并项目配置的当前默认值,并完整保留 workflow 配置、状态索引、`changes/`、`archive/`、永久知识、sidecarcommand 报告和具有当前合同的 command `state.json`。
7
+ 重新运行 `speculo init` 会以当前模板替换 commands、skills、CLI metadata 与选中的 workflow 静态资产。`.speculo/managed.json` 逐文件记录受管理路径、ownerkind、版本与 SHA-256;未选中的当前受支持 workflow 包保持原样,已移除或未知的静态包不会被带入新安装。
8
8
 
9
- 每次刷新先把旧 `config.json` 和旧 `.speculo/` 快照写入 `back/`,排除上一份 `back/` 与旧 pending marker,因此只保留最近一次刷新前备份。`install.json` 记录当前包版本和已安装 workflows;`back/manifest.json` 记录来源/目标版本及每个备份文件的 hash 和大小。
9
+ 普通 runtime 文件默认 opaque,由 CLI 按字节复制并在替换前复验 hash,不因为扩展名是 JSON 而解析。只有 workflow `runtime-contract.json` 登记的配置和结构化状态进入 schema migrator;未知结构化版本、损坏内容或符号链接会在替换前阻塞,当前安装保持不变。
10
10
 
11
- 若来源版本、核心 schema、JSON、符号链接、command state owner workflow 索引无法证明兼容,刷新安装当前干净模板状态并创建 `migration.json`,其 `status` 为 `pending`。此时所有 workflow 读取和状态写入都必须停止;只能运行 `migrate-runtime-state` command,基于只读 `back/` 逐项对账、确认并原子迁移。再次运行 `speculo init` 会在任何修改前阻塞。
11
+ 配置使用 `.speculo/baselines/` 中的上次模板默认值执行 base/local/incoming 三方合并:模板新增项自动增加,模板删除项直接删除,未被用户修改的旧默认值跟随模板更新,用户覆盖值在满足目标合同的前提下保留。只有字段删除、显式 schema 迁移或结构化文件变换时,CLI 才把原文件写入 `back/` 并生成 targeted manifest;opaque 内容不会被整包复制到备份。
12
+
13
+ `install.json` 使用 schema v2,记录包版本、已安装 workflows、managed manifest 路径和 baseline schema。初始化以项目锁、完整 staging、active fingerprint 复验、原子 rename 与失败 rollback 组成一个事务;冲突不会发布部分结果,也不会创建新的 pending marker。
12
14
 
13
15
  ## 读取顺序
14
16
 
15
17
  1. 读取 `workspace.json`,以当前打开项目为 `project_root` 解析公共 roots。
16
- 2. 检查 `migration.json`;存在 pending 时停止,仅路由到 `migrate-runtime-state` command。
17
- 3. `../workflows/<workflow>/INDEX.md` 进入 workflow,再通过 `<Path>` 指针进入具体 work 入口文件。
18
- 4. 读取 `<workflow>/status.json`,再读取 `changes/<change>/.status.json` 和当前 work 产物。
19
- 5. 历史 change 只从 `<workflow>/archive/YYYY-MM/<change>/` 读取。
20
- 6. Command 报告位于 `commands/<command>/*.md`,command state 位于 `commands/<command>/state.json`。
21
- 7. 首次 docs-sync 确认后读取 `<workflow>/docs-sync.json`;它分列该 workflow 的项目文档和私有 state 更新范围。
18
+ 2. `../workflows/<workflow>/INDEX.md` 进入 workflow,再通过 `<Path>` 指针进入具体 work 入口文件。
19
+ 3. 读取 `<workflow>/status.json`,再读取 `changes/<change>/.status.json` 和当前 work 产物。
20
+ 4. 历史 change 只从 `<workflow>/archive/YYYY-MM/<change>/` 读取。
21
+ 5. Command 报告位于 `commands/<command>/*.md`,command state 位于 `commands/<command>/state.json`。
22
+ 6. 首次 docs-sync 确认后读取 `<workflow>/docs-sync.json`;它分列该 workflow 的项目文档和私有 state 更新范围。
22
23
 
23
24
  ## 写入边界
24
25
 
@@ -26,5 +27,5 @@
26
27
  - `docs-sync.json` 是 docs-sync command 拥有的延迟 sidecar,不进入 `_state`,也不授予越过 workflow 确认规则的权限。
27
28
  - `.config` 不是标准目录;只有 workflow 声明时才可使用。
28
29
  - Command 报告命名为 `<YYYY-MM-DD>-<scope>-<topic>[-NN].md`,禁止覆盖。
29
- - `back/` 由 `speculo init` 单一写入,迁移 command 只读;workflow 和其他 commands 不得修改。
30
- - `install.json``migration.json` 由 CLI/迁移脚本拥有,workflow 不得创建、修改或删除。
30
+ - `back/` 由 `speculo init` 单一写入;workflow commands 不得修改。
31
+ - `install.json`、`managed.json`、`baselines/`refresh contract 由 CLI 拥有,workflow 不得创建、修改或删除。
@@ -0,0 +1,30 @@
1
+ {
2
+ "schema_version": 1,
3
+ "runtime_root": ".speculo",
4
+ "managed_roots": [
5
+ "commands",
6
+ "skills",
7
+ "workflows"
8
+ ],
9
+ "managed_metadata": [
10
+ ".speculo/README.md",
11
+ ".speculo/workspace.json",
12
+ ".speculo/refresh-contract.json"
13
+ ],
14
+ "reserved_runtime": [
15
+ "README.md",
16
+ "workspace.json",
17
+ "refresh-contract.json",
18
+ "install.json",
19
+ "managed.json",
20
+ "migration.json",
21
+ "baselines",
22
+ "back"
23
+ ],
24
+ "project_config": {
25
+ "path": "config.json",
26
+ "baseline": ".speculo/baselines/config.json",
27
+ "schema_version": 1,
28
+ "additional_properties": true
29
+ }
30
+ }
@@ -1432,6 +1432,7 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
1432
1432
  | Evidence | `specdev/changes/{change}/evidence/T-NN.md` | 实际修改、命令、结果、验收映射、偏差、风险和提交引用 | 新的产品或架构决策 |
1433
1433
  | 代码审查 | `specdev/changes/{change}/reviews/CR-###.md` | 固定点、标准轴和规范轴 finding | 实施修复或合并两轴排名 |
1434
1434
  | 原型记录 | `specdev/changes/{change}/prototypes/{prototype-id}/record.md` | 一个问题、分支、资产、答案、promotion 和清理 | 生产实现或多个问题的计划 |
1435
+ | 五岁图解 | `specdev/changes/{change}/eli5.html` | 面向五岁、零背景读者的大图少字解释 | 产品决定、架构决定或实现授权 |
1435
1436
  | Stakeholder 问卷 | `specdev/changes/{change}/questionnaires/{slug}.md` | 第三方原始回答和恢复条件 | 未经转录确认的产品/架构决定 |
1436
1437
  | Wayfinder 地图 | `specdev/changes/{change}/wayfinder-map.md` | 目的地、说明、已关闭决策索引、战争迷雾和范围之外 | 开放 Ticket 正文或答案详情 |
1437
1438
  | Wayfinder Ticket | `specdev/changes/{change}/investigation/{investigation-id}.md` | 一个可精确陈述的问题、类型、阻塞和关闭状态 | 解决方案评论或交付目标 |
@@ -559,6 +559,7 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
559
559
  | Evidence | `specdev/changes/{change}/evidence/T-NN.md` | 实际修改、命令、结果、验收映射、偏差、风险和提交引用 | 新的产品或架构决策 |
560
560
  | 代码审查 | `specdev/changes/{change}/reviews/CR-###.md` | 固定点、标准轴和规范轴 finding | 实施修复或合并两轴排名 |
561
561
  | 原型记录 | `specdev/changes/{change}/prototypes/{prototype-id}/record.md` | 一个问题、分支、资产、答案、promotion 和清理 | 生产实现或多个问题的计划 |
562
+ | 五岁图解 | `specdev/changes/{change}/eli5.html` | 面向五岁、零背景读者的大图少字解释 | 产品决定、架构决定或实现授权 |
562
563
  | Stakeholder 问卷 | `specdev/changes/{change}/questionnaires/{slug}.md` | 第三方原始回答和恢复条件 | 未经转录确认的产品/架构决定 |
563
564
  | Wayfinder 地图 | `specdev/changes/{change}/wayfinder-map.md` | 目的地、说明、已关闭决策索引、战争迷雾和范围之外 | 开放 Ticket 正文或答案详情 |
564
565
  | Wayfinder Ticket | `specdev/changes/{change}/investigation/{investigation-id}.md` | 一个可精确陈述的问题、类型、阻塞和关闭状态 | 解决方案评论或交付目标 |
@@ -377,6 +377,7 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
377
377
  | Evidence | `specdev/changes/{change}/evidence/T-NN.md` | 实际修改、命令、结果、验收映射、偏差、风险和提交引用 | 新的产品或架构决策 |
378
378
  | 代码审查 | `specdev/changes/{change}/reviews/CR-###.md` | 固定点、标准轴和规范轴 finding | 实施修复或合并两轴排名 |
379
379
  | 原型记录 | `specdev/changes/{change}/prototypes/{prototype-id}/record.md` | 一个问题、分支、资产、答案、promotion 和清理 | 生产实现或多个问题的计划 |
380
+ | 五岁图解 | `specdev/changes/{change}/eli5.html` | 面向五岁、零背景读者的大图少字解释 | 产品决定、架构决定或实现授权 |
380
381
  | Stakeholder 问卷 | `specdev/changes/{change}/questionnaires/{slug}.md` | 第三方原始回答和恢复条件 | 未经转录确认的产品/架构决定 |
381
382
  | Wayfinder 地图 | `specdev/changes/{change}/wayfinder-map.md` | 目的地、说明、已关闭决策索引、战争迷雾和范围之外 | 开放 Ticket 正文或答案详情 |
382
383
  | Wayfinder Ticket | `specdev/changes/{change}/investigation/{investigation-id}.md` | 一个可精确陈述的问题、类型、阻塞和关闭状态 | 解决方案评论或交付目标 |
@@ -368,6 +368,7 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
368
368
  | Evidence | `specdev/changes/{change}/evidence/T-NN.md` | 实际修改、命令、结果、验收映射、偏差、风险和提交引用 | 新的产品或架构决策 |
369
369
  | 代码审查 | `specdev/changes/{change}/reviews/CR-###.md` | 固定点、标准轴和规范轴 finding | 实施修复或合并两轴排名 |
370
370
  | 原型记录 | `specdev/changes/{change}/prototypes/{prototype-id}/record.md` | 一个问题、分支、资产、答案、promotion 和清理 | 生产实现或多个问题的计划 |
371
+ | 五岁图解 | `specdev/changes/{change}/eli5.html` | 面向五岁、零背景读者的大图少字解释 | 产品决定、架构决定或实现授权 |
371
372
  | Stakeholder 问卷 | `specdev/changes/{change}/questionnaires/{slug}.md` | 第三方原始回答和恢复条件 | 未经转录确认的产品/架构决定 |
372
373
  | Wayfinder 地图 | `specdev/changes/{change}/wayfinder-map.md` | 目的地、说明、已关闭决策索引、战争迷雾和范围之外 | 开放 Ticket 正文或答案详情 |
373
374
  | Wayfinder Ticket | `specdev/changes/{change}/investigation/{investigation-id}.md` | 一个可精确陈述的问题、类型、阻塞和关闭状态 | 解决方案评论或交付目标 |
@@ -655,6 +655,7 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
655
655
  | Evidence | `specdev/changes/{change}/evidence/T-NN.md` | 实际修改、命令、结果、验收映射、偏差、风险和提交引用 | 新的产品或架构决策 |
656
656
  | 代码审查 | `specdev/changes/{change}/reviews/CR-###.md` | 固定点、标准轴和规范轴 finding | 实施修复或合并两轴排名 |
657
657
  | 原型记录 | `specdev/changes/{change}/prototypes/{prototype-id}/record.md` | 一个问题、分支、资产、答案、promotion 和清理 | 生产实现或多个问题的计划 |
658
+ | 五岁图解 | `specdev/changes/{change}/eli5.html` | 面向五岁、零背景读者的大图少字解释 | 产品决定、架构决定或实现授权 |
658
659
  | Stakeholder 问卷 | `specdev/changes/{change}/questionnaires/{slug}.md` | 第三方原始回答和恢复条件 | 未经转录确认的产品/架构决定 |
659
660
  | Wayfinder 地图 | `specdev/changes/{change}/wayfinder-map.md` | 目的地、说明、已关闭决策索引、战争迷雾和范围之外 | 开放 Ticket 正文或答案详情 |
660
661
  | Wayfinder Ticket | `specdev/changes/{change}/investigation/{investigation-id}.md` | 一个可精确陈述的问题、类型、阻塞和关闭状态 | 解决方案评论或交付目标 |
@@ -16,7 +16,7 @@
16
16
  | 7 | 包管理器 | `pnpm --version` (或 `npm` / `yarn`) | 版本 ≥ 仓库 lockfile 隐含版本 | 安装匹配版本;不要随意切换包管理器 |
17
17
  | 8 | release.yml 存在 | `test -f .github/workflows/release.yml` | 文件存在 | 转 `github-npm-ops` skill 的 `references/workflow-yaml-reference.md` 先落该文件 |
18
18
  | 9 | release.yml 形态 | 见 [publish-detection.md](publish-detection.md) | 输出 `PUBLISH_TO_NPM=true` 或 `false` | 见 publish-detection 文档的判定矩阵 |
19
- | 10 | docs-sync state | `test -f speculo/.speculo/commands/docs-sync/state.json && jq . speculo/.speculo/commands/docs-sync/state.json` | schema v4、scope 已确认,baseline 可解析 | 不存在/未确认 → 走 docs-sync command bootstrap;旧 schema 或损坏 → 运行 `speculo init` 建立 pending 备份,再以 `migrate-runtime-state` command 修复后确认范围 |
19
+ | 10 | docs-sync state | `test -f speculo/.speculo/commands/docs-sync/state.json && jq . speculo/.speculo/commands/docs-sync/state.json` | schema v4、scope 已确认,baseline 可解析 | 不存在/未确认 → 走 docs-sync command bootstrap;旧 schema 或损坏 → 停止发布并按 docs-sync state contract 修复,`speculo init` 不解析未登记的 command state |
20
20
  | 11 | tag 名称冲突 | `git rev-parse vX.Y.Z 2>/dev/null` | 退出码非 0(tag 不存在) | 同 tag 已存在:先确认是否真的失败需要重发;若是则 `git tag -d` + `git push origin :refs/tags/vX.Y.Z`,否则 bump 到下一版本 |
21
21
 
22
22
  ## 失败处理总策略
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_version": 1,
3
+ "workflow": "person",
4
+ "config": null,
5
+ "structured_state": [
6
+ ".speculo/person/status.json"
7
+ ],
8
+ "opaque_default": "preserve-byte-for-byte"
9
+ }
@@ -0,0 +1,35 @@
1
+ ---
2
+ id: specdev/eli5
3
+ type: workflow-entry
4
+ workflow: specdev
5
+ name: 五岁解释
6
+ description: 像对五岁的我一样解释一个主题。当用户要求用极其简单的图片解释某件事如何运作时,生成大图、少字的持久化 HTML 图解。
7
+ ---
8
+
9
+ # eli5:像对五岁的我一样解释
10
+
11
+ ## 原作者核心(完整中文转写)
12
+
13
+ 像对五岁的我一样解释一个主题。要求用极其简单的图片解释某件事如何运作时,使用此 Work。
14
+
15
+ 像对一个完全不了解这个主题的五岁孩子一样解释,使用一个大图、少字的 HTML 工件。
16
+
17
+ 主题:`$ARGUMENTS`
18
+
19
+ 这里的“五岁”是字面标准,不只是“初学者”的别称:假定读者真的只有五岁,没有专业词汇、背景知识或抽象模型。保留事实准确性,但用熟悉的物体、动作、因果和类比来解释。
20
+
21
+ ## 执行
22
+
23
+ 1. 读取 `<Path>{roots.workflows}/specdev/INDEX.md</Path>`、全局状态和当前 change 状态。选择用户指定或唯一活跃的 change;没有时按 SpecDev 启动协议创建。`current_work` 为空时设为 `specdev/eli5`;若指向其他 Work,先完成显式交接。
24
+ 2. 将调用中的 `$ARGUMENTS` 解析为主题;直接提出的图解请求以用户最新消息为主题。主题缺失时只询问主题,不猜测。
25
+ 3. 按需读取当前 change 工件、项目事实和可靠来源。先找出一个孩子必须理解的核心因果,再选择一个熟悉、不会歪曲事实的视觉类比。
26
+ 4. 原子写入 `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>`。页面必须是可直接打开的完整 HTML,以大图为主、文字为辅;避免术语、长段落和先备知识。需要术语时,先用孩子能懂的话解释。
27
+ 5. 检查 HTML 可打开、主题明确、主要解释由图片承担、文字足够少,而且一个真正的五岁孩子仅看页面就能说出“它是什么”和“它怎么运作”。可用浏览器时实际打开检查;不可用时做静态检查并说明限制。
28
+ 6. 运行 `<Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path>` 的 `--stage eli5`。成功后把 `specdev/eli5` 去重加入 `works_run`,清空 `current_work`,并返回 HTML 完整路径;失败时保留 `current_work` 和阻塞原因,便于恢复。
29
+
30
+ ## 完成标准
31
+
32
+ - `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>` 存在且是完整 HTML。
33
+ - 页面确实面向五岁、零背景读者,并以大图、少字解释主题,而不是把普通长文换成更大的字号。
34
+ - 解释简单但不虚假;类比的边界不会让读者形成相反理解。
35
+ - 状态已原子更新;除当前 change 工件外,没有修改项目代码、永久知识或远程系统。
@@ -82,7 +82,7 @@ keywords: [初始化, 配置, status, tracking, 验证命令]
82
82
  - `<Path>{roots.state}/specdev/research/</Path>`
83
83
  - `<Path>{roots.state}/specdev/archive/</Path>`
84
84
 
85
- 若全局状态或 config 已存在,先检查各自 `schema_version`。版本未知、JSON 不可解析或状态与当前 workflow 契约不一致时,停止当前 Work,并提示用户运行 `speculo init` 建立备份与 pending marker,再运行 `migrate-runtime-state` command 对账修复;不得在 Work 内迁移、兼容或猜测旧状态。只有状态不存在时才从当前 schema 模板创建。
85
+ 若全局状态或 config 已存在,先检查各自 `schema_version`。版本未知、JSON 不可解析或状态与当前 workflow 契约不一致时,停止当前 Work;不得在 Work 内迁移、兼容或猜测旧状态。`speculo init` 只会对 `runtime-contract.json` 已登记且存在显式 migrator 的旧版本升级,其他冲突会保留当前安装并报告具体 blocker。只有状态不存在时才从当前 schema 模板创建。
86
86
 
87
87
  从模板生成:
88
88
 
@@ -3,8 +3,8 @@ id: specdev
3
3
  type: workflow
4
4
  workflow: specdev
5
5
  name: SpecDev Workflow
6
- description: 以本地工件为唯一开发权威,从来源冻结、诊断、设计、原型、规格、Ticket、编排和审查推进到证据驱动实现、远程 reconcile 与知识归档。
7
- keywords: [specdev, local-first, 规格驱动开发, decision-complete, prototype, code-review, TDD, 证据]
6
+ description: 以本地工件为唯一开发权威,从来源冻结、诊断、设计、五岁图解、原型、规格、Ticket、编排和审查推进到证据驱动实现、远程 reconcile 与知识归档。
7
+ keywords: [specdev, local-first, 规格驱动开发, decision-complete, eli5, prototype, code-review, TDD, 证据]
8
8
  ---
9
9
 
10
10
  # SpecDev Workflow
@@ -25,7 +25,7 @@ SpecDev 将“理解、决定、规划、执行、验证、沉淀”拆成职责
25
25
 
26
26
  Triage 冻结为本地 Source
27
27
 
28
- Diagnose / Grill / Wayfinder / Prototype / Code Review / Architecture Review
28
+ Diagnose / Grill / ELI5 / Wayfinder / Prototype / Code Review / Architecture Review
29
29
 
30
30
  Spec 外部行为、范围、验收合同与关键约束
31
31
 
@@ -59,6 +59,7 @@ Archive 归档历史并将经验证知识提升为当前长期知识
59
59
  - `<Path>{roots.state}/specdev/changes/{change}/reviews/</Path>`
60
60
  - `<Path>{roots.state}/specdev/changes/{change}/prototypes/</Path>`
61
61
  - `<Path>{roots.state}/specdev/changes/{change}/questionnaires/</Path>`
62
+ - `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>`
62
63
 
63
64
  工件职责和冲突裁决位于 `<Path>{roots.workflows}/specdev/common/rules/artifact-contract.md</Path>`。
64
65
 
@@ -70,7 +71,7 @@ Archive 归档历史并将经验证知识提升为当前长期知识
70
71
  - 活跃 change:`<Path>{roots.state}/specdev/changes/</Path>`
71
72
  - 历史归档:`<Path>{roots.state}/specdev/archive/</Path>`
72
73
 
73
- 刷新时 CLI `<Path>{roots.state}/back/</Path>` 保留最近一次旧配置与完整 runtime state,并对 v0.7+ 状态执行兼容迁移。若 `<Path>{roots.state}/migration.json</Path>` 存在且为 pending,所有 SpecDev Works 必须在读取 workflow state 前停止;只有 `<Path>{roots.commands}/migrate-runtime-state.md</Path>` 可以读取备份并在用户确认后修复。`<Path>{roots.state}/back/</Path>`、`<Path>{roots.state}/install.json</Path>` 与 `<Path>{roots.state}/migration.json</Path>` 均不属于 SpecDev 写入 namespace。
74
+ 刷新时 CLI 依据 `<Path>{roots.workflows}/specdev/runtime-contract.json</Path>` 处理持久化数据:配置使用 baseline 三方合并,登记的状态 schema 使用显式 migrator,其他 runtime 文件按字节保留。只有字段删除或结构迁移时才在 `<Path>{roots.state}/back/</Path>` 写入 targeted backup;冲突在替换 active 安装前阻塞。`<Path>{roots.state}/back/</Path>`、`<Path>{roots.state}/install.json</Path>`、`<Path>{roots.state}/managed.json</Path>` 与 `<Path>{roots.state}/baselines/</Path>` 均不属于 SpecDev 写入 namespace。
74
75
 
75
76
  初始化设置 work 首次运行时生成配置并创建空的永久 namespace:
76
77
 
@@ -107,6 +108,7 @@ Archive 归档历史并将经验证知识提升为当前长期知识
107
108
  - `<Path>{roots.state}/specdev/changes/{change}/reviews/</Path>`
108
109
  - `<Path>{roots.state}/specdev/changes/{change}/prototypes/</Path>`
109
110
  - `<Path>{roots.state}/specdev/changes/{change}/questionnaires/</Path>`
111
+ - `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>`
110
112
 
111
113
  ## 全局治理原则
112
114
 
@@ -140,12 +142,11 @@ Archive 归档历史并将经验证知识提升为当前长期知识
140
142
  ## 启动协议
141
143
 
142
144
  1. 解析 workflow 和 state roots。
143
- 2. 检查 `<Path>{roots.state}/migration.json</Path>`;存在且 `status: pending` 时停止,不读取或写入 SpecDev state,并路由到 `<Path>{roots.commands}/migrate-runtime-state.md</Path>`。
144
- 3. 读取 `<Path>{roots.state}/specdev/config.json</Path>`;不存在时运行 `<Path>{roots.workflows}/specdev/I-init-setup/I-init-setup.md</Path>`。
145
- 4. 读取 `<Path>{roots.state}/specdev/status.json</Path>`:用户指定 change 优先;唯一活跃 change 直接使用;无活跃时创建;多个候选时请求消歧。
146
- 5. 若当前 change 已有非空 `current_work`,先恢复或显式结束该 Work;否则将 `current_work` 设置为本次 work id。
147
- 6. 只加载当前步骤需要的 work 子文件和共享规则。
148
- 7. 完成后写入产物、运行适用校验、更新状态和 `works_run`。
145
+ 2. 读取 `<Path>{roots.state}/specdev/config.json</Path>`;不存在时运行 `<Path>{roots.workflows}/specdev/I-init-setup/I-init-setup.md</Path>`。
146
+ 3. 读取 `<Path>{roots.state}/specdev/status.json</Path>`:用户指定 change 优先;唯一活跃 change 直接使用;无活跃时创建;多个候选时请求消歧。
147
+ 4. 若当前 change 已有非空 `current_work`,先恢复或显式结束该 Work;否则将 `current_work` 设置为本次 work id。
148
+ 5. 只加载当前步骤需要的 work 子文件和共享规则。
149
+ 6. 完成后写入产物、运行适用校验、更新状态和 `works_run`。
149
150
 
150
151
  Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>`:有 Goal Plan 时由其中唯一 Lead 拥有转换;无 Goal Plan 的 Ticket/Direct Spec 由当前 I owner 拥有;非实现型终点由最终验收工件 owner 拥有。Archive 不补造 completed。
151
152
 
@@ -196,6 +197,7 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
196
197
  | 本地 change 完成且来源可关闭 | T-triage reconcile | A |
197
198
  | 疑难 bug 或性能回归 | D-diagnose-bugs | S / T / I / R / W |
198
199
  | 模糊但可通过决策访谈收敛 | G-grill-with-docs | P / S / T / W |
200
+ | 需要向五岁、零背景读者做大图少字的解释 | E-eli5 | 返回用户 / 继续当前 change |
199
201
  | 路径超出单次上下文 | W-wayfinder | G / P / D / S / T |
200
202
  | 需要用代码回答逻辑/UI 问题 | P-prototype | G / S / T / I |
201
203
  | 固定点 diff、branch 或 PR review | C-code-review | completed / T / S / G |
@@ -214,9 +216,10 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
214
216
  - **A-archive-and-consolidate** — 归档与沉淀:校验本地完成与远程 reconcile 门,复用全局归档能力移动 completed change 并提升当前知识,或从代码访谈形成可归档知识 change。
215
217
  - **C-code-review** — 代码审查:将 commit、branch、tag、merge-base 或 PR 解析为本地不可变固定点,执行隔离的标准轴与规范轴审查并持久化可恢复报告。
216
218
  - **D-diagnose-bugs** — 诊断 Bug:先建立会在精确症状上变红的紧凑反馈回路,再通过最小化、排名假设和单变量探针确认根因,输出修复契约而不实施生产修复。
219
+ - **E-eli5** — 五岁解释:像对五岁的我一样解释一个主题。当用户输入 /eli5 <主题>,或要求用极其简单的图片解释某件事如何运作时,生成大图、少字的持久化 HTML 图解。
217
220
  - **E-engineering-cognitive-mentor** — 工程认知导师:面向 Bug、项目源码、需求技术方案、架构设计与陌生技术领域的非执行型认知指导 Work;以证据、因果 Why、候选方案对比和逐轮澄清帮助用户形成可复述理解,并将完整问答轨迹持续持久化到当前 change。
218
221
  - **G-grill-with-docs** — 设计访谈(带文档):以完整 frontier 逐轮推进设计树,直到每个决策分支都已关闭并获得用户共识,同时持续维护当前 change 的设计树、日志、领域上下文和架构决策。
219
- - **I-implement** — 实现:基于 Ready Ticket 或获批小型 Spec 执行设计检查、TDD、动态派单、双轴审查、Ticket worktree commit、候选合并验证和 Lead Evidence 回写。
222
+ - **I-implement** — 实现:基于 Ready Ticket 或获批小型 Spec 执行设计检查、TDD、动态派单、双轴审查、按 Goal Plan 选择的 current workspace 或 Ticket worktree 提交、直接父分支或候选合并验证和 Lead Evidence 回写。
220
223
  - **I-init-setup** — 初始化设置:初始化 SpecDev 的语言、配置、全局状态、本地 change 追踪、领域知识布局、验证命令和并发治理。
221
224
  - **P-goal-plan** — 目标规划:在跨 Ticket 协调复杂度需要时,以固定 Lead、动态派单、DAG/Gate 和候选合并门禁生成决策完备且可恢复的执行计划。
222
225
  - **P-prototype** — 原型:在获授权的临时 branch/worktree 中构建一次性 Logic 或 UI 原型,回答一个明确设计问题并持久化答案、资产定位和清理状态。
@@ -242,7 +245,7 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
242
245
 
243
246
  ```bash
244
247
  node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
245
- --stage <triage|diagnosis|grill|spec|tickets|goal-plan|implement|review|prototype|wayfinder|complete> \
248
+ --stage <triage|diagnosis|grill|eli5|spec|tickets|goal-plan|implement|review|prototype|wayfinder|complete> \
246
249
  <Path>{roots.state}/specdev/changes/{change}</Path>
247
250
  ```
248
251
 
@@ -20,6 +20,7 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
20
20
  | Evidence | `<Path>{roots.state}/specdev/changes/{change}/evidence/{ticket-id}.md</Path>` | 实际修改、命令、结果、验收映射、偏差、风险和提交引用 | 新的产品或架构决策 |
21
21
  | 代码审查 | `<Path>{roots.state}/specdev/changes/{change}/reviews/CR-###.md</Path>` | 固定点、标准轴和规范轴 finding | 实施修复或合并两轴排名 |
22
22
  | 原型记录 | `<Path>{roots.state}/specdev/changes/{change}/prototypes/{prototype-id}/record.md</Path>` | 一个问题、分支、资产、答案、promotion 和清理 | 生产实现或多个问题的计划 |
23
+ | 五岁图解 | `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>` | 面向五岁、零背景读者的大图少字解释 | 产品决定、架构决定或实现授权 |
23
24
  | Stakeholder 问卷 | `<Path>{roots.state}/specdev/changes/{change}/questionnaires/{slug}.md</Path>` | 第三方原始回答和恢复条件 | 未经转录确认的产品/架构决定 |
24
25
  | Wayfinder 地图 | `<Path>{roots.state}/specdev/changes/{change}/wayfinder-map.md</Path>` | 目的地、说明、已关闭决策索引、战争迷雾和范围之外 | 开放 Ticket 正文或答案详情 |
25
26
  | Wayfinder Ticket | `<Path>{roots.state}/specdev/changes/{change}/investigation/{investigation-id}.md</Path>` | 一个可精确陈述的问题、类型、阻塞和关闭状态 | 解决方案评论或交付目标 |
@@ -4,7 +4,7 @@
4
4
 
5
5
  ```bash
6
6
  node <Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path> \
7
- --stage <triage|diagnosis|grill|spec|tickets|goal-plan|implement|review|prototype|wayfinder|complete> \
7
+ --stage <triage|diagnosis|grill|eli5|spec|tickets|goal-plan|implement|review|prototype|wayfinder|complete> \
8
8
  --repo <project-root> \
9
9
  <Path>{roots.state}/specdev/changes/{change}</Path>
10
10
  ```