@namewta/speculo 0.8.6 → 0.8.8

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 (98) hide show
  1. package/dist/src/structured.js +8 -4
  2. package/dist/src/structured.js.map +1 -1
  3. package/package.json +1 -1
  4. package/template/canonical/canonical-specdev-goal-plan.md +67 -20
  5. package/template/canonical/canonical-specdev-grill-with-docs.md +17 -9
  6. package/template/canonical/canonical-specdev-orchestrate-implementation.md +2784 -0
  7. package/template/canonical/canonical-specdev-spec.md +19 -9
  8. package/template/canonical/canonical-specdev-tickets.md +58 -16
  9. package/template/canonical/canonical-specdev-wayfinder.md +11 -11
  10. package/template/workflows/specdev/A-archive-and-consolidate/A-archive-and-consolidate.md +1 -1
  11. package/template/workflows/specdev/I-implement/I-implement.md +10 -5
  12. package/template/workflows/specdev/I-implement/execution-preflight.md +2 -0
  13. package/template/workflows/specdev/I-init-setup/I-init-setup.md +1 -1
  14. package/template/workflows/specdev/I-init-setup/config-template.json +2 -2
  15. package/template/workflows/specdev/O-orchestrate-implementation/O-orchestrate-implementation.md +129 -0
  16. package/template/workflows/specdev/O-orchestrate-implementation/conflict-and-drift.md +18 -0
  17. package/template/workflows/specdev/O-orchestrate-implementation/execution-loop.md +30 -0
  18. package/template/workflows/specdev/O-orchestrate-implementation/implementation-evidence-template.md +39 -0
  19. package/template/workflows/specdev/O-orchestrate-implementation/implementation-map-template.md +50 -0
  20. package/template/workflows/specdev/O-orchestrate-implementation/implementation-plan-template.md +61 -0
  21. package/template/workflows/specdev/O-orchestrate-implementation/input-readiness.md +25 -0
  22. package/template/workflows/specdev/O-orchestrate-implementation/super-dag.md +27 -0
  23. package/template/workflows/specdev/P-goal-plan/planning-modes.md +1 -1
  24. package/template/workflows/specdev/P-prototype/P-prototype.md +30 -26
  25. package/template/workflows/specdev/P-prototype/design-library/INDEX.md +43 -0
  26. package/template/workflows/specdev/P-prototype/design-library/color-and-theme.md +65 -0
  27. package/template/workflows/specdev/P-prototype/design-library/foundations.md +66 -0
  28. package/template/workflows/specdev/P-prototype/design-library/interaction-patterns.md +61 -0
  29. package/template/workflows/specdev/P-prototype/design-library/product-pattern-index.md +73 -0
  30. package/template/workflows/specdev/P-prototype/design-library/research-provenance.md +54 -0
  31. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/METHODOLOGY.md +90 -0
  32. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/README.md +31 -0
  33. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/data/extended-projects.json +241 -0
  34. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/data/projects.json +253 -0
  35. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/reference/USAGE.md +40 -0
  36. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/reference/design-tokens.css +145 -0
  37. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/report/OPEN_SOURCE_UI_RESEARCH_2026.md +519 -0
  38. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/PROJECT_TEMPLATE.md +29 -0
  39. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/README.md +9 -0
  40. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/claude-code-modern-clients.md +407 -0
  41. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/creative-ai-communication.md +574 -0
  42. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/data-dev-tools.md +432 -0
  43. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/personal-multiplatform-apps.md +185 -0
  44. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/productivity-collaboration.md +398 -0
  45. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/01-dense-ide.html +68 -0
  46. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/02-monochrome-console.html +18 -0
  47. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/03-soft-personal-ai.html +17 -0
  48. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/04-responsive-web.html +14 -0
  49. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/05-mobile-supervisor.html +16 -0
  50. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/06-cross-platform-workspace.html +17 -0
  51. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/07-local-first-content.html +9 -0
  52. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/08-media-first.html +17 -0
  53. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/README.md +49 -0
  54. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/ATTRIBUTION.md +9 -0
  55. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/landscape.jpg +0 -0
  56. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/lucide.js +20494 -0
  57. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/mountain.jpg +0 -0
  58. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/workspace.jpg +0 -0
  59. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/index.html +70 -0
  60. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/package-lock.json +78 -0
  61. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/package.json +12 -0
  62. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/screenshots/index-desktop.png +0 -0
  63. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/scripts/gallery.js +134 -0
  64. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/styles/base.css +795 -0
  65. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/styles/pages.css +533 -0
  66. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/tests/gallery.spec.js +56 -0
  67. package/template/workflows/specdev/P-prototype/design-library/responsive-and-platforms.md +53 -0
  68. package/template/workflows/specdev/P-prototype/design-library/style-index.md +32 -0
  69. package/template/workflows/specdev/P-prototype/design-package.schema.json +70 -0
  70. package/template/workflows/specdev/P-prototype/design-system-template.md +366 -0
  71. package/template/workflows/specdev/P-prototype/detect-existing-style.md +53 -0
  72. package/template/workflows/specdev/P-prototype/generate-design-package.md +50 -0
  73. package/template/workflows/specdev/P-prototype/style-selection-protocol.md +41 -0
  74. package/template/workflows/specdev/P-prototype/tools/materialize-prototype.mjs +126 -0
  75. package/template/workflows/specdev/P-prototype/tools/validate-design-package.mjs +155 -0
  76. package/template/workflows/specdev/README.md +28 -15
  77. package/template/workflows/specdev/T-triage/T-triage.md +1 -1
  78. package/template/workflows/specdev/W-wayfinder/W-wayfinder.md +2 -2
  79. package/template/workflows/specdev/W-wayfinder/local-tracker-contract.md +3 -4
  80. package/template/workflows/specdev/common/README.md +6 -3
  81. package/template/workflows/specdev/common/rules/artifact-contract.md +9 -3
  82. package/template/workflows/specdev/common/rules/change-completion.md +3 -0
  83. package/template/workflows/specdev/common/rules/deviation-control.md +2 -0
  84. package/template/workflows/specdev/common/rules/evidence-and-verification.md +2 -0
  85. package/template/workflows/specdev/common/rules/parent-implementation-orchestration.md +27 -0
  86. package/template/workflows/specdev/common/rules/path-ownership.md +3 -1
  87. package/template/workflows/specdev/common/schemas/config.schema.json +4 -4
  88. package/template/workflows/specdev/common/schemas/implementation-map.schema.json +40 -0
  89. package/template/workflows/specdev/common/schemas/implementation-plan.schema.json +44 -0
  90. package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +4 -4
  91. package/template/workflows/specdev/common/skills/dev-worktree/references/create.md +1 -3
  92. package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +5 -3
  93. package/template/workflows/specdev/common/tools/README.md +2 -2
  94. package/template/workflows/specdev/common/tools/validate-specdev.mjs +572 -30
  95. package/template/workflows/specdev/P-prototype/logic-prototype.md +0 -24
  96. package/template/workflows/specdev/P-prototype/prototype-record-template.md +0 -46
  97. package/template/workflows/specdev/P-prototype/ui-prototype.md +0 -21
  98. package/template/workflows/specdev/common/schemas/prototype-record.schema.json +0 -24
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { lstat, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
4
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+
7
+ const REQUIRED_TARGETS = new Set([
8
+ "final/index.html",
9
+ "final/styles.css",
10
+ "final/app.js",
11
+ ]);
12
+
13
+ const TARGET_LANGUAGE = new Map([
14
+ ["final/index.html", new Set(["html"])],
15
+ ["final/styles.css", new Set(["css"])],
16
+ ["final/app.js", new Set(["javascript", "js"])],
17
+ ]);
18
+
19
+ export function extractPrototypeSources(markdown) {
20
+ const pattern = /<!-- PROTOTYPE-FILE: ([^\r\n]+) -->\r?\n```(html|css|javascript|js)\r?\n([\s\S]*?)\r?\n```\r?\n<!-- \/PROTOTYPE-FILE -->/g;
21
+ const sources = new Map();
22
+
23
+ for (const match of markdown.matchAll(pattern)) {
24
+ const target = match[1].trim().replaceAll("\\", "/");
25
+ if (isAbsolute(target) || !TARGET_LANGUAGE.has(target)) {
26
+ throw new Error(`unsupported prototype target: ${target}`);
27
+ }
28
+ if (!TARGET_LANGUAGE.get(target).has(match[2])) throw new Error(`invalid code fence language for ${target}: ${match[2]}`);
29
+ if (sources.has(target)) throw new Error(`duplicate prototype target: ${target}`);
30
+ sources.set(target, `${match[3].replaceAll("\r\n", "\n")}\n`);
31
+ }
32
+
33
+ const openingCount = markdown.match(/<!-- PROTOTYPE-FILE:/g)?.length ?? 0;
34
+ const closingCount = markdown.match(/<!-- \/PROTOTYPE-FILE -->/g)?.length ?? 0;
35
+ if (openingCount !== 3 || closingCount !== 3 || sources.size !== 3) {
36
+ throw new Error(`expected exactly three paired PROTOTYPE-FILE blocks; found ${openingCount} openings, ${closingCount} closings, ${sources.size} valid blocks`);
37
+ }
38
+
39
+ for (const target of REQUIRED_TARGETS) {
40
+ if (!sources.has(target)) throw new Error(`missing prototype source block: ${target}`);
41
+ }
42
+
43
+ return sources;
44
+ }
45
+
46
+ function resolveInside(root, target) {
47
+ const destination = resolve(root, ...target.split("/"));
48
+ const local = relative(root, destination);
49
+ if (!local || local.startsWith(`..${sep}`) || local === ".." || isAbsolute(local)) {
50
+ throw new Error(`prototype target escapes design package: ${target}`);
51
+ }
52
+ return destination;
53
+ }
54
+
55
+ async function assertNoSymlink(root, target) {
56
+ let current = root;
57
+ const local = relative(root, target);
58
+ for (const segment of ["", ...local.split(sep).filter(Boolean)]) {
59
+ if (segment) current = join(current, segment);
60
+ try {
61
+ const info = await lstat(current);
62
+ if (info.isSymbolicLink()) throw new Error(`prototype path must not contain symlinks: ${current}`);
63
+ } catch (error) {
64
+ if (error.code !== "ENOENT") throw error;
65
+ }
66
+ }
67
+ }
68
+
69
+ async function atomicWrite(destination, content) {
70
+ await mkdir(dirname(destination), { recursive: true });
71
+ const temporary = `${destination}.tmp-${process.pid}-${Date.now()}`;
72
+ await writeFile(temporary, content, "utf8");
73
+ try {
74
+ await rename(temporary, destination);
75
+ } catch (error) {
76
+ await rm(temporary, { force: true });
77
+ throw error;
78
+ }
79
+ }
80
+
81
+ export async function materialize(markdownPath, { check = false } = {}) {
82
+ const absoluteMarkdown = resolve(markdownPath);
83
+ const root = dirname(absoluteMarkdown);
84
+ const markdown = await readFile(absoluteMarkdown, "utf8");
85
+ const sources = extractPrototypeSources(markdown);
86
+ const mismatches = [];
87
+
88
+ for (const [target, expected] of sources) {
89
+ const destination = resolveInside(root, target);
90
+ await assertNoSymlink(root, destination);
91
+ if (check) {
92
+ let actual;
93
+ try {
94
+ actual = await readFile(destination, "utf8");
95
+ } catch (error) {
96
+ if (error.code === "ENOENT") {
97
+ mismatches.push(`${target}: missing`);
98
+ continue;
99
+ }
100
+ throw error;
101
+ }
102
+ if (actual !== expected) mismatches.push(`${target}: differs from design-system.md`);
103
+ } else {
104
+ await atomicWrite(destination, expected);
105
+ }
106
+ }
107
+
108
+ if (mismatches.length > 0) throw new Error(mismatches.join("\n"));
109
+ return [...sources.keys()];
110
+ }
111
+
112
+ async function main() {
113
+ const args = process.argv.slice(2);
114
+ const check = args.includes("--check");
115
+ const paths = args.filter((arg) => arg !== "--check");
116
+ if (paths.length !== 1) throw new Error("usage: materialize-prototype.mjs [--check] <design-system.md>");
117
+ const targets = await materialize(paths[0], { check });
118
+ console.log(`${check ? "verified" : "materialized"} ${targets.length} prototype files`);
119
+ }
120
+
121
+ if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) {
122
+ main().catch((error) => {
123
+ console.error(error.message);
124
+ process.exitCode = 1;
125
+ });
126
+ }
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { lstat, readdir, readFile, stat } from "node:fs/promises";
4
+ import { basename, dirname, join, resolve } from "node:path";
5
+ import { extractPrototypeSources, materialize } from "./materialize-prototype.mjs";
6
+
7
+ const REQUIRED_HEADINGS = [
8
+ "## Project Evidence",
9
+ "## Style Decision",
10
+ "## Foundation Tokens",
11
+ "## Component and State Contract",
12
+ "## Interaction Contract",
13
+ "## Responsive Contract",
14
+ "## Prototype Sources",
15
+ "## Validation and Handoff",
16
+ ];
17
+
18
+ function frontmatterValue(header, key) {
19
+ const match = header.match(new RegExp(`^${key}:\\s*(.*?)\\s*$`, "m"));
20
+ if (!match) return undefined;
21
+ const value = match[1].trim();
22
+ if (value === "null") return null;
23
+ if (/^\d+$/.test(value)) return Number(value);
24
+ return value.replace(/^['"]|['"]$/g, "");
25
+ }
26
+
27
+ function frontmatterArray(header, key) {
28
+ const value = frontmatterValue(header, key);
29
+ if (typeof value !== "string" || !value.startsWith("[") || !value.endsWith("]")) return [];
30
+ return value.slice(1, -1).split(",").map((item) => item.trim().replace(/^['"]|['"]$/g, "")).filter(Boolean);
31
+ }
32
+
33
+ async function isFile(path) {
34
+ try {
35
+ return (await stat(path)).isFile();
36
+ } catch (error) {
37
+ if (error.code === "ENOENT") return false;
38
+ throw error;
39
+ }
40
+ }
41
+
42
+ async function isSymlink(path) {
43
+ try {
44
+ return (await lstat(path)).isSymbolicLink();
45
+ } catch (error) {
46
+ if (error.code === "ENOENT") return false;
47
+ throw error;
48
+ }
49
+ }
50
+
51
+ async function validate(path, { allowDraft = false } = {}) {
52
+ const designPath = resolve(path);
53
+ if (await isSymlink(designPath)) throw new Error("design-system.md must not be a symlink");
54
+ const markdown = await readFile(designPath, "utf8");
55
+ const match = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
56
+ const errors = [];
57
+ if (!match) throw new Error("design-system.md requires YAML frontmatter");
58
+ const [, header, body] = match;
59
+ const meta = {
60
+ schemaVersion: frontmatterValue(header, "schema_version"),
61
+ artifact: frontmatterValue(header, "artifact"),
62
+ change: frontmatterValue(header, "change"),
63
+ designId: frontmatterValue(header, "design_id"),
64
+ status: frontmatterValue(header, "status"),
65
+ projectKind: frontmatterValue(header, "project_kind"),
66
+ platforms: frontmatterArray(header, "platforms"),
67
+ candidates: frontmatterArray(header, "style_candidates"),
68
+ selectedStyle: frontmatterValue(header, "selected_style"),
69
+ density: frontmatterValue(header, "density"),
70
+ colorMode: frontmatterValue(header, "color_mode"),
71
+ researchSnapshot: frontmatterValue(header, "research_snapshot"),
72
+ prototypeFiles: frontmatterArray(header, "prototype_files"),
73
+ updatedAt: frontmatterValue(header, "updated_at"),
74
+ };
75
+
76
+ const designRoot = dirname(designPath);
77
+ const expectedDesignId = basename(designRoot);
78
+ const expectedChange = basename(dirname(dirname(designRoot)));
79
+ if (meta.schemaVersion !== 2 || meta.artifact !== "ui-design-system") errors.push("artifact/schema_version must be ui-design-system/2");
80
+ if (!/^UI-\d{3,}$/.test(String(meta.designId ?? "")) || meta.designId !== expectedDesignId) errors.push("design_id must match the UI-NNN directory");
81
+ if (meta.change !== expectedChange) errors.push("change must match the owning change directory");
82
+ if (!new Set(["detecting", "selecting", "ready", "blocked"]).has(meta.status)) errors.push("invalid design status");
83
+ if (!new Set(["existing", "new"]).has(meta.projectKind)) errors.push("project_kind must be existing or new");
84
+ if (!meta.platforms.length || meta.platforms.some((value) => !new Set(["desktop", "web", "mobile"]).has(value))) errors.push("platforms must contain desktop, web, or mobile");
85
+ if (meta.candidates.length < 2 || meta.candidates.length > 4 || new Set(meta.candidates).size !== meta.candidates.length) errors.push("style_candidates must contain 2-4 unique values");
86
+ if (meta.researchSnapshot !== "49b5659") errors.push("research_snapshot must equal 49b5659");
87
+ for (const required of ["final/index.html", "final/styles.css", "final/app.js"]) {
88
+ if (!meta.prototypeFiles.includes(required)) errors.push(`prototype_files must include ${required}`);
89
+ }
90
+ if (typeof meta.updatedAt !== "string" || Number.isNaN(Date.parse(meta.updatedAt))) errors.push("updated_at must be ISO-8601");
91
+ for (const heading of REQUIRED_HEADINGS) if (!body.includes(heading)) errors.push(`missing '${heading}'`);
92
+ if (/(?:[A-Za-z]:[\\/]|\/(?:Users|home|tmp)\/)/.test(markdown)) errors.push("design package contains a machine-specific absolute path");
93
+
94
+ let sources;
95
+ try {
96
+ sources = extractPrototypeSources(markdown);
97
+ } catch (error) {
98
+ errors.push(error.message);
99
+ }
100
+
101
+ if (meta.status === "ready" && !allowDraft) {
102
+ if (!meta.selectedStyle || !meta.candidates.includes(meta.selectedStyle)) errors.push("ready design requires selected_style from style_candidates");
103
+ if (!new Set(["compact", "default", "comfortable", "touch"]).has(meta.density)) errors.push("ready design requires a density");
104
+ if (!new Set(["light", "dark", "system", "both"]).has(meta.colorMode)) errors.push("ready design requires a color_mode");
105
+ const comparisonIndex = join(designRoot, "comparison", "index.html");
106
+ const variantsRoot = join(designRoot, "comparison", "variants");
107
+ if (!(await isFile(comparisonIndex))) errors.push("ready design requires comparison/index.html");
108
+ if (await isSymlink(comparisonIndex)) errors.push("comparison/index.html must not be a symlink");
109
+ if (await isSymlink(join(designRoot, "comparison")) || await isSymlink(variantsRoot)) errors.push("comparison directories must not be symlinks");
110
+ let variants = [];
111
+ try {
112
+ variants = (await readdir(variantsRoot)).filter((entry) => entry.endsWith(".html"));
113
+ } catch (error) {
114
+ if (error.code !== "ENOENT") throw error;
115
+ }
116
+ if (variants.length < 2 || variants.length > 4) errors.push("ready design requires 2-4 comparison variant HTML files");
117
+ for (const variant of variants) {
118
+ if (await isSymlink(join(variantsRoot, variant))) errors.push(`comparison variant must not be a symlink: ${variant}`);
119
+ }
120
+ if (await isSymlink(join(designRoot, "final"))) errors.push("final directory must not be a symlink");
121
+ if (sources) {
122
+ try {
123
+ await materialize(designPath, { check: true });
124
+ } catch (error) {
125
+ errors.push(error.message);
126
+ }
127
+ const html = sources.get("final/index.html") ?? "";
128
+ const css = sources.get("final/styles.css") ?? "";
129
+ const js = sources.get("final/app.js") ?? "";
130
+ if (!/href=["']styles\.css["']/.test(html) || !/src=["']app\.js["']/.test(html)) errors.push("final HTML must reference relative styles.css and app.js");
131
+ if (/<(?:script|link)[^>]+(?:src|href)=["']https?:/i.test(html)) errors.push("final HTML must not load remote scripts or styles");
132
+ if (!css.includes(":focus-visible")) errors.push("final CSS must define :focus-visible");
133
+ if (!css.includes("prefers-reduced-motion")) errors.push("final CSS must handle prefers-reduced-motion");
134
+ if (!js.includes("addEventListener")) errors.push("final JS must implement an explicit interaction");
135
+ }
136
+ }
137
+
138
+ if (errors.length) throw new Error(errors.join("\n"));
139
+ return meta;
140
+ }
141
+
142
+ const args = process.argv.slice(2);
143
+ const allowDraft = args.includes("--allow-draft");
144
+ const paths = args.filter((arg) => arg !== "--allow-draft");
145
+ if (paths.length !== 1) {
146
+ console.error("usage: validate-design-package.mjs [--allow-draft] <design-system.md>");
147
+ process.exitCode = 1;
148
+ } else {
149
+ validate(paths[0], { allowDraft })
150
+ .then((meta) => console.log(`valid ${meta.designId} (${meta.status})`))
151
+ .catch((error) => {
152
+ console.error(error.message);
153
+ process.exitCode = 1;
154
+ });
155
+ }
@@ -37,6 +37,8 @@ Triage 本地完成后按确认回写/关闭支持的远程 Issue
37
37
  Archive 归档历史并将经验证知识提升为当前长期知识
38
38
  ```
39
39
 
40
+ 多个已经完成 Ready Spec 与 Ready Tickets 的 change 需要在一个会话持续实现时,O-orchestrate-implementation 额外创建一个父实现 change;父 Implementation Map/Plan 位于上述单 change 链之外,只编排实现,不参与或替代任何子 change 的需求澄清、Spec 或 Ticket 生产。
41
+
40
42
  核心状态工件:
41
43
 
42
44
  - `<Path>{roots.state}/specdev/changes/{change}/source.md</Path>`
@@ -45,14 +47,20 @@ Archive 归档历史并将经验证知识提升为当前长期知识
45
47
  - `<Path>{roots.state}/specdev/changes/{change}/ticket/</Path>`
46
48
  - `<Path>{roots.state}/specdev/changes/{change}/tickets-map.md</Path>`
47
49
  - `<Path>{roots.state}/specdev/changes/{change}/goal-plan.md</Path>`
50
+ - `<Path>{roots.state}/specdev/changes/{change}/implementation-map.md</Path>`
51
+ - `<Path>{roots.state}/specdev/changes/{change}/implementation-plan.md</Path>`
48
52
  - `<Path>{roots.state}/specdev/changes/{change}/design-tree.json</Path>`
49
53
  - `<Path>{roots.state}/specdev/changes/{change}/wayfinder-map.md</Path>`
50
54
  - `<Path>{roots.state}/specdev/changes/{change}/investigation/</Path>`
51
55
  - `<Path>{roots.state}/specdev/changes/{change}/evidence/</Path>`
52
56
  - `<Path>{roots.state}/specdev/changes/{change}/reviews/</Path>`
53
- - `<Path>{roots.state}/specdev/changes/{change}/prototypes/</Path>`
57
+ - `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/design-system.md</Path>`
58
+ - `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/comparison/</Path>`
59
+ - `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/final/</Path>`
54
60
  - `<Path>{roots.state}/specdev/changes/{change}/questionnaires/</Path>`
55
61
 
62
+ `{design-id}` 由 P-prototype 在当前 change 内分配为最小未占用的 `UI-NNN`;设计系统文档是设计权威,comparison 与 final 是其可运行投影。
63
+
56
64
  工件职责和冲突裁决位于 `<Path>{roots.workflows}/specdev/common/rules/artifact-contract.md</Path>`。
57
65
 
58
66
  ## 持久化约定
@@ -91,6 +99,8 @@ Archive 归档历史并将经验证知识提升为当前长期知识
91
99
  - `<Path>{roots.state}/specdev/changes/{change}/ticket/</Path>`
92
100
  - `<Path>{roots.state}/specdev/changes/{change}/tickets-map.md</Path>`
93
101
  - `<Path>{roots.state}/specdev/changes/{change}/goal-plan.md</Path>`
102
+ - `<Path>{roots.state}/specdev/changes/{change}/implementation-map.md</Path>`
103
+ - `<Path>{roots.state}/specdev/changes/{change}/implementation-plan.md</Path>`
94
104
  - `<Path>{roots.state}/specdev/changes/{change}/wayfinder-map.md</Path>`
95
105
  - `<Path>{roots.state}/specdev/changes/{change}/investigation/</Path>`
96
106
  - `<Path>{roots.state}/specdev/changes/{change}/investigation/comments/</Path>`
@@ -98,7 +108,9 @@ Archive 归档历史并将经验证知识提升为当前长期知识
98
108
  - `<Path>{roots.state}/specdev/changes/{change}/architecture-review.html</Path>`
99
109
  - `<Path>{roots.state}/specdev/changes/{change}/evidence/</Path>`
100
110
  - `<Path>{roots.state}/specdev/changes/{change}/reviews/</Path>`
101
- - `<Path>{roots.state}/specdev/changes/{change}/prototypes/</Path>`
111
+ - `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/design-system.md</Path>`
112
+ - `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/comparison/</Path>`
113
+ - `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/final/</Path>`
102
114
  - `<Path>{roots.state}/specdev/changes/{change}/questionnaires/</Path>`
103
115
 
104
116
  ## 全局治理原则
@@ -117,6 +129,7 @@ Archive 归档历史并将经验证知识提升为当前长期知识
117
129
  12. **完成与归档分离**:本地完成按 change completion 合同决定;远程 close 失败不回滚完成,但必须 reconcile 或 waive 后才归档。
118
130
  13. **Lead 与隔离正交**:Lead 固定拥有 SpecDev 状态、Evidence 与父分支;是否派遣 subagent 由 Lead 动态决定。Goal Plan 创建时询问 Ticket 是否开启 worktree,默认不开启;选择只作用于当前 Goal Plan。
119
131
  14. **策略化验收**:current 模式使用当前 workspace 严格串行、direct-parent 验证;required 模式使用 source worktree 与 parent-candidate。只有 required 模式创建独立 Ticket worktree。
132
+ 15. **父子权威隔离**:父实现 change 只拥有 Ready 子 change 的组合 Ticket DAG、serialization、全局 workspace/资源和实现进度投影;子 change 继续拥有全部行为与实现合同。一个未完成子 change 只能属于一个未完成父实现 change。
120
133
 
121
134
  共享规则:
122
135
 
@@ -129,34 +142,32 @@ Archive 归档历史并将经验证知识提升为当前长期知识
129
142
  - `<Path>{roots.workflows}/specdev/common/rules/path-reference-contract.md</Path>`
130
143
  - `<Path>{roots.workflows}/specdev/common/rules/codebase-design.md</Path>`
131
144
  - `<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>`
145
+ - `<Path>{roots.workflows}/specdev/common/rules/parent-implementation-orchestration.md</Path>`
132
146
 
133
147
  ## 启动协议
134
148
 
135
149
  1. 解析 workflow 和 state roots。
136
150
  2. 读取 `<Path>{roots.state}/specdev/config.json</Path>`;不存在时运行 `<Path>{roots.workflows}/specdev/I-init-setup/I-init-setup.md</Path>`。
137
151
  3. 读取 `<Path>{roots.state}/specdev/status.json</Path>`:用户指定 change 优先;唯一活跃 change 直接使用;无活跃时创建;多个候选时请求消歧。
138
- 4. 若当前 change 已有非空 `current_work`,先恢复或显式结束该 Work;否则将 `current_work` 设置为本次 work id。
139
- 5. 只加载当前步骤需要的 work 子文件和共享规则。
140
- 6. 完成后写入产物、运行适用校验、更新状态和 `works_run`。
152
+ 4. 读取当前 change `<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>`。若当前 change 是未完成父 Implementation Map 的成员,同时读取父 Map/Plan;父 O Work 自身恢复时以父产物为入口,不逐个手工激活成员。
153
+ 5. 若当前 change 已有非空 `current_work`,先恢复或显式结束该 Work;否则将 `current_work` 设置为本次 work id。
154
+ 6. 只加载当前步骤需要的 work 子文件和共享规则。
155
+ 7. 完成后写入产物、运行适用校验、更新 change 状态和 `works_run`;全局状态只更新 active/archived 索引。
141
156
 
142
157
  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。
143
158
 
144
159
  ## 状态字段
145
160
 
146
- `<Path>{roots.state}/specdev/status.json</Path>` 使用全局 schema v5;Spec/Ticket/Tickets Map 继续使用各自 schema v3,config 使用 schema v5,Goal Plan 使用 schema v6,`<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 使用 schema v6:
161
+ `<Path>{roots.state}/specdev/status.json</Path>` 使用全局 schema v5;Spec/Ticket/Tickets Map 继续使用各自 schema v3,config 使用 schema v5,Goal Plan 使用 schema v6,Implementation Map/Plan 使用 schema v1,`<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 使用 schema v6:
147
162
 
148
163
  - `schema_version`(数字):全局状态 schema 版本,固定为 `5`。
149
164
  - `workflow`(字符串):workflow 标识,固定为 `"specdev"`。
150
- - `active`(对象数组):当前活跃 change;每项包含:
151
- - `change`(字符串):change 目录名,格式 `"YYYY-MM-DD-<kebab-topic>"`。
152
- - `current_work`(字符串或 null):当前 work id,如 `"specdev/implement"`;无运行中 work 时为 null。
153
- - `works_run`(去重字符串数组):已成功完成的 work id;重复运行同一 work 不追加副本。
154
- - `claimed_investigations`(对象数组,可选):并行调查领取记录;每项包含 `id`、`owner`、可选 `session` 和 `claimed_at`。
165
+ - `active`(对象数组):当前活跃 change 的严格索引;每项只能包含 `change`,格式 `"YYYY-MM-DD-<kebab-topic>"`。
155
166
  - `archived`(去重字符串数组):已归档 change 名称。详细归档时间、路径和 promotion 摘要只存在于 `<Path>{roots.state}/specdev/archive/YYYY-MM/{change}/.status.json</Path>`。
156
167
 
157
- `active[].change` 必须唯一,且不得同时出现在 `archived`。开始 Work 时设置 `current_work`;暂停或可恢复阻塞时保留;成功完成时加入 `works_run` 并清空;取消时清空但不加入。逐次时间、结果和审计证据由 change 自有状态、Work 主产物、Evidence 或 LOG 承载,不写入全局索引。
168
+ `active[].change` 必须唯一,且不得同时出现在 `archived`。`current_work`、`works_run` 和 `claimed_investigations` 只存在于 change 自有 `<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>`:开始 Work 时设置 `current_work`;暂停或可恢复阻塞时保留;成功完成时加入 `works_run` 并清空;取消时清空但不加入。逐次时间、结果和审计证据由 change 自有状态、Work 主产物、Evidence 或 LOG 承载,不写入全局索引。
158
169
 
159
- `<Path>{roots.state}/specdev/config.json</Path>` 的 `execution.max_implementation_agents`、`max_integration_attempts` 和 planning 原型变体字段均为可配置正整数,初始化时写入默认值;仅 implementation subagent 受前者约束且不含 Lead,current workspace 仍保持单 writer 串行安全不变量;只读 review/research/test-observation agent 不设 SpecDev 数字上限。
170
+ `<Path>{roots.state}/specdev/config.json</Path>` 的 `execution.max_implementation_agents`、`max_integration_attempts` 和 planning UI 设计候选字段均为可配置正整数;候选默认值与上限必须落在 2-4 且默认值不大于上限。仅 implementation subagent 受前者约束且不含 Lead,current workspace 仍保持单 writer 串行安全不变量;只读 review/research/test-observation agent 不设 SpecDev 数字上限。
160
171
 
161
172
  `<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 的 `worktrees` 保存 Ticket 级 `base_sha`、父分支、workspace/implementation/integration owner、workspace locator、implementation/source checkpoint、适用 candidate/result SHA、验证、E2E disposition 与生命周期状态。current 记录使用 `workspace_ref=current` 和 direct-parent;required 记录使用 source/parent-candidate。每个实现 Ticket 都有一条记录;父分支只有在对应策略的验证通过后推进。`removed` 是 required 集成后来源 branch/worktree 完成清理的终态,必须保留全部集成与 E2E 证据。
162
173
 
@@ -189,11 +200,12 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
189
200
  | 疑难 bug 或性能回归 | D-diagnose-bugs | S / T / I / R / W |
190
201
  | 模糊但可通过决策访谈收敛 | G-grill-with-docs | P / S / T / W |
191
202
  | 路径超出单次上下文 | W-wayfinder | G / P / D / S / T |
192
- | 需要用代码回答逻辑/UI 问题 | P-prototype | G / S / T / I |
203
+ | 需要检测项目 UI、选择设计方向并生成可运行设计包 | P-prototype | G / S / T / I |
193
204
  | 固定点 diff、branch 或 PR review | C-code-review | completed / T / S / G |
194
205
  | 外部行为已清楚 | S-spec | T-tickets |
195
206
  | Ready Spec 需要垂直切片 | T-tickets | P-goal-plan / I |
196
207
  | 多 Ticket 协调 | P-goal-plan | I / Triage / A |
208
+ | 多个 Ready change 的持续实现 | O-orchestrate-implementation | I-implement 循环 / completed / blocked |
197
209
  | Ready 执行 | I-implement | Triage / A / blocked / deviation |
198
210
  | 架构健康扫描 | R-review-architecture | G / T |
199
211
 
@@ -209,8 +221,9 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
209
221
  - **G-grill-with-docs** — 设计访谈(带文档):以完整 frontier 逐轮推进设计树,直到每个决策分支都已关闭并获得用户共识,同时持续维护当前 change 的设计树、日志、领域上下文和架构决策。
210
222
  - **I-implement** — 实现:基于 Ready Ticket 或获批小型 Spec 执行设计检查、TDD、动态派单、双轴审查、按 Goal Plan 选择的 current workspace 或 Ticket worktree 提交、直接父分支或候选合并验证和 Lead Evidence 回写。
211
223
  - **I-init-setup** — 初始化设置:初始化 SpecDev 的语言、配置、全局状态、本地 change 追踪、领域知识布局、验证命令和并发治理。
224
+ - **O-orchestrate-implementation** — 编排实现:将两个或以上已完成 Ready Spec 与 Ready Tickets 的 change 编译为跨 change implementation super-DAG,并由单一 Lead 在一个会话中持续调度实现、验证和集成。
212
225
  - **P-goal-plan** — 目标规划:在跨 Ticket 协调复杂度需要时,以固定 Lead、动态派单、DAG/Gate 和候选合并门禁生成决策完备且可恢复的执行计划。
213
- - **P-prototype** — 原型:在获授权的临时 branch/worktree 中构建一次性 Logic UI 原型,回答一个明确设计问题并持久化答案、资产定位和清理状态。
226
+ - **P-prototype** — UI 设计原型:检测现有项目的 UI 事实,按产品任务推荐并逐步选择设计风格,生成持久化设计系统文档、多风格 HTML 对照和可运行 HTML/CSS/JS 原型。
214
227
  - **R-review-architecture** — 架构审查:从用户指定范围或 Git 热点扫描代码库的深化机会,以持久化可视化 HTML 呈现候选,并对用户选择的一个方案运行设计树访谈。
215
228
  - **S-spec** — 编写 Spec:综合已知事实、设计决定、诊断与代码现状,产出以外部行为和验收合同为权威的 Ready Spec。
216
229
  - **T-tickets** — 拆分 Tickets:将 Spec、计划或已确认对话拆成曳光弹式垂直切片;每个 Ticket 决策完备、可独立验证、适配单一上下文,并建立阻塞 DAG、路径所有权和执行就绪门禁。
@@ -38,7 +38,7 @@ Triage 是 SpecDev 唯一的远程摄入与关闭边界。开发期间,`<Path>
38
38
  - 根因未知的 bug → `<Path>{roots.workflows}/specdev/D-diagnose-bugs/D-diagnose-bugs.md</Path>`;
39
39
  - 产品或架构决定未锁定 → `<Path>{roots.workflows}/specdev/G-grill-with-docs/G-grill-with-docs.md</Path>`;
40
40
  - 路径超出单次上下文 → `<Path>{roots.workflows}/specdev/W-wayfinder/W-wayfinder.md</Path>`;
41
- - 需要可运行原型回答设计问题 → `<Path>{roots.workflows}/specdev/P-prototype/P-prototype.md</Path>`;
41
+ - 需要检测项目 UI、比较风格候选并固化可运行设计包 → `<Path>{roots.workflows}/specdev/P-prototype/P-prototype.md</Path>`;
42
42
  - 外部行为明确 → `<Path>{roots.workflows}/specdev/S-spec/S-spec.md</Path>`;
43
43
  - 固定点 diff 或 PR 审查 → `<Path>{roots.workflows}/specdev/C-code-review/C-code-review.md</Path>`;
44
44
  - 小型明确变更 → `<Path>{roots.workflows}/specdev/T-tickets/T-tickets.md</Path>` 或获批 Direct Spec。
@@ -34,7 +34,7 @@ Wayfinder 默认进行**规划**:每个 Ticket 解决一个决策,当地图
34
34
  - 地图:`<Path>{roots.state}/specdev/changes/{change}/wayfinder-map.md</Path>`
35
35
  - 子 Tickets:`<Path>{roots.state}/specdev/changes/{change}/investigation/</Path>`
36
36
  - solution comments:`<Path>{roots.state}/specdev/changes/{change}/investigation/comments/</Path>`
37
- - assignment registry:`<Path>{roots.state}/specdev/status.json</Path>` 的 `claimed_investigations`
37
+ - assignment registry:`<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 的 `claimed_investigations`
38
38
 
39
39
  每次绘制或遍历前加载 `<Path>{roots.workflows}/specdev/W-wayfinder/local-tracker-contract.md</Path>`。Ticket 和地图模板:
40
40
 
@@ -47,7 +47,7 @@ Wayfinder 默认进行**规划**:每个 Ticket 解决一个决策,当地图
47
47
  每个 Ticket 要么是 **HITL**,与一个代表自己发言的人类一起工作;要么是 **AFK**,由 Agent 独立驱动。HITL Ticket 只能通过实时交流解决,Agent 绝不代替人类一方发言。
48
48
 
49
49
  - **Research(AFK)**:阅读文档、第三方 API 或知识库等资源,揭示某个决策等待的事实。调用 `<Path>{roots.workflows}/specdev/common/skills/research/SKILL.md</Path>`。当需要当前工作目录之外的知识时使用。
50
- - **Prototype(HITL)**:调用 `<Path>{roots.workflows}/specdev/P-prototype/P-prototype.md</Path>` 回答一个 UI/逻辑问题,并把 record、临时 branch/worktree 和运行 URL 链接为 solution comment 资产;P 不实现目的地。
50
+ - **Prototype(HITL)**:调用 `<Path>{roots.workflows}/specdev/P-prototype/P-prototype.md</Path>` 检测项目 UI、比较功能风格候选并逐步确认设计方向,把 `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/design-system.md</Path>` comparison locator 链接为 solution comment 资产;`{design-id}` 使用 P 返回的 `UI-NNN`,P 不实现目的地。
51
51
  - **Grilling(HITL)**:对话。调用 `<Path>{roots.workflows}/specdev/G-grill-with-docs/G-grill-with-docs.md</Path>` 的 grilling 与 domain-modeling 能力,但本会话只关闭当前 Wayfinder Ticket。
52
52
  - **Task(HITL 或 AFK)**:在决策做出前必须完成的手动工作。它通过为决策解除阻塞赢得位置,不以交付目的地为目标。Agent 能独立驱动时使用 AFK,否则给人类精确清单。
53
53
 
@@ -8,7 +8,7 @@
8
8
  | 子 issue | `<Path>{roots.state}/specdev/changes/{change}/investigation/{investigation-id}.md</Path>` |
9
9
  | label | Ticket frontmatter 的 `wayfinder:research|prototype|grilling|task` |
10
10
  | 阻塞关系 | Ticket frontmatter 的 `blocked_by` |
11
- | assignment | `<Path>{roots.state}/specdev/status.json</Path>` 当前 change 的 `claimed_investigations` |
11
+ | assignment | `<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 的 `claimed_investigations` |
12
12
  | solution comment | `<Path>{roots.state}/specdev/changes/{change}/investigation/comments/{investigation-id}/NN-solution.md</Path>` |
13
13
  | 关闭 issue | Ticket frontmatter 的 `status: closed` 与 `resolution` |
14
14
 
@@ -24,13 +24,12 @@
24
24
 
25
25
  ## 原子领取
26
26
 
27
- 开始任何工作前,重读全局状态并原子写入 `id`、`owner`、可选 `session` 和 `claimed_at`。已领取则选择下一前沿 Ticket。写回结果前再次重读;完成、释放或取消时删除 claim。
27
+ 开始任何工作前,重读当前 change 状态并原子写入 `id`、`owner`、可选 `session` 和 `claimed_at`。已领取则选择下一前沿 Ticket。写回结果前再次重读;完成、释放或取消时删除 claim。
28
28
 
29
- Ticket 文件不重复保存 assignee,地图不重复保存 claim。全局 assignment registry 是领取的单一事实源。
29
+ Ticket 文件不重复保存 assignee,地图不重复保存 claim。change assignment registry 是领取的单一事实源。
30
30
 
31
31
  ## 解决方案评论
32
32
 
33
33
  Ticket 正文只保存问题。答案写入下一个未占用的 solution comment 文件,资产从评论链接,不粘贴进 Ticket。关闭 Ticket 后,地图的“已做出的决策”只追加名称链接和一句概括;`out-of-scope` 不进入决策索引。
34
34
 
35
35
  **完成标准**:地图、Ticket、claim、阻塞和 solution comment 可以重建相同前沿;同一事实没有第二份可写副本。
36
-
@@ -21,6 +21,7 @@
21
21
  - Change 完成:`<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>`
22
22
  - 代码注释:`<Path>{roots.workflows}/specdev/common/rules/code-commenting-rule.md</Path>`
23
23
  - 代码库设计:`<Path>{roots.workflows}/specdev/common/rules/codebase-design.md</Path>`
24
+ - 父实现编排:`<Path>{roots.workflows}/specdev/common/rules/parent-implementation-orchestration.md</Path>`
24
25
 
25
26
  ## 结构化工件 Schema
26
27
 
@@ -31,21 +32,23 @@
31
32
  - Ticket:`<Path>{roots.workflows}/specdev/common/schemas/ticket.schema.json</Path>`
32
33
  - Tickets Map:`<Path>{roots.workflows}/specdev/common/schemas/tickets-map.schema.json</Path>`
33
34
  - Goal Plan:`<Path>{roots.workflows}/specdev/common/schemas/goal-plan.schema.json</Path>`
35
+ - Implementation Map:`<Path>{roots.workflows}/specdev/common/schemas/implementation-map.schema.json</Path>`
36
+ - Implementation Plan:`<Path>{roots.workflows}/specdev/common/schemas/implementation-plan.schema.json</Path>`
34
37
  - 设计树:`<Path>{roots.workflows}/specdev/common/schemas/design-tree.schema.json</Path>`
35
38
  - Wayfinder Ticket:`<Path>{roots.workflows}/specdev/common/schemas/wayfinder-ticket.schema.json</Path>`
36
39
  - 来源快照:`<Path>{roots.workflows}/specdev/common/schemas/source.schema.json</Path>`
37
40
  - 分诊:`<Path>{roots.workflows}/specdev/common/schemas/triage.schema.json</Path>`
38
41
  - 诊断:`<Path>{roots.workflows}/specdev/common/schemas/diagnosis.schema.json</Path>`
39
42
  - 代码审查:`<Path>{roots.workflows}/specdev/common/schemas/code-review.schema.json</Path>`
40
- - 原型记录:`<Path>{roots.workflows}/specdev/common/schemas/prototype-record.schema.json</Path>`
43
+ - UI 设计包:`<Path>{roots.workflows}/specdev/P-prototype/design-package.schema.json</Path>`
41
44
 
42
45
  ## 工具与 Skill
43
46
 
44
47
  - 包与 change 校验器:`<Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path>`
45
48
  - 校验器说明:`<Path>{roots.workflows}/specdev/common/tools/README.md</Path>`
46
49
  - 外部技术研究 Skill:`<Path>{roots.workflows}/specdev/common/skills/research/SKILL.md</Path>`
47
- - Ticket/原型 worktree Skill:`<Path>{roots.workflows}/specdev/common/skills/dev-worktree/SKILL.md</Path>`;仅 required Ticket 使用 source → parent-candidate → parent 状态机,current Ticket 使用 current workspace/direct-parent,原型保持临时生命周期
48
- - 动态 Agent 交付合同 Skill:`<Path>{roots.workflows}/specdev/common/skills/subagent-delivery/SKILL.md</Path>`;P-goal-plan 建立 Lead 合同,I-implement 在执行期派单与验收
50
+ - Ticket worktree Skill:`<Path>{roots.workflows}/specdev/common/skills/dev-worktree/SKILL.md</Path>`;仅 required Ticket 使用 source → parent-candidate → parent 状态机,current Ticket 使用 current workspace/direct-parent
51
+ - 动态 Agent 交付合同 Skill:`<Path>{roots.workflows}/specdev/common/skills/subagent-delivery/SKILL.md</Path>`;P-goal-plan 可建立子 change Lead 合同,I-implement 在执行期派单与验收,父实现编排存在时受 O-orchestrate-implementation 的全局门约束
49
52
  - 双轴代码审查 Skill:`<Path>{roots.workflows}/specdev/common/skills/code-review/SKILL.md</Path>`
50
53
 
51
54
  ## 加载原则
@@ -17,15 +17,20 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
17
17
  | Ticket | `<Path>{roots.state}/specdev/changes/{change}/ticket/{ticket-file}.md</Path>` | 单一垂直切片的行为、决策、范围、路径所有权、执行路线和验证证据 | 跨 Ticket 里程碑治理 |
18
18
  | Tickets Map | `<Path>{roots.state}/specdev/changes/{change}/tickets-map.md</Path>` | 依赖 DAG、合同覆盖、Ready 投影、并行候选和路径冲突 | 单 Ticket 的完整实现契约 |
19
19
  | Goal Plan | `<Path>{roots.state}/specdev/changes/{change}/goal-plan.md</Path>` | 跨 Ticket 调度、Gate、共享所有权、迁移顺序、集成和偏差治理 | 复制 Ticket 全文 |
20
+ | Implementation Map | `<Path>{roots.state}/specdev/changes/{change}/implementation-map.md</Path>` | Ready 成员、组合 Ticket inventory、跨 change dependency/serialization 与 revision | 创建或改写子 Spec、Ticket 或实现细节 |
21
+ | Implementation Plan | `<Path>{roots.state}/specdev/changes/{change}/implementation-plan.md</Path>` | 父 Lead、全局 workspace/实现上限、frontier/Wave/locks/integration queue 和可恢复进度投影 | 改写子 change 权威或伪造完成 |
22
+ | Implementation Orchestration Evidence | `<Path>{roots.state}/specdev/changes/{change}/evidence/implementation-orchestration.md</Path>` | 成员完成、组合 Ticket 顺序/锁、repository integration、整体验证、漂移和残余风险 | 新产品/架构决定或单 Ticket Evidence 替代品 |
20
23
  | Evidence | `<Path>{roots.state}/specdev/changes/{change}/evidence/{ticket-id}.md</Path>` | 实际修改、命令、结果、验收映射、偏差、风险和提交引用 | 新的产品或架构决策 |
21
24
  | 代码审查 | `<Path>{roots.state}/specdev/changes/{change}/reviews/CR-###.md</Path>` | 固定点、标准轴和规范轴 finding | 实施修复或合并两轴排名 |
22
- | 原型记录 | `<Path>{roots.state}/specdev/changes/{change}/prototypes/{prototype-id}/record.md</Path>` | 一个问题、分支、资产、答案、promotion 和清理 | 生产实现或多个问题的计划 |
25
+ | UI 设计包 | `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/design-system.md</Path>`、`<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/comparison/</Path>` 与 `<Path>{roots.state}/specdev/changes/{change}/prototypes/{design-id}/final/</Path>` | 项目 UI 证据、功能风格候选、逐层用户决定、设计 token、交互合同和可运行 HTML/CSS/JS 投影 | 生产 UI 实现或替用户确认高影响偏好 |
23
26
  | Stakeholder 问卷 | `<Path>{roots.state}/specdev/changes/{change}/questionnaires/{slug}.md</Path>` | 第三方原始回答和恢复条件 | 未经转录确认的产品/架构决定 |
24
27
  | Wayfinder 地图 | `<Path>{roots.state}/specdev/changes/{change}/wayfinder-map.md</Path>` | 目的地、说明、已关闭决策索引、战争迷雾和范围之外 | 开放 Ticket 正文或答案详情 |
25
28
  | Wayfinder Ticket | `<Path>{roots.state}/specdev/changes/{change}/investigation/{investigation-id}.md</Path>` | 一个可精确陈述的问题、类型、阻塞和关闭状态 | 解决方案评论或交付目标 |
26
29
  | Wayfinder solution comment | `<Path>{roots.state}/specdev/changes/{change}/investigation/comments/{investigation-id}/NN-solution.md</Path>` | Ticket 的答案、结果事实和资产指针 | 地图索引或产品实现 |
27
30
  | 架构审查 | `<Path>{roots.state}/specdev/changes/{change}/architecture-review.md</Path>` 与 `<Path>{roots.state}/specdev/changes/{change}/architecture-review.html</Path>` | 深化候选、证据、可视化、选择和访谈状态 | 未经用户选择的执行契约 |
28
31
 
32
+ UI 设计包中的 `{design-id}` 由 P-prototype 分配为当前 change 内最小未占用的 `UI-NNN`;设计系统文档是唯一设计权威,comparison 与 final 不建立第二套规则。
33
+
29
34
  Change CONTEXT/ADR 是 active change 内的执行权威,不是 workflow 级永久知识。G 和其他设计/执行 Works 只读 `<Path>{roots.state}/specdev/context/</Path>` 与 `<Path>{roots.state}/specdev/adr/</Path>`;只有 A 在 change 完成、实现证据验证、毕业评估和用户确认后才能写入永久 namespace。未毕业内容随归档 change 保留,不能从 change 工件消失。
30
35
 
31
36
  ## 2. 权威顺序
@@ -38,8 +43,9 @@ Change CONTEXT/ADR 是 active change 内的执行权威,不是 workflow 级永
38
43
  4. 当前外部行为权威:`<Path>{roots.state}/specdev/changes/{change}/spec.md</Path>`;
39
44
  5. 当前 Ticket 契约:`<Path>{roots.state}/specdev/changes/{change}/ticket/{ticket-file}.md</Path>`;
40
45
  6. 当前跨 Ticket 编排:`<Path>{roots.state}/specdev/changes/{change}/goal-plan.md</Path>`;
41
- 7. 当前代码与运行事实;
42
- 8. 旧计划、旧日志和未经确认的推断。
46
+ 7. 若当前 change 属于父实现 change,父 Implementation Map 对组合 Ticket dependency/serialization 具有权威,父 Implementation Plan 拥有全局 workspace、frontier 与 integration queue;
47
+ 8. 当前代码与运行事实;
48
+ 9. 旧计划、旧日志和未经确认的推断。
43
49
 
44
50
  当前 change 决定与永久知识冲突时,必须在 LOG/ADR 中显式说明替代关系;它只约束当前 change,直到 A 决定是否提升并更新永久版本。
45
51
 
@@ -16,11 +16,14 @@
16
16
 
17
17
  Evidence-only Done 和 empty commit 不满足完成门。
18
18
 
19
+ 父实现 change 还必须满足 `<Path>{roots.workflows}/specdev/common/rules/parent-implementation-orchestration.md</Path>`:全部成员 completed,Implementation Map 与 Implementation Plan completed 且 revision 一致,跨 change 全套验证通过,`<Path>{roots.state}/specdev/changes/{change}/evidence/implementation-orchestration.md</Path>` 完整,没有活动派单、candidate、serialization lock 或未裁决冲突。父完成不自动归档或移动任何成员。
20
+
19
21
  ## 转换 Owner
20
22
 
21
23
  - 有 Goal Plan:其唯一 Lead 在关闭最后 Gate 后拥有转换;
22
24
  - 无 Goal Plan 的 Ticket/Direct Spec:当前 I-implement 主会话 owner 拥有转换;
23
25
  - 非实现型终点:最终验收工件 owner 使用本规则。
26
+ - 父实现 change:Implementation Plan 的唯一 Lead 在全部成员与 aggregate gate 关闭后拥有转换。
24
27
 
25
28
  Owner 原子更新 `<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>` 的 `change_status`、`completed_at`、`updated_at` 和 `current_work`,然后重读。全局 status 只维护 active/archived 索引。
26
29
 
@@ -21,6 +21,7 @@
21
21
  - 发现新的安全、数据、兼容、性能或迁移风险;
22
22
  - 依赖、合同或外部参考权威已变化;
23
23
  - 实际行为将与 Spec 或 ADR 不一致。
24
+ - 父 Implementation Map 的成员、组合 Ticket、dependency、serialization 或 revision 已与子状态、路径或 Git 事实不一致。
24
25
 
25
26
  ## 3. 偏差记录
26
27
 
@@ -41,3 +42,4 @@
41
42
  - 未批准的 ticket、spec、architecture 或 release 偏差不得继续实现。
42
43
  - 不得通过扩大 `writable_paths`、删除测试、降低断言或把风险改写成“已知限制”来绕过停止。
43
44
  - 偏差影响并行执行、source checkpoint 或 candidate 集成时,Lead 必须暂停受影响 Wave,重新计算路径所有权、依赖、Gate 与父分支顺序;任何 subagent 都不能自行改写上层合同。
45
+ - 偏差跨越多个成员时,父 Lead 先递增 Implementation Map revision,再重算 Implementation Plan;旧派单和 candidate 全部标记 stale。
@@ -49,3 +49,5 @@ subagent 只返回候选命令与结果,不写 Evidence。Lead 重读 workspac
49
49
  required Ticket Done 必须有 source commit、通过 candidate、父分支 result 与 Lead Evidence;current Ticket Done 必须有 implementation commit、通过 direct-parent 验证、父分支 result 与 Lead Evidence。无法运行 required 验证、存在未批准偏差、父分支未包含 Ticket commit 或 Evidence 不完整时不得 Done。
50
50
 
51
51
  Direct Spec Evidence 至少包含:用户批准与轻量合同、Lead、实施前/最终 checkpoint、实际路径、定向/回归/E2E 命令及环境、验收映射、未运行项、偏差、残余风险和提交授权状态。
52
+
53
+ 父实现 change 的 Implementation Orchestration Evidence 不能替代子 Evidence。它至少记录最终 Map revision、全部成员最终状态和子证据指针、dependency/serialization 实际顺序、跨 change 合同检查、aggregate 命令/环境/结果、stale candidate 处理、偏差和残余风险。任何成员未 completed 或整体验证未通过时不得形成父完成证据。
@@ -0,0 +1,27 @@
1
+ # Parent Implementation Orchestration
2
+
3
+ 本规则只约束 Ready Spec/Tickets 之后的跨 change 实现,供 O-orchestrate-implementation、I-implement 与 A-archive-and-consolidate 读取。
4
+
5
+ ## 输入边界
6
+
7
+ 父实现 change 只能在所有成员通过 Ready Spec/Tickets 输入门后创建。父 Work 不调用或代行 Triage、Grill、Wayfinder、Spec、Tickets 或普通 Goal Plan;输入不足时不留下父状态或父工件。
8
+
9
+ ## 权威边界
10
+
11
+ - 父 Implementation Map:成员、组合 Ticket inventory、跨 change dependency/serialization 与 revision 的唯一权威投影。
12
+ - 父 Implementation Plan:Lead、全局 workspace 策略、implementation agent/integration attempt 上限、frontier、Wave、locks 和 integration queue 的唯一权威。
13
+ - 子 change:自己的 Spec、Ticket、内部 Goal Gate、workspace、Git、Evidence 和完成状态的唯一权威。
14
+
15
+ 父工件不得复制完整子合同。子权威变化时停止旧派单、递增父 Map revision 并重算父 Plan;不能从旧父投影覆盖子工件。
16
+
17
+ ## 唯一所有权
18
+
19
+ 一个 active/blocked 子 change 最多属于一个未完成父实现 change。v1 不支持父实现 change 嵌套。父 Lead 是父工件、全部 SpecDev 状态写入、E2E、repository/ref integration queue 和父分支推进的唯一 owner;implementation agent 只写授权项目 workspace。
20
+
21
+ ## I-implement 调用
22
+
23
+ 父 Plan 可以替代缺失的子 Goal Plan 提供 workspace/integration 策略和全局执行边界。子 Goal Plan 存在时继续拥有子 change 内 Gate,但不得与父策略冲突。I-implement 完成或阻塞一个组合 Ticket 后返回父 O Work,不要求用户重新激活 change。
24
+
25
+ ## 归档与完成
26
+
27
+ 未完成父实现 change 的成员不得归档。成员满足普通 change completion 时可以先 completed,但不自动归档。父 change 只有全部成员 completed、Map/Plan completed、aggregate Evidence 完整且无 active dispatch/candidate/lock 后才能 completed;完成或归档均不自动级联。