create-yss-spec 3.5.8 → 3.5.9
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.
- package/cli-core.lock.json +1 -1
- package/package.json +1 -1
- package/src/commands/doctor.js +40 -0
- package/src/commands/skills.js +7 -2
- package/src/template/asset-runtime.js +120 -21
- package/template/.agents/skills/.strategic-design-skills-manifest.json +3 -3
- package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +20 -16
- package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -1
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +43 -0
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +3 -1
- package/template/.agents/skills/yss-product-lifecycle/references/plan-requirements.md +7 -6
- package/template/.agents/skills/yss-prototype-stage/scripts/verify-prototype-design.mjs +1 -0
- package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -5
- package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -5
- package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +83 -13
- package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +20 -16
- package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -1
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +43 -0
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +3 -1
- package/template/.codex/skills/yss-product-lifecycle/references/plan-requirements.md +7 -6
- package/template/.codex/skills/yss-prototype-stage/scripts/verify-prototype-design.mjs +1 -0
- package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -5
- package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -5
- package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +83 -13
- package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +20 -16
- package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +43 -0
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +3 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/plan-requirements.md +7 -6
- package/template/.cursor/skills/yss-prototype-stage/scripts/verify-prototype-design.mjs +1 -0
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -5
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -5
- package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +83 -13
- package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +20 -16
- package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -1
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +43 -0
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +3 -1
- package/template/.pi/skills/yss-product-lifecycle/references/plan-requirements.md +7 -6
- package/template/.pi/skills/yss-prototype-stage/scripts/verify-prototype-design.mjs +1 -0
- package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -5
- package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -5
- package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +83 -13
- package/template/.template-spec/plan/entry-review.md +2 -1
- package/template/.template-spec/plan/templates/plan-template.md +11 -5
- package/template/.template-spec/process/script-execution.md +37 -0
- package/template/.template-spec/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +2 -0
- package/template/skills-lock.json +11 -11
- package/template.snapshot.json +4 -4
package/cli-core.lock.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"sourceRepository": "https://github.com/iloveZzz/yss-spec-project-template.git",
|
|
4
|
-
"sourceRevision": "
|
|
4
|
+
"sourceRevision": "e2c16b4e8de991f8942bc6cfa43e784ae0e106ca",
|
|
5
5
|
"sourceState": "committed",
|
|
6
6
|
"sourcePath": ".template-source/cli-core",
|
|
7
7
|
"coreVersion": "0.2.0",
|
package/package.json
CHANGED
package/src/commands/doctor.js
CHANGED
|
@@ -15,7 +15,9 @@ const {
|
|
|
15
15
|
readTemplateSnapshot,
|
|
16
16
|
readTargetIdentity,
|
|
17
17
|
loadTemplateMetadata,
|
|
18
|
+
BUNDLED_TEMPLATE_ROOT,
|
|
18
19
|
} = require("../template/instance-runtime");
|
|
20
|
+
const { assetRequirements } = require("../template/asset-runtime");
|
|
19
21
|
const {
|
|
20
22
|
ownershipPolicyDrift,
|
|
21
23
|
} = require("../template/ownership-metadata");
|
|
@@ -268,6 +270,29 @@ function runVerifierCheck(report, targetDir, verifier, gitWorktree) {
|
|
|
268
270
|
);
|
|
269
271
|
}
|
|
270
272
|
|
|
273
|
+
function checkRuntimeDependencies(report, requirements, targetDir) {
|
|
274
|
+
if (!requirements.selective) {
|
|
275
|
+
addCheck(report, "runtime-dependencies", "warning", "旧实例保持原分发范围;解释器依赖继续由实例校验器核验", { code: "LEGACY_DISTRIBUTION" });
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
for (const dependency of requirements.runtimeDependencies) {
|
|
279
|
+
const command = dependency.executable === "node" ? process.execPath : dependency.executable;
|
|
280
|
+
const probe = dependency.executable === "python3"
|
|
281
|
+
? ["-c", `${dependency.packages.length ? `import ${dependency.packages.join(", ")}; ` : ""}import sys; print(sys.version.split()[0])`]
|
|
282
|
+
: ["--version"];
|
|
283
|
+
const result = spawnSync(command, probe, { cwd: targetDir, encoding: "utf8", timeout: 5000, env: { ...process.env, PYTHONDONTWRITEBYTECODE: "1" } });
|
|
284
|
+
const data = { ...dependency, exitCode: result.status, code: result.error?.code === "ENOENT" ? "RUNTIME_UNAVAILABLE" : result.status !== 0 || result.error ? "RUNTIME_DEPENDENCY_FAILED" : "RUNTIME_READY" };
|
|
285
|
+
const packages = dependency.packages.length ? `;所需包 ${dependency.packages.join(", ")}` : "";
|
|
286
|
+
if (result.error || result.status !== 0) {
|
|
287
|
+
data.error = result.error?.message || (result.stderr || result.stdout || "").trim();
|
|
288
|
+
addCheck(report, `runtime-${dependency.executable}`, "error", `无法使用 ${dependency.executable}${packages};核对解释器 PATH 和依赖后重验`, data);
|
|
289
|
+
} else {
|
|
290
|
+
data.version = result.stdout.trim();
|
|
291
|
+
addCheck(report, `runtime-${dependency.executable}`, "ok", `${dependency.executable} 可用${packages}`, data);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
271
296
|
function buildDoctorReport(targetDir) {
|
|
272
297
|
const report = {
|
|
273
298
|
schemaVersion: DOCTOR_SCHEMA_VERSION,
|
|
@@ -340,6 +365,20 @@ function buildDoctorReport(targetDir) {
|
|
|
340
365
|
checkOwnershipPolicy(report, metadata);
|
|
341
366
|
checkLifecyclePolicies(report, metadata);
|
|
342
367
|
checkManagedBaseline(report, targetDir, metadata);
|
|
368
|
+
if (snapshot && metadata.templateCommit === snapshot.templateCommit && metadata.snapshotHash === snapshot.snapshotHash) {
|
|
369
|
+
try {
|
|
370
|
+
const requirements = assetRequirements(BUNDLED_TEMPLATE_ROOT, metadata.distribution || { mode: "legacy-all" });
|
|
371
|
+
const missingPaths = Object.keys(requirements.inclusionReasons).filter(ref => pathKind(targetPath(targetDir, ref)) !== "file");
|
|
372
|
+
addCheck(report, "asset-dependencies", missingPaths.length ? "error" : "ok", missingPaths.length
|
|
373
|
+
? `当前阶段缺少 ${missingPaths.length} 项执行依赖;先运行 create-yss-spec sync --plan 核对补齐范围`
|
|
374
|
+
: requirements.selective ? "当前阶段资产依赖来源已解析" : "旧实例继续保持原分发范围", { ...requirements, missingPaths });
|
|
375
|
+
checkRuntimeDependencies(report, requirements, targetDir);
|
|
376
|
+
} catch (error) {
|
|
377
|
+
addCheck(report, "asset-dependencies", "error", error.message);
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
addCheck(report, "asset-dependencies", "warning", "CLI 与实例快照不一致,先核对匹配版本再解析阶段依赖", { code: "SNAPSHOT_MISMATCH" });
|
|
381
|
+
}
|
|
343
382
|
} catch (error) {
|
|
344
383
|
addCheck(report, "template-metadata", "error", error.message);
|
|
345
384
|
}
|
|
@@ -414,6 +453,7 @@ module.exports = {
|
|
|
414
453
|
checkOwnershipPolicy,
|
|
415
454
|
checkLifecyclePolicies,
|
|
416
455
|
runVerifierCheck,
|
|
456
|
+
checkRuntimeDependencies,
|
|
417
457
|
buildDoctorReport,
|
|
418
458
|
renderDoctorText,
|
|
419
459
|
runDoctor,
|
package/src/commands/skills.js
CHANGED
|
@@ -9,7 +9,7 @@ const { assertTargetFamily } = require("../family-runtime");
|
|
|
9
9
|
const { assertTargetWorkingTreeWritable } = require("../validation/security");
|
|
10
10
|
const { readTemplateSnapshot, loadTemplateMetadata, writeTemplateMetadata, buildDesiredManagedOperations, BUNDLED_TEMPLATE_ROOT, fileHash } = require("../template/instance-runtime");
|
|
11
11
|
const { RUNTIMES, assertRuntime, readDistributionRegistry, requiredSkills, renderInstanceDesignSkillFile } = require("../template/distribution-runtime");
|
|
12
|
-
const { ASSET_PROFILE, STAGES } = require("../template/asset-runtime");
|
|
12
|
+
const { ASSET_PROFILE, STAGES, assetRequirements } = require("../template/asset-runtime");
|
|
13
13
|
const { refreshGeneratedProjectInstance, verifyGeneratedProjectInstance } = require("../template/verification-runtime");
|
|
14
14
|
|
|
15
15
|
function parseSkillArgs(argv) {
|
|
@@ -109,8 +109,13 @@ function runAssetSelection({ targetDir, requestedSkills = [], triggers = [], sta
|
|
|
109
109
|
if (pathKind(targetPath(targetDir, relative)) !== "missing") throw new Error(`目标阶段资产路径已存在,拒绝覆盖:${relative}`);
|
|
110
110
|
}
|
|
111
111
|
if (plan) {
|
|
112
|
+
const requirements = assetRequirements(BUNDLED_TEMPLATE_ROOT, nextDistribution);
|
|
113
|
+
const inclusionReasons = Object.fromEntries(paths.map(ref => {
|
|
114
|
+
const skill = ref.match(/^\.(?:agents|codex|cursor|pi)\/skills\/([^/]+)\//)?.[1];
|
|
115
|
+
return [ref, requirements.inclusionReasons[ref] || (skill ? [{ kind: "selected-skill", skill }] : [{ kind: "selected-asset" }])];
|
|
116
|
+
}));
|
|
112
117
|
console.log(JSON.stringify({ operation: stage ? "assets ensure" : "skills ensure", targetDir, requested: stage || requestedSkills,
|
|
113
|
-
dependencies: names, addSkills: missingSkills, addStage, paths }, null, 2));
|
|
118
|
+
dependencies: names, addSkills: missingSkills, addStage, paths, inclusionReasons, runtimeDependencies: requirements.runtimeDependencies }, null, 2));
|
|
114
119
|
return;
|
|
115
120
|
}
|
|
116
121
|
if (!addStage && !missingSkills.length && !paths.length) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require("node:fs");
|
|
4
4
|
const path = require("node:path");
|
|
5
|
+
const { pathToFileURL } = require("node:url");
|
|
5
6
|
|
|
6
7
|
const ASSET_PROFILE = "stage-selective";
|
|
7
8
|
const INITIAL_STAGES = ["stage.entry-triage", "stage.plan"];
|
|
@@ -24,6 +25,7 @@ const COMMON = {
|
|
|
24
25
|
".template-spec/process/lifecycle-registry-baseline-v1.json",
|
|
25
26
|
".template-spec/process/lifecycle-artifact-map.md",
|
|
26
27
|
".template-spec/process/harness-process-tailoring.md",
|
|
28
|
+
".template-spec/process/script-execution.md",
|
|
27
29
|
".template-spec/process/document-writing.md",
|
|
28
30
|
".template-spec/process/contract-reading.md",
|
|
29
31
|
".template-spec/process/structured-assets.md",
|
|
@@ -149,31 +151,94 @@ const STAGES = Object.freeze({
|
|
|
149
151
|
},
|
|
150
152
|
});
|
|
151
153
|
|
|
154
|
+
function assertContained(root, ref) {
|
|
155
|
+
if (path.posix.isAbsolute(ref) || ref.includes("\\") || ref.split("/").includes("..")) throw new Error(`阶段资产路径越界:${ref}`);
|
|
156
|
+
const file = path.join(root, ref);
|
|
157
|
+
const relative = path.relative(fs.realpathSync(root), fs.realpathSync(file));
|
|
158
|
+
if (relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) throw new Error(`阶段资产路径越界:${ref}`);
|
|
159
|
+
return file;
|
|
160
|
+
}
|
|
161
|
+
|
|
152
162
|
function sourceFile(root, ref) {
|
|
153
163
|
const file = path.join(root, ref);
|
|
154
164
|
if (!fs.existsSync(file) || !fs.statSync(file).isFile()) throw new Error(`CLI 快照缺少阶段资产:${ref}`);
|
|
155
|
-
return
|
|
165
|
+
return assertContained(root, ref);
|
|
156
166
|
}
|
|
157
167
|
|
|
158
|
-
function
|
|
159
|
-
|
|
160
|
-
|
|
168
|
+
function recordReason(result, ref, reason) {
|
|
169
|
+
const reasons = result.inclusionReasons.get(ref) || [];
|
|
170
|
+
if (!reasons.some(item => JSON.stringify(item) === JSON.stringify(reason))) reasons.push(reason);
|
|
171
|
+
result.inclusionReasons.set(ref, reasons);
|
|
161
172
|
}
|
|
162
173
|
|
|
163
|
-
function
|
|
174
|
+
function addFile(root, result, ref, reason, uri) {
|
|
175
|
+
recordReason(result, ref, reason);
|
|
176
|
+
if (!result.has(ref)) {
|
|
177
|
+
sourceFile(root, ref);
|
|
178
|
+
result.add(ref);
|
|
179
|
+
} else if (!ref.endsWith(".schema.json")) return;
|
|
180
|
+
if (ref.endsWith(".schema.json")) {
|
|
181
|
+
const visited = result.schemaFiles.has(ref);
|
|
182
|
+
const text = result.schemaFiles.get(ref) || fs.readFileSync(path.join(root, ref), "utf8"), schema = JSON.parse(text);
|
|
183
|
+
const fileURI = pathToFileURL(path.join(root, ref)).href;
|
|
184
|
+
for (const id of [uri, fileURI, schema.$id].filter(Boolean)) {
|
|
185
|
+
if (result.schemaResources.has(id) && result.schemaResources.get(id) !== text) throw new Error(`阶段 Schema ID 冲突:${id}`);
|
|
186
|
+
result.schemaResources.set(id, text);
|
|
187
|
+
}
|
|
188
|
+
if (visited) return;
|
|
189
|
+
result.schemaFiles.set(ref, text);
|
|
190
|
+
const base = schema.$id || uri || fileURI;
|
|
191
|
+
function visit(value) {
|
|
192
|
+
if (!value || typeof value !== "object") return;
|
|
193
|
+
for (const [key, dependency] of Object.entries(value)) {
|
|
194
|
+
if (["$ref", "$dynamicRef"].includes(key) && typeof dependency === "string" && !dependency.startsWith("#")) {
|
|
195
|
+
const file = dependency.split("#")[0];
|
|
196
|
+
const resolvedURI = new URL(file, base).href;
|
|
197
|
+
if (result.schemaResources.has(resolvedURI)) continue;
|
|
198
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(file) || path.posix.isAbsolute(file) || file.includes("\\")) throw new Error(`阶段 Schema 依赖必须为本地相对路径:${ref} -> ${dependency}`);
|
|
199
|
+
const resolved = path.posix.normalize(path.posix.join(path.posix.dirname(ref), file));
|
|
200
|
+
if (!resolved.startsWith(".template-spec/") && !resolved.startsWith("scripts/")) throw new Error(`阶段 Schema 依赖路径越界:${ref} -> ${dependency}`);
|
|
201
|
+
addFile(root, result, resolved, { kind: "schema-ref", from: ref, reference: dependency }, resolvedURI);
|
|
202
|
+
} else visit(dependency);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
visit(schema);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function addPrefix(root, result, prefix, reason, ancestors = []) {
|
|
164
210
|
const directory = path.join(root, prefix);
|
|
165
211
|
if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) throw new Error(`CLI 快照缺少阶段目录:${prefix}`);
|
|
212
|
+
assertContained(root, prefix);
|
|
213
|
+
const physical = fs.realpathSync(directory);
|
|
214
|
+
if (ancestors.includes(physical)) throw new Error(`阶段资产目录链接循环:${prefix}`);
|
|
215
|
+
const nextAncestors = [...ancestors, physical];
|
|
166
216
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
167
217
|
const ref = `${prefix}${entry.name}`;
|
|
168
|
-
|
|
169
|
-
|
|
218
|
+
const stat = entry.isSymbolicLink() ? fs.statSync(path.join(root, ref)) : entry;
|
|
219
|
+
if (stat.isDirectory()) addPrefix(root, result, `${ref}/`, reason, nextAncestors);
|
|
220
|
+
else if (stat.isFile()) addFile(root, result, ref, reason);
|
|
170
221
|
}
|
|
171
222
|
}
|
|
172
223
|
|
|
173
|
-
function moduleClosure(root, result, ref, selectedSkills) {
|
|
174
|
-
|
|
224
|
+
function moduleClosure(root, result, ref, selectedSkills, reason) {
|
|
225
|
+
addFile(root, result, ref, reason);
|
|
226
|
+
if (result.modules.has(ref)) return;
|
|
227
|
+
result.modules.add(ref);
|
|
175
228
|
const source = fs.readFileSync(sourceFile(root, ref), "utf8");
|
|
176
|
-
|
|
229
|
+
for (const match of source.matchAll(/\b(?:spawnSync|spawn|execFileSync|execFile)\(\s*['"](python3|node)['"]\s*,/g)) {
|
|
230
|
+
const dependency = result.runtimeDependencies.get(match[1]) || { executable: match[1], requiredBy: new Set(), packages: new Set() };
|
|
231
|
+
dependency.requiredBy.add(ref);
|
|
232
|
+
if (match[1] === "python3") {
|
|
233
|
+
for (const pkg of ["jsonschema", "referencing"]) if (new RegExp(`^from ${pkg}(?:\\.|\\s)`, "m").test(source)) dependency.packages.add(pkg);
|
|
234
|
+
}
|
|
235
|
+
result.runtimeDependencies.set(match[1], dependency);
|
|
236
|
+
}
|
|
237
|
+
if (/\b(?:spawnSync|spawn|execFileSync|execFile)\(\s*process\.execPath\s*,/.test(source)) {
|
|
238
|
+
const dependency = result.runtimeDependencies.get("node") || { executable: "node", requiredBy: new Set(), packages: new Set() };
|
|
239
|
+
dependency.requiredBy.add(ref);
|
|
240
|
+
result.runtimeDependencies.set("node", dependency);
|
|
241
|
+
}
|
|
177
242
|
const expressions = [
|
|
178
243
|
/\b(?:import|export)\s+(?:[^'"\n]*?\s+from\s*)?['"]([^'"]+)['"]/g,
|
|
179
244
|
/\b(?:require|import)\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
@@ -194,9 +259,27 @@ function moduleClosure(root, result, ref, selectedSkills) {
|
|
|
194
259
|
continue;
|
|
195
260
|
}
|
|
196
261
|
if (!candidate || !candidate.startsWith("scripts/")) throw new Error(`阶段脚本依赖未分发:${ref} -> ${match[1]}`);
|
|
197
|
-
moduleClosure(root, result, candidate, selectedSkills);
|
|
262
|
+
moduleClosure(root, result, candidate, selectedSkills, { kind: "module-import", from: ref, reference: match[1] });
|
|
198
263
|
}
|
|
199
264
|
}
|
|
265
|
+
// File names passed to a subprocess or Schema loader are runtime resources,
|
|
266
|
+
// not JavaScript imports. Include only complete, fixed local file references.
|
|
267
|
+
for (const match of source.matchAll(/['"]((?:scripts\/[\p{L}\p{N}_.\/-]+\.py|\.template-spec\/[\p{L}\p{N}_.\/-]+\.(?:json|yaml)))['"]/gu)) {
|
|
268
|
+
if (!fs.existsSync(path.join(root, match[1])) && !/\.(?:py|schema\.json)$/.test(match[1])) continue;
|
|
269
|
+
addFile(root, result, match[1], { kind: "runtime-resource", from: ref });
|
|
270
|
+
}
|
|
271
|
+
for (const match of source.matchAll(/\bnew\s+URL\(\s*['"](\.[^'"]+\.(?:json|yaml|py))['"]\s*,\s*import\.meta\.url\s*\)/g)) {
|
|
272
|
+
const resolved = path.posix.normalize(path.posix.join(path.posix.dirname(ref), match[1]));
|
|
273
|
+
if (!resolved.startsWith("scripts/") && !resolved.startsWith(".template-spec/")) throw new Error(`阶段资源依赖路径越界:${ref} -> ${match[1]}`);
|
|
274
|
+
addFile(root, result, resolved, { kind: "runtime-resource", from: ref, reference: match[1] });
|
|
275
|
+
}
|
|
276
|
+
// Caller-supplied roots can address another registered project. Only the
|
|
277
|
+
// module's fixed template root proves a dependency in this distribution.
|
|
278
|
+
for (const match of source.matchAll(/\b(?:spawnSync|spawn|execFileSync|execFile)\(\s*(?:(?:process\.execPath|['"](?:node|python3)['"])\s*,\s*\[\s*)?(?:path\.)?(?:join|resolve)\(\s*(?:ROOT|TEMPLATE_ROOT)\s*,\s*['"](scripts\/[\p{L}\p{N}_.\/-]+)['"]\s*\)/gu)) {
|
|
279
|
+
const reason = { kind: "subprocess-entry", from: ref };
|
|
280
|
+
if (/\.(?:py|json|yaml)$/.test(match[1])) addFile(root, result, match[1], reason);
|
|
281
|
+
else moduleClosure(root, result, match[1], selectedSkills, reason);
|
|
282
|
+
}
|
|
200
283
|
}
|
|
201
284
|
|
|
202
285
|
function skillReferences(root, result, skillId, selectedSkills) {
|
|
@@ -211,15 +294,16 @@ function skillReferences(root, result, skillId, selectedSkills) {
|
|
|
211
294
|
for (const match of source.matchAll(/(?:\.template-spec|scripts)\/[\p{L}\p{N}_.\/-]+/gu)) {
|
|
212
295
|
const ref = match[0].replace(/[.,;]+$/, "");
|
|
213
296
|
if (!fs.existsSync(path.join(root, ref)) || !fs.statSync(path.join(root, ref)).isFile()) continue;
|
|
214
|
-
|
|
215
|
-
|
|
297
|
+
const reason = { kind: "skill-reference", skill: skillId, from: path.relative(root, file).split(path.sep).join("/") };
|
|
298
|
+
if (ref.startsWith("scripts/")) moduleClosure(root, result, ref, selectedSkills, reason);
|
|
299
|
+
else addFile(root, result, ref, reason);
|
|
216
300
|
}
|
|
217
301
|
}
|
|
218
302
|
}
|
|
219
303
|
}
|
|
220
304
|
visit(skillRoot);
|
|
221
|
-
for (const prefix of SKILL_ASSET_PREFIXES[skillId] || []) addPrefix(root, result, prefix);
|
|
222
|
-
for (const ref of RENDERED_SKILL_SCRIPTS[skillId] || []) moduleClosure(root, result, ref, selectedSkills);
|
|
305
|
+
for (const prefix of SKILL_ASSET_PREFIXES[skillId] || []) addPrefix(root, result, prefix, { kind: "skill-resource", skill: skillId, prefix });
|
|
306
|
+
for (const ref of RENDERED_SKILL_SCRIPTS[skillId] || []) moduleClosure(root, result, ref, selectedSkills, { kind: "skill-resource", skill: skillId });
|
|
223
307
|
}
|
|
224
308
|
|
|
225
309
|
function assetPaths(root, distribution) {
|
|
@@ -230,6 +314,11 @@ function assetPaths(root, distribution) {
|
|
|
230
314
|
throw new Error("CLI 阶段资产映射与生命周期注册表阶段 ID 不一致");
|
|
231
315
|
}
|
|
232
316
|
const result = new Set();
|
|
317
|
+
result.inclusionReasons = new Map();
|
|
318
|
+
result.runtimeDependencies = new Map();
|
|
319
|
+
result.modules = new Set();
|
|
320
|
+
result.schemaFiles = new Map();
|
|
321
|
+
result.schemaResources = new Map();
|
|
233
322
|
const selectedSkills = new Set(distribution.installedSkills);
|
|
234
323
|
for (const ref of COMMON.files) {
|
|
235
324
|
if (ref === ".template-spec/process/lifecycle-registry-baseline-v1.json" &&
|
|
@@ -237,15 +326,15 @@ function assetPaths(root, distribution) {
|
|
|
237
326
|
const baseline = JSON.parse(fs.readFileSync(sourceFile(root, ".template-spec/process/lifecycle-registry-baseline.json"), "utf8"));
|
|
238
327
|
if (baseline.schema_version === 1) continue;
|
|
239
328
|
}
|
|
240
|
-
addFile(root, result, ref);
|
|
329
|
+
addFile(root, result, ref, { kind: "common-asset" });
|
|
241
330
|
}
|
|
242
|
-
for (const ref of COMMON.scripts) moduleClosure(root, result, ref, selectedSkills);
|
|
331
|
+
for (const ref of COMMON.scripts) moduleClosure(root, result, ref, selectedSkills, { kind: "common-entry" });
|
|
243
332
|
for (const stage of distribution.installedStages) {
|
|
244
333
|
const bundle = STAGES[stage];
|
|
245
334
|
if (!bundle) throw new Error(`未知生命周期阶段:${stage}`);
|
|
246
|
-
for (const prefix of bundle.prefixes || []) addPrefix(root, result, prefix);
|
|
247
|
-
for (const ref of bundle.files || []) addFile(root, result, ref);
|
|
248
|
-
for (const ref of bundle.scripts || []) moduleClosure(root, result, ref, selectedSkills);
|
|
335
|
+
for (const prefix of bundle.prefixes || []) addPrefix(root, result, prefix, { kind: "stage-asset", stage, prefix });
|
|
336
|
+
for (const ref of bundle.files || []) addFile(root, result, ref, { kind: "stage-asset", stage });
|
|
337
|
+
for (const ref of bundle.scripts || []) moduleClosure(root, result, ref, selectedSkills, { kind: "stage-entry", stage });
|
|
249
338
|
}
|
|
250
339
|
const resourceSkills = new Set(distribution.resourceSkills || []);
|
|
251
340
|
if (selectedSkills.has("yss-harness-upgrade")) resourceSkills.add("yss-harness-upgrade");
|
|
@@ -253,4 +342,14 @@ function assetPaths(root, distribution) {
|
|
|
253
342
|
return result;
|
|
254
343
|
}
|
|
255
344
|
|
|
256
|
-
|
|
345
|
+
function assetRequirements(root, distribution) {
|
|
346
|
+
const files = assetPaths(root, distribution);
|
|
347
|
+
if (!files) return { selective: false, inclusionReasons: {}, runtimeDependencies: [] };
|
|
348
|
+
return {
|
|
349
|
+
selective: true,
|
|
350
|
+
inclusionReasons: Object.fromEntries([...files.inclusionReasons].sort(([a], [b]) => a.localeCompare(b)).map(([ref, reasons]) => [ref, reasons.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)))])),
|
|
351
|
+
runtimeDependencies: [...files.runtimeDependencies.values()].sort((a, b) => a.executable.localeCompare(b.executable)).map(item => ({ executable: item.executable, requiredBy: [...item.requiredBy].sort(), packages: [...item.packages].sort() })),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
module.exports = { ASSET_PROFILE, INITIAL_STAGES, STAGES, assetPaths, assetRequirements };
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"source": "iloveZzz/yss-harness-design-agent",
|
|
4
4
|
"source_type": "git-submodule",
|
|
5
5
|
"source_root": ".agents/skills",
|
|
6
|
-
"source_revision": "
|
|
6
|
+
"source_revision": "8948ada59432ce2c4e1ef34999eaed45939bdf5e",
|
|
7
7
|
"adaptation_ref": ".template-source/agents/strategic-design-skills-integration.md",
|
|
8
8
|
"skills": [
|
|
9
9
|
{
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
{
|
|
15
15
|
"upstream": "yss-prototype-stage",
|
|
16
16
|
"canonical": "yss-prototype-stage",
|
|
17
|
-
"upstream_hash": "
|
|
17
|
+
"upstream_hash": "9d1177a3f7f4737e08f084049ca3c0a6e8da0c5327da8370a87262a1b5db3b8e"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"upstream": "yss-design-system",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
{
|
|
25
25
|
"upstream": "yss-stage-decision",
|
|
26
26
|
"canonical": "yss-stage-decision",
|
|
27
|
-
"upstream_hash": "
|
|
27
|
+
"upstream_hash": "5a55a18e996920c5e5ec683b6dfa89d714bb0a3299632ecc75e0d4865b71d108"
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
30
|
"source_state": "committed"
|
|
@@ -30,6 +30,8 @@ Slice v3 的当前执行结果须按 `references/yss-skill-execution-result.md`
|
|
|
30
30
|
|
|
31
31
|
完整草案使用 `scripts/slice-contract prepare` 或 `prepareSliceImplementationContract` 从已有 Ticket / checkpoint 和必要细化组装;执行前读取唯一 YAML,视图和检查报告不授予权限。
|
|
32
32
|
|
|
33
|
+
来源摘要、闭包、阅读视图和校验直接复用 `slice-contract` / `contract` 入口;不再用临时脚本手工重算同一合同。工具或参数缺失按消费项目 `.template-spec/process/script-execution.md` 诊断,禁止用自写校验替代当前合同门禁。
|
|
34
|
+
|
|
33
35
|
合同结构见 [slice-implementation-contract.md](references/slice-implementation-contract.md),专项返回协议见 [yss-skill-execution-result.md](references/yss-skill-execution-result.md)。前端、后端和测试子任务必须由生命周期主控从批准的 Slice Contract 编译任务包;任务包 schema 为 `.template-spec/process/schemas/subagent-task-package.schema.json`,技能列表必须来自 `taskPackageDefaults`,不能由编译器或执行 Agent 另行手写。
|
|
34
36
|
|
|
35
37
|
## 硬规则
|
|
@@ -9,7 +9,7 @@ description: 编排 YSS 研发全生命周期;当阶段、产物、门禁或 S
|
|
|
9
9
|
|
|
10
10
|
五类机器资产默认 JSON;读写、迁移及恢复须遵循 `.template-spec/process/structured-assets.md`。
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
文档/进度按 `document_writing` 调用 `i-have-adhd`,遵循 `.template-spec/process/document-writing.md`。
|
|
13
13
|
|
|
14
14
|
## 事实源
|
|
15
15
|
|
|
@@ -29,18 +29,20 @@ scripts/query-lifecycle-context --work-unit work-unit.plan-requirements --check-
|
|
|
29
29
|
|
|
30
30
|
`--include` 限合同顶层键。调用前按 [来源与补装](references/matt-yss-adapter.md) 预检,在既有授权内补装并重验。
|
|
31
31
|
|
|
32
|
-
按 `execution_efficiency`
|
|
32
|
+
按 `execution_efficiency` 复用入口、合并查询和未变资料,核验资产与门禁;见项目 `.template-spec/process/script-execution.md`。
|
|
33
33
|
|
|
34
34
|
## 入口与模式
|
|
35
35
|
|
|
36
36
|
1. 严格解析 `yss-project.yaml`,不得按目录、Git remote 或占位符猜仓库身份。
|
|
37
|
-
2.
|
|
38
|
-
3.
|
|
37
|
+
2. 判定影响面及最近可信阶段;完成须有内容、审查、新鲜上游和可读证据,文件存在不代表通过。
|
|
38
|
+
3. 按 `request_triage` 选 `route`、`orchestrate`、`resume`、`audit`;行动请求无需模式关键字,意图不明只读 `route`。模式、门禁及授权边界仍适用。
|
|
39
39
|
4. `project-instance` 按生命周期注册表推进;`template-source` 只走模板维护流程。
|
|
40
40
|
|
|
41
|
-
Plan 入口读 `.template-spec/plan/README.md`、`.template-spec/process/plan-migration.md
|
|
41
|
+
Plan 入口读 `.template-spec/plan/README.md`、`.template-spec/process/plan-migration.md`,核验战略输入与退出条件。关键未决项阻断 Spec;其余记责任人、时点和接收方。仅认 Plan,不解析旧阶段或自动沿用历史批准。
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
必须确认的未决项按 `planning.clarification_policy` 主动调用 `grilling`,见 [澄清](references/plan-requirements.md)。
|
|
44
|
+
|
|
45
|
+
分诊见 [协议](references/request-triage.md) 与 `--include request_triage`;先查证据,再问必要缺口。
|
|
44
46
|
|
|
45
47
|
## 不可越过的边界
|
|
46
48
|
|
|
@@ -58,18 +60,18 @@ Plan 入口读 `.template-spec/plan/README.md`、`.template-spec/process/plan-mi
|
|
|
58
60
|
|
|
59
61
|
### 用户决定
|
|
60
62
|
|
|
61
|
-
按角色表 `user_decision_policy`
|
|
63
|
+
按角色表 `user_decision_policy` 与 `references/user-decisions.md` 展示资产、范围、风险、后续动作,再取得提问者或指定生物人的原始回复。数字人、超时、默认项不得代答。先验 `continuation_ref`;未知先调查,实质变化或缺强制审批时重新决定。缺陷/缺证据阻断,建议记待办;合同、验证、外部授权仍适用。
|
|
62
64
|
|
|
63
65
|
### 外部副作用与 Git
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
生命周期批准、实现授权、泛泛意向不构成 Git 授权。按 `references/user-decisions.md` 整理明确动作与范围的真实回复,无需重填字段。commit、push、其他外部动作分别核验;来源不可读、撤回、越界则不执行。`git-submodule` 逐仓授权、非 detached HEAD、先子仓后父仓 gitlink。
|
|
66
68
|
|
|
67
69
|
## 有界编排循环
|
|
68
70
|
|
|
69
71
|
1. 从真实资产重建状态,查询 mode、stage、work-unit 及必要合同子树。
|
|
70
72
|
2. 核验影响面、上游新鲜度、门禁和阻塞,选择首个未阻塞单元;`not-applicable` 不作豁免。
|
|
71
73
|
3. 主控持有原生正式资产;专项按结构化任务包派发,只调用合同允许的 model-invoked skill。
|
|
72
|
-
4. `to-spec`、`to-tickets`、`implement`
|
|
74
|
+
4. 兼容入口 `to-spec`、`to-tickets`、`implement` 仅由用户显式调用。主控预检输入、路径、门禁;入口按 `matt_invocation_boundary` 写产物并回交验收,不批准或改变 Ticket 就绪状态。原生资产归主控。
|
|
73
75
|
5. 先逐项验收用户目标、遗漏、错误假设和未决问题,再验收 `Workflow Execution Result`:工作单元、合同、允许写路径、`context_reconciliation`、证据、实际验证、延期 seam、漂移和下一路由必须可核验。实现派发额外绑定当前 Slice Implementation Contract v3;其他阶段不得伪造该合同。
|
|
74
76
|
6. 按 `blocking_disposition` 自主处理阻塞;缺真实决定或新授权才展示资产后询问。独立工作继续,完成结论不新增暂停。
|
|
75
77
|
|
|
@@ -81,22 +83,24 @@ Plan 入口读 `.template-spec/plan/README.md`、`.template-spec/process/plan-mi
|
|
|
81
83
|
|
|
82
84
|
Plan → Spec 写入前按 `.template-spec/plan/entry-review.md` 持久化审阅包,执行 `node scripts/verify-plan-spec-entry <state.yaml>`;缺项、过期或无真实回复阻断,独立调研继续。
|
|
83
85
|
|
|
86
|
+
`checks.grill_exit=passed` 仅准备就绪;共同理解与当前 Plan 合并真实确认后,入口判定完整退出。
|
|
87
|
+
|
|
84
88
|
## 结果与暂停
|
|
85
89
|
|
|
86
|
-
|
|
90
|
+
每轮返回/暂停按 `user_progress_report` 说明阶段及依据、结果、下一阶段/单元及条件、问题/阻塞、责任方、解除与复验、主控动作、用户决定。未知写“待核验”,负责人缺失写“未登记”;目标不代表批准,已授权修复继续。
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
按 `workflow_execution_result` 与 `references/state-model.md` 记录状态、证据新鲜度、阻塞、动作、路由、Ticket / Git checkpoint。
|
|
89
93
|
|
|
90
|
-
|
|
94
|
+
发送前核对状态、证据新鲜度、阻塞与结构化结果;见 [结果提示](references/orchestration.md#结果与友好提示)。会签保留门禁、角色/运行时、文件、推荐答案、恢复动作。恢复先验证;完成/合并/发布须同一候选通过适用审查和 fresh verification;发布须生物人决定。
|
|
91
95
|
|
|
92
|
-
Plan
|
|
96
|
+
Plan/Spec/Design 追踪见 `.template-spec/process/stage-tracking.md`。
|
|
93
97
|
|
|
94
|
-
|
|
98
|
+
澄清读 [对账](references/plan-requirements.md),外部输入读 [问卷](references/external-input-questionnaire.md)。
|
|
95
99
|
|
|
96
100
|
Spec 起草业务票,Design 校准后正式化;无设计影响直接正式化,研发再细化 Slice。按 `.template-spec/process/business-tickets.md` 检查覆盖和批准;业务票不授予实现资格。
|
|
97
101
|
|
|
98
102
|
## 功能资产整理
|
|
99
103
|
|
|
100
|
-
|
|
104
|
+
资产整理及旧票迁移按 `.template-spec/process/feature-assets.md` 和显式计划保留状态、批准依据、原文,不推进阶段;被引用草稿按正式资产保留。
|
|
101
105
|
|
|
102
|
-
|
|
106
|
+
既有实例模板升级、旧布局迁移和升级恢复用 `yss-harness-upgrade`,遵循 `.template-spec/process/harness-upgrade.md`;不推进产品阶段或重写历史批准。
|
|
@@ -35,7 +35,7 @@ Matt skills 决定如何工作;YSS 生命周期决定是否允许推进;YSS
|
|
|
35
35
|
| 情形 | Matt flow | 生命周期验收 |
|
|
36
36
|
|---|---|---|
|
|
37
37
|
| 首次启用或配置缺失 | `setup-matt-pocock-skills`(用户显式) | `needs-human`,说明缺失项;用户完成 setup 后重新计算 readiness |
|
|
38
|
-
| 需求澄清 | 原生 `work-unit.plan-requirements
|
|
38
|
+
| 需求澄清 | 原生 `work-unit.plan-requirements`,按 `planning.clarification_policy` 主动调用 `grilling` 处理必须确认的未决决定,术语使用 `domain-modeling` | 逐项验收未决项和证据回流;完整退出联合当前 Plan 用户决定 |
|
|
39
39
|
| 信息在其他人手中 | 生命周期外部输入问卷 | 使用 `external-input-required` 暂停;答案回流后记录 response、重新分类影响面,再进入 `work-unit.plan-requirements` 或 `to-spec` |
|
|
40
40
|
| 大型模糊工作 | `wayfinder`(可选) | 仅在跨会话 / 跨 Agent 或 frontier 不清晰时启用;map 真正完成后 `handoff → to-spec` |
|
|
41
41
|
| 技术或战略事实 | `yss-research`(`research` 为 deprecated alias) | `technical-evidence` 核验一手技术资料;`strategy-evidence` 为领域战略和阶段决策提供可审计证据;研究包不得自行修改或批准下游资产 |
|
|
@@ -92,6 +92,8 @@ blocking_signals: []
|
|
|
92
92
|
|
|
93
93
|
`grill_exit` 不是“已经聊过”的自然语言声明。它必须同时证明 frontier 为空、事实已解决或分别路由到 `yss-research` / prototype / external input、用户决策已确认、双方共同理解已确认,并且没有未回流的 runnable blocker。
|
|
94
94
|
|
|
95
|
+
按 `planning.clarification_policy` 主动开始必要澄清,调查、实验和专业审查分别取得证据,分轮仅询问前提已明确的必要决定。审阅包中的 `checks.grill_exit=passed` 表示澄清准备就绪;共同理解总述与完整当前 Plan 审阅包合并展示,由同一真实回复确认。入口联合准备检查与当前 `gate.plan-approved` 决定后才判断完整退出;回复独立保存,不回写审阅包或依据,不增加批准阶段。
|
|
96
|
+
|
|
95
97
|
## Review 候选与 Git 授权
|
|
96
98
|
|
|
97
99
|
YSS 调用 `code-review` 前必须形成 review input,至少包含 `review_mode`、`review_base_ref`、`implementation_candidate_ref`、`candidate_snapshot_ref`、`candidate_digest`、`spec_ref`、`ticket_ref`、`slice_contract_ref`、`build_architecture_checklist_ref` 和 `yss_execution_result_refs`,并满足 `orchestration-contract.yaml.review_input.manifest_required_by_mode`。Standards 还必须编译 `review_standards_route`:合同 `required_skills`、影响面专项检查输入、报告模板与 `finding_disposition`;机器检查按 `run_if_present` 执行。质量标准只从 `engineering-baseline` 引用,禁止在 review input 或切片中另起一份。命中高风险影响时,review input 还要引用 Doubt-Driven 主张 / 反证记录;缺少反证或残余风险未处理时返回 `blocked`。`committed` 审查 merge-base 到不可变 `HEAD`;`worktree` 一次捕获 merge-base 到 working tree 的 committed、staged、unstaged 和 untracked 内容,使用 `yss-worktree-candidate-v1` 规定的 raw path、uint64 big-endian 长度、tracked/untracked record 和不支持条目阻断规则计算 SHA-256,让所有参与审查者(人数按 `orchestration-contract.yaml.gate_consolidation`)消费同一不可变快照,并在返回和完成 checkpoint 复核摘要未变化。缺少输入、候选为空、专项覆盖缺失、未关闭 mandatory `violation`、适用行空白或摘要变化时返回 `blocked`,不能漏掉首轮适用项、另起通用审查 skill、由审查者改实现,或合并未重绑定的不同候选结论。`violation` 类 finding 交实现者在原合同路径修复,按差异、受影响结论 / 行为及依赖定向复审并重绑定;摘要变化、UI 或 `new_impacts` 不触发全轴默认或兜底,未知先调查。`drift` / `new_impacts` 使合同 `stale` 并回 实现合同编译器更新受影响合同;未受影响项须有可读比较依据才能复用。
|
package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml
CHANGED
|
@@ -164,6 +164,14 @@ request_triage:
|
|
|
164
164
|
structural_checks_prove_model_accuracy: false
|
|
165
165
|
|
|
166
166
|
execution_efficiency:
|
|
167
|
+
script_execution:
|
|
168
|
+
standard_operations: reuse-installed-public-entrypoints
|
|
169
|
+
entrypoint_invocation: declared-interpreter-or-executable-shebang
|
|
170
|
+
missing_capability: inspect-help-and-profile-before-adding-adapter
|
|
171
|
+
temporary_analysis: bounded-scope-outside-repository-no-new-authority
|
|
172
|
+
diagnostic_generation: synthetic-fixtures-no-real-approval-bodies
|
|
173
|
+
dependency_explanation: derive-from-current-source-and-distribution-closure
|
|
174
|
+
guidance_ref: .template-spec/process/script-execution.md
|
|
167
175
|
context_query:
|
|
168
176
|
strategy: combine-mode-stage-work-unit-and-required-includes
|
|
169
177
|
read_scope: current-work-unit-and-triggered-impacts
|
|
@@ -787,6 +795,38 @@ planning:
|
|
|
787
795
|
implementation_authorized: false
|
|
788
796
|
frontier_scope: current-plan-decisions
|
|
789
797
|
deferred_details: excluded-from-frontier-only-after-user-confirms-deferral
|
|
798
|
+
clarification_policy:
|
|
799
|
+
trigger: required-plan-user-decision-unresolved
|
|
800
|
+
skill: grilling
|
|
801
|
+
invocation_mode: model-invoked
|
|
802
|
+
explicit_user_invocation_required: false
|
|
803
|
+
inputs: [ current_scope, discovered_facts, confirmed_decisions, open_items, decision_dependencies ]
|
|
804
|
+
dispositions:
|
|
805
|
+
required_user_decision: grilling-with-real-user-response
|
|
806
|
+
discoverable_fact: investigate-or-yss-research
|
|
807
|
+
runnable_blocker: prototype-or-actual-verification-with-evidence
|
|
808
|
+
professional_wait: autonomously-dispatch-or-inspect-existing-task-then-wait
|
|
809
|
+
verification_failure: repair-supply-evidence-or-reroute
|
|
810
|
+
noncritical_detail: existing-deferral-policy-with-user-confirmation
|
|
811
|
+
rounds:
|
|
812
|
+
frontier: decisions-with-settled-prerequisites
|
|
813
|
+
questions: all-independent-actionable-frontier-questions-with-recommendations
|
|
814
|
+
advance: after-real-user-response
|
|
815
|
+
unsettled_facts: wait-only-for-dependent-questions
|
|
816
|
+
reuse: unchanged-confirmed-decisions
|
|
817
|
+
correction: reopen-only-affected-decisions-and-dependencies
|
|
818
|
+
independent_authorized_work: continue
|
|
819
|
+
convergence:
|
|
820
|
+
summary: [ user_problem, goals, mvp, non_goals, key_rules, acceptance_examples, open_item_resolutions, remaining_uncertainty ]
|
|
821
|
+
required_open_items: resolved-with-current-evidence
|
|
822
|
+
facts_and_verification: readable-evidence-required
|
|
823
|
+
preparation_check: grill_exit
|
|
824
|
+
preparation_passed_means: clarification-materials-and-prerequisites-ready
|
|
825
|
+
final_confirmation_boundary: gate.plan-approved
|
|
826
|
+
final_confirmation: shared-understanding-and-current-plan-in-one-real-response
|
|
827
|
+
final_confirmation_proof: plan_user_decision_ref-or-valid-plan_continuation_ref
|
|
828
|
+
confirmation_writeback: external-proof-without-review-or-basis-rewrite
|
|
829
|
+
completion: passed-preparation-and-valid-current-user-decision
|
|
790
830
|
|
|
791
831
|
grill_exit:
|
|
792
832
|
required: [ frontier_empty, facts_resolved_or_routed, decisions_confirmed, shared_understanding_confirmed, no_unresolved_runnable_blocker ]
|
|
@@ -795,6 +835,9 @@ grill_exit:
|
|
|
795
835
|
runnable_question: handoff-prototype-handoff
|
|
796
836
|
external_decision: external-input-required
|
|
797
837
|
user_confirmation_required: true
|
|
838
|
+
preparation_check: grill_exit
|
|
839
|
+
final_confirmation_boundary: gate.plan-approved
|
|
840
|
+
completion: passed-preparation-and-valid-current-user-decision
|
|
798
841
|
output: plan-evidence
|
|
799
842
|
|
|
800
843
|
ticket_role_transition:
|
|
@@ -55,6 +55,8 @@
|
|
|
55
55
|
|
|
56
56
|
脚本命令、实际退出码和 duration_ms 记入已有 checkpoint 的验证证据;Agent 编排和人工等待仅在有计时来源时记录,否则标为 unknown。无需为耗时再建一套阶段产物。
|
|
57
57
|
|
|
58
|
+
常见查询、合同准备/阅读/验证、状态恢复和技能同步直接消费已安装入口,调用约定见消费项目 `.template-spec/process/script-execution.md`。工具缺失先按 Profile 和固定版本核对安装;只有实际参数或输出缺口才补适配。一次性分析保留明确输入、允许写范围与实际日志,不承载阶段裁决或批准;诊断使用固定适配器与合成 fixture。
|
|
59
|
+
|
|
58
60
|
## 阶段边界
|
|
59
61
|
|
|
60
62
|
Matt phase boundary 是工作阶段之间的上下文决策,不是新的生命周期状态。按以下顺序判断,第一项适用即停止判断:
|
|
@@ -101,7 +103,7 @@ tracker 选择和冲突按 `.template-spec/agents/issue-tracker.md` 裁决:已
|
|
|
101
103
|
|
|
102
104
|
- `work-unit.technical-analysis` 由 `yss-technical-design` 组织后端技术设计;其 `domain-driven` 分支调用 `yss-tactical-design`,`layered-mvc` 分支由自身持有。状态、规则、一致性、持久化影响本身不意味着选择 DDD。无后端技术设计影响记录带原因的 `not-applicable`,其他 API / 前端技术分析继续各自路由。新合同使用 `artifact.technical-design`,通过 `evidence.technical-design-review` 回交现有架构审查;旧 DDD 稳定 ID 只读兼容。批准仍由生命周期维护,编译器消费批准且当前的设计起草实现合同;`stale`、`drift` 或 `new_impacts` 时不得继续 Ticket 正式化。
|
|
103
105
|
|
|
104
|
-
- `work-unit.plan-requirements`
|
|
106
|
+
- `work-unit.plan-requirements` 按 `planning.clarification_policy` 在必须确认的需求、规则、范围或取舍未决时主动调用 `grilling`,术语工作使用 `domain-modeling`。事实、实验、专业审查分别回流证据,依赖分轮并复用未变确认。`checks.grill_exit=passed` 表示准备就绪;固定审阅包后将共同理解与 Plan 批准范围一并展示,以单独保存的真实回复联合完成完整退出。`work-unit.plan-opportunity` 按事实类型路由 `competitive-intelligence` 或 `yss-research`。`yss-research:quick` 只用于探索;外部证据进入领域战略、阶段决策或其他生命周期批准输入前必须升级为 `evidence-audited`。生命周期原生工作单元默认负责 Spec、Ticket 和实现资产;`to-spec`、`to-tickets`、`implement` 仅保留为显式兼容入口,结果必须回交生命周期验收。
|
|
105
107
|
- 原生 `work-unit.ticket-decomposition` 只能在 OpenAPI Freeze 或无 API 影响记录后创建垂直切片,初始 Ticket 状态统一为 `ready-for-human`;生命周期复算完整公式后才能提升 `ready-for-agent`。该工作单元必须返回 `ticket_decomposition_result_ref` 和垂直切片引用,并作为实现的必经前置证据。
|
|
106
108
|
- 原生 `work-unit.slice-implementation` 必须在生命周期批准并持久化 Slice Implementation Contract 和 Build Architecture Checklist 后执行;用户显式 `implement` 仍走兼容入口,不得绕过生命周期。
|
|
107
109
|
- `Workflow Execution Result.next_route` 必须通过生命周期转换校验;Spec、原型和技术分析不得直接跳转到 Ticket 正式化或实现,必须先完成 `work-unit.implementation-repository-preparation`,再进入 `work-unit.ticket-decomposition`。
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# 需求澄清与 Context 对账
|
|
2
2
|
|
|
3
|
-
`work-unit.plan-requirements` 由 `yss-product-lifecycle` 或当前 profile
|
|
3
|
+
`work-unit.plan-requirements` 由 `yss-product-lifecycle` 或当前 profile 编排器执行。发现必须确认的需求、业务规则、范围或取舍未决项时,按 `planning.clarification_policy` 主动调用 `grilling`;术语工作使用 `domain-modeling`。不另建批准入口。
|
|
4
4
|
|
|
5
5
|
1. 读取 yss-project.yaml 与唯一根 CONTEXT.md,执行 `scripts/verify-context-contract --root . --json`。缺失、大小写错误、嵌套合同、跨仓路径、伪锚点或不支持的 schema 都阻断;格式消费 `domain-modeling/CONTEXT-FORMAT.md`。
|
|
6
|
-
2.
|
|
7
|
-
3.
|
|
8
|
-
4.
|
|
9
|
-
5.
|
|
10
|
-
6.
|
|
6
|
+
2. 自行查证可发现事实,技术事实路由 `yss-research`,可执行阻塞安排原型或实际验证,专业审查由主控派发,验证失败修复或补证。真正用户决定才组成当前决策前沿;调查未完成只等待依赖该事实的问题,其他必要问题和独立已授权工作继续。未确认的术语留在 Plan,不能写成稳定事实。
|
|
7
|
+
3. 依问题依赖分轮询问全部当前可回答的必要问题,每题给出建议,保留真实原始回复;回复后再推进依赖问题。复用未变化的确认,用户纠正理解时只重开受影响问题及依赖。不能用口头同意代替事实、实验或审查证据。
|
|
8
|
+
4. 确认后由 domain-modeling 维护五列业务词汇表,以 `<ContextId>/<EnglishIdentifier>` 标识;非 Global 的 ContextId 来自已确认业务责任区。只有难以逆转、非显然且有真实取舍的决定才形成 ADR。研究和实际验证保留可读证据。
|
|
9
|
+
5. `project-instance` 批准或返回下一工作单元前生成 `context_reconciliation`,保存可读 ref、document_digest、referenced_terms_digest 与 term_refs,并执行对账验证。候选、别名、范围冲突或摘要漂移均阻断;对账不另增门禁。`template-source` 仅校验模板合同并记录有原因的 `not-applicable`,不虚构业务术语。
|
|
10
|
+
6. 收敛时回述用户问题、目标、MVP、非目标、关键规则、验收例子、未决项结论及剩余不确定性,核对解决证据和非关键延期交接。`checks.grill_exit=passed` 表示准备就绪,仍待最终真实决定。固定完整 Plan 审阅包后,将共同理解与当前 Plan 批准范围合并展示、取得同一真实回复;回复存入外部 `plan_user_decision_ref`,不回写审阅包或其 `basis`。入口通过准备检查和当前决定后才判定完整 `grill_exit`;既有批准仅按用户决定协议核验延续。
|
|
11
|
+
7. 结束时列出已确认决定、未决假设、变更文档、对账状态与引用、下一授权动作。未回流 blocker 不得进入 Spec。共同理解与变更范围未确认前不改实现合同或代码;澄清结果不能批准资产、设置 ready-for-agent 或自行推进阶段,交回当前编排器验收。
|
|
11
12
|
|
|
12
13
|
起草 Plan 使用 `.template-spec/plan/templates/plan-template.md`,Spec 使用 `.template-spec/templates/spec-template.md`;显式 `to-spec` 使用同一模板。可选只读诊断及未评估项见 `.template-spec/process/plan-spec-quality.md`,不增加阶段门禁。
|
|
@@ -26,6 +26,7 @@ export async function verifyPrototypeDesign({scope='all',toolchain=process.env.Y
|
|
|
26
26
|
if((await readdir(output)).length)throw Error('验证输出非空,拒绝覆盖历史证据');
|
|
27
27
|
const report={schema_version:1,scope,status:'running',started_at:new Date().toISOString(),output,source:null,tools:{node:process.version},checks:[],counts:{passed:0,failed:0,'not-executed':0,'not-applicable':0},limitations:['自动化结果不构成人工视觉批准、读屏结论或真实用户效果。']};
|
|
28
28
|
const env={...process.env,TMPDIR:output,YSS_PROTOTYPE_EVIDENCE_DIR:output};
|
|
29
|
+
delete env.NODE_TEST_CONTEXT; // 子进程独立输出 TAP,不继承父级 node --test 的内部传输协议。
|
|
29
30
|
const add=(id,status,reason,extra={})=>report.checks.push({id,status,...(reason?{reason}:{}),...extra});
|
|
30
31
|
async function run(id,args){
|
|
31
32
|
const log=path.join(output,id+'.log'),command=[process.execPath,...args];
|