create-yss-spec 3.3.6 → 3.3.7
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/README.md +2 -2
- package/package.json +1 -1
- package/src/template/instance-runtime.js +8 -2
- package/src/validation/snapshot.js +7 -0
- package/template/.agents/skills/.strategic-design-skills-manifest.json +5 -3
- package/template/.agents/skills/archify/SKILL.md +1 -1
- package/template/.agents/skills/yss-stage-decision/SKILL.md +13 -4
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
- package/template/.agents/skills/yss-stage-decision/references/validation-rules.md +2 -2
- package/template/.agents/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
- package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
- package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
- package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
- package/template/.codex/skills/archify/SKILL.md +1 -1
- package/template/.codex/skills/yss-stage-decision/SKILL.md +13 -4
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
- package/template/.codex/skills/yss-stage-decision/references/validation-rules.md +2 -2
- package/template/.codex/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
- package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
- package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
- package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
- package/template/.cursor/skills/archify/SKILL.md +1 -1
- package/template/.cursor/skills/yss-stage-decision/SKILL.md +13 -4
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
- package/template/.cursor/skills/yss-stage-decision/references/validation-rules.md +2 -2
- package/template/.cursor/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
- package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
- package/template/.pi/skills/archify/SKILL.md +1 -1
- package/template/.pi/skills/yss-stage-decision/SKILL.md +13 -4
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
- package/template/.pi/skills/yss-stage-decision/references/validation-rules.md +2 -2
- package/template/.pi/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
- package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
- package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
- package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
- package/template/docs/process/frontend-backend-delivery.md +7 -4
- package/template/docs/process/schemas/backend-delivery.schema.json +4 -0
- package/template/docs/process/schemas/frontend-delivery-acceptance-v1.schema.json +200 -0
- package/template/docs/process/schemas/frontend-delivery-acceptance.schema.json +37 -3
- package/template/docs/process/schemas/frontend-strategic-preflight.schema.json +32 -0
- package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +2 -1
- package/template/docs/process/schemas/strategic-consumer-feedback.schema.json +40 -0
- package/template/docs/process/schemas/strategic-design-handoff-v3.schema.json +743 -0
- package/template/docs/process/schemas/strategic-design-handoff-v4.schema.json +712 -0
- package/template/docs/process/schemas/strategic-feedback-adjudication.schema.json +42 -0
- package/template/docs/process/schemas/strategic-handoff-domain-strategy-v3.schema.json +216 -0
- package/template/docs/process/schemas/strategic-handoff-import-receipt.schema.json +39 -0
- package/template/docs/process/schemas/strategic-handoff-stage-decision-package-v3.schema.json +148 -0
- package/template/docs/process/strategic-handoff-package.md +37 -4
- package/template/docs/process/templates/lifecycle-checkpoint-template.yaml +1 -0
- package/template/docs/process/templates/stage-checkpoint-template.md +1 -0
- package/template/scripts/lib/approval-record.mjs +2 -1
- package/template/scripts/lib/backend-delivery.mjs +15 -3
- package/template/scripts/lib/frontend-delivery-boundary.mjs +20 -4
- package/template/scripts/lib/frontend-delivery.mjs +66 -2
- package/template/scripts/lib/strategic-feedback.mjs +33 -0
- package/template/scripts/lib/strategic-handoff-consumption.mjs +5 -0
- package/template/scripts/lib/strategic-handoff-io.mjs +1 -0
- package/template/scripts/lib/strategic-handoff.mjs +101 -10
- package/template/scripts/lib/user-decision-reuse.mjs +38 -0
- package/template/scripts/strategic-feedback +10 -0
- package/template/scripts/verify-frontend-strategic-preflight +12 -0
- package/template/skills-lock.json +10 -10
- package/template.manifest.json +1 -0
- package/template.snapshot.json +6 -5
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
用于初始化、接管已有项目并持续同步 `yss-spec-project-template` 研发管理资产的 npm CLI。
|
|
4
4
|
|
|
5
|
-
源码候选版本:`3.3.
|
|
5
|
+
源码候选版本:`3.3.7`。当前固定模板为 `yss-spec-project-template@857265c065d48198aaa2a8bcece22da5885daf7b`;CLI 运行时不会拉取模板仓库。`npm create yss-spec@latest` 获取的是实际已发布 npm 包,发布版本请以 `npm view create-yss-spec version` 为准。
|
|
6
6
|
|
|
7
7
|
## 本版模板能力
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
本版同步 Handoff v4、领域与阶段决策 v3、前后端交付边界和 committed-source 身份校验。CLI 仍会在同一事务内刷新生成型 `skills-lock.json`,再运行项目实例校验;刷新或校验失败恢复同步前状态。版本升级只完成 GitHub 源码交付,npm 发布状态仍以 registry 为准。
|
|
10
10
|
|
|
11
11
|
## 快速开始
|
|
12
12
|
|
package/package.json
CHANGED
|
@@ -395,13 +395,16 @@ function collectManagedFiles(desiredOperations) {
|
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
function buildMetadata(variables, desiredOperations, timestamp = nowIsoString()) {
|
|
398
|
+
const snapshot = readTemplateSnapshot();
|
|
398
399
|
return {
|
|
399
400
|
metadataSchemaVersion: METADATA_SCHEMA_VERSION,
|
|
400
401
|
templateName: PACKAGE_MANIFEST.name,
|
|
401
402
|
cliVersion: PACKAGE_MANIFEST.version,
|
|
402
403
|
templateVersion: PACKAGE_MANIFEST.version,
|
|
403
404
|
templateSource: TEMPLATE_SOURCE,
|
|
404
|
-
templateCommit:
|
|
405
|
+
templateCommit: snapshot.templateCommit,
|
|
406
|
+
templateSourceState: snapshot.sourceState,
|
|
407
|
+
snapshotHash: snapshot.snapshotHash,
|
|
405
408
|
initializedAt: timestamp,
|
|
406
409
|
lastSyncedAt: timestamp,
|
|
407
410
|
managedFilesManifestVersion: TEMPLATE_MANIFEST_VERSION,
|
|
@@ -427,6 +430,7 @@ function writeTemplateMetadata(targetDir, metadata, transaction = null) {
|
|
|
427
430
|
}
|
|
428
431
|
|
|
429
432
|
function buildNextSyncMetadata(metadata, syncPlan) {
|
|
433
|
+
const snapshot = readTemplateSnapshot();
|
|
430
434
|
const nextManagedFiles = { ...(metadata.managedFiles || {}) };
|
|
431
435
|
delete nextManagedFiles["README.md"];
|
|
432
436
|
for (const relativePath of syncPlan.alreadyMissing || []) delete nextManagedFiles[relativePath];
|
|
@@ -449,7 +453,9 @@ function buildNextSyncMetadata(metadata, syncPlan) {
|
|
|
449
453
|
cliVersion: PACKAGE_MANIFEST.version,
|
|
450
454
|
templateVersion: PACKAGE_MANIFEST.version,
|
|
451
455
|
templateSource: TEMPLATE_SOURCE,
|
|
452
|
-
templateCommit:
|
|
456
|
+
templateCommit: snapshot.templateCommit,
|
|
457
|
+
templateSourceState: snapshot.sourceState,
|
|
458
|
+
snapshotHash: snapshot.snapshotHash,
|
|
453
459
|
lastSyncedAt: nowIsoString(),
|
|
454
460
|
managedFilesManifestVersion: TEMPLATE_MANIFEST_VERSION,
|
|
455
461
|
managedFiles: nextManagedFiles,
|
|
@@ -13,6 +13,13 @@ function validateTemplateSnapshot(snapshot, { manifestHash, treeHash } = {}) {
|
|
|
13
13
|
if (!/^[0-9a-f]{40}$/.test(snapshot.templateCommit || "")) {
|
|
14
14
|
throw new Error("模板快照必须绑定 40 位不可变 templateCommit");
|
|
15
15
|
}
|
|
16
|
+
if (!["committed", "working-tree"].includes(snapshot.sourceState)) {
|
|
17
|
+
throw new Error("模板快照 sourceState 必须为 committed 或 working-tree");
|
|
18
|
+
}
|
|
19
|
+
const expectedRef = snapshot.sourceState === "working-tree" ? "working-tree" : snapshot.templateCommit;
|
|
20
|
+
if (snapshot.requestedRef !== expectedRef) {
|
|
21
|
+
throw new Error(`模板快照 requestedRef 与 sourceState 不一致,预期 ${expectedRef}`);
|
|
22
|
+
}
|
|
16
23
|
if (!/^[0-9a-f]{64}$/.test(snapshot.snapshotHash || "")) {
|
|
17
24
|
throw new Error("模板快照必须包含 64 位 snapshotHash");
|
|
18
25
|
}
|
|
@@ -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": "e24465921a8a51d8690a1732842274a35b935c9e",
|
|
7
7
|
"adaptation_ref": "docs/agents/strategic-design-skills-integration.md",
|
|
8
8
|
"skills": [
|
|
9
9
|
{
|
|
@@ -34,7 +34,9 @@
|
|
|
34
34
|
{
|
|
35
35
|
"upstream": "yss-stage-decision",
|
|
36
36
|
"canonical": "yss-stage-decision",
|
|
37
|
-
"upstream_hash": "
|
|
37
|
+
"upstream_hash": "8752a1ed6903bd20c33e21b521d52bd4f7a0662b1d25e00152b60ba38333c93b"
|
|
38
38
|
}
|
|
39
|
-
]
|
|
39
|
+
],
|
|
40
|
+
"source_state": "committed",
|
|
41
|
+
"source_state_note": "source_revision 与 upstream_hash 均来自已提交设计模板。"
|
|
40
42
|
}
|
|
@@ -16,7 +16,7 @@ Create a self-contained, interactive HTML diagram from a small typed JSON specif
|
|
|
16
16
|
|
|
17
17
|
When the current repository contains `yss-project.yaml`, these rules override the upstream update and delivery commands below:
|
|
18
18
|
|
|
19
|
-
- Treat Archify as a conditional specialist. Use it only when the user or the current YSS contract explicitly requires an architecture, workflow, sequence, data-flow, lifecycle, or Mermaid-beautification artifact. A diagram is derived evidence; it never replaces Spec, ADR, OpenAPI,
|
|
19
|
+
- Treat Archify as a conditional specialist. Use it only when the user or the current YSS contract explicitly requires an architecture, workflow, sequence, data-flow, lifecycle, or Mermaid-beautification artifact. A diagram is derived evidence; it never replaces the active profile's architecture contract (such as backend Tactical Design or Frontend Engineering Design), Spec, ADR, OpenAPI, Slice Implementation Contract, review, or approval evidence.
|
|
20
20
|
- Do not run `scripts/check-update.mjs`. YSS pins the upstream revision in `skills-lock.json`; upgrades happen only through the repository's skill-maintenance workflow.
|
|
21
21
|
- Validate with the upstream `validate` command, but deliver through the repository-safe wrapper from the repository root:
|
|
22
22
|
|
|
@@ -24,13 +24,22 @@ description: 编排 Plan 到 Spec 入口的方案决策与业务边界、协作
|
|
|
24
24
|
|
|
25
25
|
Plan 的目标与退出条件由 `docs/process/lifecycle-registry.yaml` 持有;从 `docs/plan/templates/plan-template.md` 汇总输入。旧资产按 `docs/process/plan-migration.md` 重新整理并核查,关键未决项不得延期到 Spec,非关键项记录责任人、解决时点与接收方。
|
|
26
26
|
|
|
27
|
-
1. 读取 `yss-project.yaml`、`CONTEXT.md`、既有 Plan/Spec、ADR
|
|
27
|
+
1. 读取 `yss-project.yaml`、`CONTEXT.md`、既有 Plan/Spec、ADR 和当前 profile 的主索引/checkpoint;按 `yss-product-lifecycle` 的 `request-triage` 区分事实确认、产品决定、门禁确认和普通澄清。
|
|
28
28
|
2. 分离事实、决策、假设、约束和未决项;技术事实走 `yss-research` 的 `technical-evidence`,领域边界、业务规则、MVP、非目标、成功标准或阶段推进依据等决策证据走 `strategy-evidence`,市场/竞品事实走 `competitive-intelligence`。
|
|
29
29
|
3. 从业务故事、已发生的事实、规则、责任人和失败路径识别业务板块与业务责任区,不从数据库表或调用链直接反推边界。
|
|
30
30
|
4. 为每个业务责任区建立统一业务词汇;对跨责任区协作记录规则提供方、规则使用方、业务决策权、信息传递方向和口径转换负责人。
|
|
31
31
|
5. 记录待确认的关键业务对象,不提前指定技术模型。
|
|
32
|
-
6. 生成 schema
|
|
33
|
-
7. 运行 Schema
|
|
32
|
+
6. 生成 schema v3 `domain_strategy` 和 `stage_decision_package`,使用稳定规则、场景、决定、假设、约束、成功标准、测试 seam 和 downstream mapping ID,并以 `context_snapshot` 绑定根 `CONTEXT.md`、术语身份、完整文档 digest、引用术语 digest和证据。
|
|
33
|
+
7. 运行 Schema、唯一性、悬空引用、根路径、术语引用、digest、语义一致性和传播验证;发现关键冲突时返回 `blocked`,不得生成 `approved` 包。v2 仅只读;修改或重发必须使用 `scripts/migrate-contract-v3.mjs` 显式迁移为 `draft` 并重新批准。v1 字符串引用先用 `scripts/migrate-context-references.mjs` 迁移到 v2;歧义引用不得猜测。
|
|
34
|
+
|
|
35
|
+
## 控制面引用
|
|
36
|
+
|
|
37
|
+
- 用户决定遵循 `docs/process/lifecycle/references/user-decisions.md`:决定必须绑定资产、版本、范围和证据;范围、风险、摘要或失效条件变化后重新确认。
|
|
38
|
+
- checkpoint 是唯一机器状态源,业务 Ticket 只保存追踪引用,不复制阶段状态。
|
|
39
|
+
- 每次批准、重发和消费者流转前执行 `context_reconciliation`,核验 `CONTEXT.md` 的全文与引用术语双摘要。
|
|
40
|
+
- 技术事实与第三方行为走 `yss-research` 的 `technical-evidence`;产品策略依据走 `strategy-evidence`;市场与竞品判断走 `competitive-intelligence`。
|
|
41
|
+
- 修改本 Skill 时只编辑 `.agents/skills` 权威副本,再由 `maintaining-skills` 生成投影和 `skills-lock.json`。
|
|
42
|
+
- 本 Skill 只能标记影响、提出待解决问题和选择消费者能力;不得预选后端架构族,不得进入技术设计或实现流程,也不得授权实现。
|
|
34
43
|
|
|
35
44
|
## 语义方向规则
|
|
36
45
|
|
|
@@ -56,7 +65,7 @@ Plan 的目标与退出条件由 `docs/process/lifecycle-registry.yaml` 持有
|
|
|
56
65
|
- 不在业务方案设计阶段生成技术模型、生产代码或 API 契约。
|
|
57
66
|
- 不把模板 Fixture 当作具体项目的业务事实。
|
|
58
67
|
|
|
59
|
-
详细合同、字段和验证规则见 `references/domain-strategy-contract.md`、`references/stage-decision-package-contract.md` 与 `references/validation-rules.md
|
|
68
|
+
详细合同、字段和验证规则见 `references/domain-strategy-contract.md`、`references/stage-decision-package-contract.md` 与 `references/validation-rules.md`。当前机器可读合同分别为 `references/domain-strategy-v3.schema.json` 和 `references/stage-decision-package-v3.schema.json`;v2 schema 仅用于历史读取。对应验证器为 `scripts/validate-domain-strategy.mjs` 与 `scripts/validate-stage-decision-package.mjs`。
|
|
60
69
|
|
|
61
70
|
## 战略交接快照包
|
|
62
71
|
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## 顶层结构
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
当前机器可读合同使用 `references/domain-strategy-v3.schema.json`;`references/domain-strategy-v2.schema.json` 仅用于历史读取。顶层必须包含:
|
|
6
6
|
|
|
7
|
-
- `schema_version:
|
|
7
|
+
- `schema_version: 3`、`domain_strategy_id`、`domain_version`、`status`、`traceability_version: 1`;
|
|
8
|
+
- 带稳定 `rule_id` 与证据的 `rule_catalog`;
|
|
8
9
|
- `contexts`、`subdomains`、`relationships`、`scenarios`;
|
|
9
10
|
- `concept_candidates`、`invariants`、`context_snapshot`;
|
|
10
11
|
- `downstream_mapping`、`evidence_refs`、`approval`。
|
|
@@ -29,4 +30,4 @@
|
|
|
29
30
|
|
|
30
31
|
## 便携交付的逐条追溯
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
正式导出要求场景 `rule_refs / critical / success_results / evidence_refs` 和不变量 `rule_ref / evidence_refs`。`downstream_mapping` 必须使用稳定 `mapping_id`、来源 ID、消费者能力、影响项、传播规则和证据。已有 v2 文档继续只读兼容;修改或重发须显式迁移为 v3 `draft` 并重新批准。具体合同见 `docs/process/strategic-handoff-package.md`,不得由导出器发明业务身份。
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://yss.local/schemas/domain-strategy-v2-compat.json",
|
|
4
|
+
"allOf": [
|
|
5
|
+
{"$ref": "domain-strategy.schema.json"},
|
|
6
|
+
{"properties": {"schema_version": {"const": 2}}, "required": ["schema_version"]}
|
|
7
|
+
]
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://yss.local/schemas/domain-strategy-v3.json",
|
|
4
|
+
"allOf": [
|
|
5
|
+
{"$ref": "domain-strategy.schema.json"},
|
|
6
|
+
{"properties": {"schema_version": {"const": 3}}, "required": ["schema_version"]}
|
|
7
|
+
]
|
|
8
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://yss.local/schemas/domain-strategy-
|
|
3
|
+
"$id": "https://yss.local/schemas/domain-strategy-current.json",
|
|
4
4
|
"title": "YSS 业务边界与规则设计",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": ["schema_version", "domain_strategy_id", "domain_version", "status", "contexts", "subdomains", "relationships", "scenarios", "concept_candidates", "invariants", "context_snapshot", "downstream_mapping", "evidence_refs", "approval"],
|
|
7
7
|
"properties": {
|
|
8
8
|
"traceability_version": {"const": 1},
|
|
9
|
-
"rule_catalog": {"type": "array", "items": {"type": "object", "additionalProperties": false, "required": ["rule_id", "statement", "responsible_context", "status"], "properties": {"rule_id": {"type": "string", "pattern": "^rule\\.[a-z0-9][a-z0-9-]*$"}, "statement": {"type": "string", "minLength": 1}, "responsible_context": {"type": "string", "minLength": 1}, "status": {"const": "confirmed"}}}, "minItems": 1},
|
|
10
|
-
"schema_version": {"
|
|
9
|
+
"rule_catalog": {"type": "array", "items": {"type": "object", "additionalProperties": false, "required": ["rule_id", "statement", "responsible_context", "status"], "properties": {"rule_id": {"type": "string", "pattern": "^rule\\.[a-z0-9][a-z0-9-]*$"}, "statement": {"type": "string", "minLength": 1}, "responsible_context": {"type": "string", "minLength": 1}, "status": {"const": "confirmed"}, "evidence_refs": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "minLength": 1}}}}, "minItems": 1},
|
|
10
|
+
"schema_version": {"enum": [2, 3]},
|
|
11
11
|
"domain_strategy_id": {"type": "string", "pattern": "^domain-strategy\\.[a-z0-9][a-z0-9-]*$"},
|
|
12
12
|
"domain_version": {"type": "string", "pattern": "^v[0-9]+$"},
|
|
13
13
|
"status": {"enum": ["draft", "ready-for-human", "approved", "stale", "blocked"]},
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"concept_candidates": {"type": "array", "items": {"$ref": "#/$defs/concept"}},
|
|
19
19
|
"invariants": {"type": "array", "items": {"$ref": "#/$defs/invariant"}},
|
|
20
20
|
"context_snapshot": {"$ref": "#/$defs/contextSnapshot"},
|
|
21
|
-
"downstream_mapping": {"type": "array"
|
|
21
|
+
"downstream_mapping": {"type": "array"},
|
|
22
22
|
"evidence_refs": {"type": "array", "minItems": 1, "items": {"type": "string", "minLength": 1}},
|
|
23
23
|
"approval": {"$ref": "#/$defs/approval"}
|
|
24
24
|
},
|
|
@@ -132,6 +132,20 @@
|
|
|
132
132
|
"reapproval_condition": {"type": "string", "minLength": 1}
|
|
133
133
|
}
|
|
134
134
|
},
|
|
135
|
+
"mappingV3": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"additionalProperties": false,
|
|
138
|
+
"required": ["mapping_id", "source_refs", "consumer_capability", "impacts", "propagation", "reapproval_condition", "evidence_refs"],
|
|
139
|
+
"properties": {
|
|
140
|
+
"mapping_id": {"type": "string", "pattern": "^mapping\\.[a-z0-9][a-z0-9-]*$"},
|
|
141
|
+
"source_refs": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "pattern": "^(rule|scenario|invariant)\\.[a-z0-9][a-z0-9-]*$"}},
|
|
142
|
+
"consumer_capability": {"enum": ["backend-technical-design", "frontend-engineering-design", "delivery-coordination"]},
|
|
143
|
+
"impacts": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "minLength": 1}},
|
|
144
|
+
"propagation": {"enum": ["direct", "transitive", "not-applicable", "stale"]},
|
|
145
|
+
"reapproval_condition": {"type": "string", "minLength": 1},
|
|
146
|
+
"evidence_refs": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "minLength": 1}}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
135
149
|
"approval": {
|
|
136
150
|
"type": "object",
|
|
137
151
|
"required": ["approval_ref", "approver", "persisted_ref", "current_version"],
|
|
@@ -142,5 +156,61 @@
|
|
|
142
156
|
"current_version": {"type": "string", "pattern": "^v[0-9]+$"}
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
|
-
}
|
|
159
|
+
},
|
|
160
|
+
"allOf": [
|
|
161
|
+
{
|
|
162
|
+
"if": {"properties": {"schema_version": {"const": 3}}, "required": ["schema_version"]},
|
|
163
|
+
"then": {
|
|
164
|
+
"required": ["traceability_version", "rule_catalog"],
|
|
165
|
+
"properties": {
|
|
166
|
+
"traceability_version": {"const": 1},
|
|
167
|
+
"rule_catalog": {
|
|
168
|
+
"items": {
|
|
169
|
+
"required": ["evidence_refs"],
|
|
170
|
+
"properties": {
|
|
171
|
+
"evidence_refs": {
|
|
172
|
+
"type": "array",
|
|
173
|
+
"minItems": 1,
|
|
174
|
+
"uniqueItems": true,
|
|
175
|
+
"items": {"type": "string", "minLength": 1}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"scenarios": {
|
|
181
|
+
"items": {
|
|
182
|
+
"required": ["rule_refs", "critical", "success_results", "evidence_refs"],
|
|
183
|
+
"properties": {
|
|
184
|
+
"evidence_refs": {
|
|
185
|
+
"type": "array",
|
|
186
|
+
"minItems": 1,
|
|
187
|
+
"uniqueItems": true,
|
|
188
|
+
"items": {"type": "string", "minLength": 1}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"invariants": {
|
|
194
|
+
"items": {
|
|
195
|
+
"required": ["rule_ref", "evidence_refs"],
|
|
196
|
+
"properties": {
|
|
197
|
+
"evidence_refs": {
|
|
198
|
+
"type": "array",
|
|
199
|
+
"minItems": 1,
|
|
200
|
+
"uniqueItems": true,
|
|
201
|
+
"items": {"type": "string", "minLength": 1}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"downstream_mapping": {"items": {"$ref": "#/$defs/mappingV3"}}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
"else": {
|
|
210
|
+
"properties": {
|
|
211
|
+
"downstream_mapping": {"items": {"$ref": "#/$defs/mapping"}}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
]
|
|
146
216
|
}
|
package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
## 必须包含
|
|
6
6
|
|
|
7
|
-
- 问题陈述、目标用户、MVP
|
|
8
|
-
-
|
|
7
|
+
- 问题陈述、目标用户、MVP、非目标,以及带稳定 ID、来源 ID 和证据的成功标准与可执行测试 seam;
|
|
8
|
+
- 带稳定 ID、来源 ID 和证据的已确认决策、假设、约束,以及有责任人的未决项;
|
|
9
9
|
- `context_snapshot`:只引用根 `CONTEXT.md`,并绑定结构化术语身份、全文摘要和引用集摘要;
|
|
10
10
|
- `domain_strategy_ref`:领域战略合同的稳定 ID、版本、digest 和批准状态;
|
|
11
11
|
- UI/API/Data/Backend/Frontend/跨仓/高风险影响面布尔值;
|
|
12
|
-
-
|
|
12
|
+
- 每个消费者能力的稳定 `mapping_id`、领域来源 ID、传播方式、重新批准条件、证据引用和批准记录。`approval.approval_ref` 必须指向可读取且通过 `scripts/verify-approval-record` 的 `gate.stage-decision-package-approved` 会签记录;`approval.approver` 必须与记录中的 `role_id` 一致。
|
|
13
13
|
|
|
14
14
|
## 未决项规则
|
|
15
15
|
|
|
@@ -19,4 +19,4 @@
|
|
|
19
19
|
|
|
20
20
|
只有 `approved` 且引用的领域战略为 `approved`、版本当前的阶段包,才可以进入 Spec synthesis。任何领域战略 digest、版本或影响面变化都使阶段包 `stale`,并要求重新评估。
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
新写入阶段包使用 `schema_version: 3`,且只能引用 Domain Strategy v3。v2 仅只读;修改或重新交付须用 `scripts/migrate-contract-v3.mjs` 生成未批准的 `draft` 后补齐来源并重新批准。旧版字符串路径或 Markdown 锚点先通过上下文迁移器读取;无法唯一映射到 `<ContextId>/<EnglishIdentifier>` 时返回 `migration-required`,不得猜测。
|
package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://yss.local/schemas/stage-decision-package-v2-compat.json",
|
|
4
|
+
"allOf": [
|
|
5
|
+
{"$ref": "stage-decision-package.schema.json"},
|
|
6
|
+
{"properties": {"schema_version": {"const": 2}}, "required": ["schema_version"]}
|
|
7
|
+
]
|
|
8
|
+
}
|
package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://yss.local/schemas/stage-decision-package-v3.json",
|
|
4
|
+
"allOf": [
|
|
5
|
+
{"$ref": "stage-decision-package.schema.json"},
|
|
6
|
+
{"properties": {"schema_version": {"const": 3}}, "required": ["schema_version"]}
|
|
7
|
+
]
|
|
8
|
+
}
|
package/template/.agents/skills/yss-stage-decision/references/stage-decision-package.schema.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://yss.local/schemas/stage-decision-package-
|
|
3
|
+
"$id": "https://yss.local/schemas/stage-decision-package-current.json",
|
|
4
4
|
"title": "YSS Stage Decision Package",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": ["schema_version", "stage_decision_id", "package_version", "status", "problem_statement", "target_users", "mvp", "non_goals", "success_criteria", "test_seams", "confirmed_decisions", "assumptions", "constraints", "unresolved_items", "context_snapshot", "domain_strategy_ref", "impact_assessment", "downstream_mapping", "evidence_refs", "approval"],
|
|
7
7
|
"properties": {
|
|
8
|
-
"schema_version": {"
|
|
8
|
+
"schema_version": {"enum": [2, 3]},
|
|
9
9
|
"stage_decision_id": {"type": "string", "pattern": "^stage-decision\\.[a-z0-9][a-z0-9-]*$"},
|
|
10
10
|
"package_version": {"type": "string", "pattern": "^v[0-9]+$"},
|
|
11
11
|
"status": {"enum": ["draft", "ready-for-human", "approved", "stale", "blocked"]},
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"target_users": {"type": "array", "minItems": 1, "items": {"type": "string", "minLength": 1}},
|
|
14
14
|
"mvp": {"type": "array", "minItems": 1, "items": {"type": "string", "minLength": 1}},
|
|
15
15
|
"non_goals": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
|
16
|
-
"success_criteria": {"type": "array", "minItems": 1
|
|
17
|
-
"test_seams": {"type": "array", "minItems": 1
|
|
18
|
-
"confirmed_decisions": {"type": "array", "minItems": 1
|
|
19
|
-
"assumptions": {"type": "array"
|
|
20
|
-
"constraints": {"type": "array"
|
|
16
|
+
"success_criteria": {"type": "array", "minItems": 1},
|
|
17
|
+
"test_seams": {"type": "array", "minItems": 1},
|
|
18
|
+
"confirmed_decisions": {"type": "array", "minItems": 1},
|
|
19
|
+
"assumptions": {"type": "array"},
|
|
20
|
+
"constraints": {"type": "array"},
|
|
21
21
|
"unresolved_items": {"type": "array", "items": {"$ref": "#/$defs/unresolved"}},
|
|
22
22
|
"context_snapshot": {"$ref": "#/$defs/contextSnapshot"},
|
|
23
23
|
"domain_strategy_ref": {"$ref": "#/$defs/domainRef"},
|
|
24
24
|
"impact_assessment": {"$ref": "#/$defs/impact"},
|
|
25
|
-
"downstream_mapping": {"type": "array", "minItems": 1
|
|
25
|
+
"downstream_mapping": {"type": "array", "minItems": 1},
|
|
26
26
|
"evidence_refs": {"type": "array", "minItems": 1, "items": {"type": "string", "minLength": 1}},
|
|
27
27
|
"approval": {"$ref": "#/$defs/approval"}
|
|
28
28
|
},
|
|
@@ -84,6 +84,31 @@
|
|
|
84
84
|
"reapproval_condition": {"type": "string", "minLength": 1}
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
|
+
"recordV3": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"additionalProperties": false,
|
|
90
|
+
"required": ["id", "statement", "evidence_refs"],
|
|
91
|
+
"properties": {
|
|
92
|
+
"id": {"type": "string", "pattern": "^(success-criterion|test-seam|decision|assumption|constraint)\\.[a-z0-9][a-z0-9-]*$"},
|
|
93
|
+
"statement": {"type": "string", "minLength": 1},
|
|
94
|
+
"source_refs": {"type": "array", "uniqueItems": true, "items": {"type": "string", "pattern": "^(rule|scenario|invariant)\\.[a-z0-9][a-z0-9-]*$"}},
|
|
95
|
+
"evidence_refs": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "minLength": 1}},
|
|
96
|
+
"status": {"enum": ["confirmed", "candidate", "stale"]}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"mappingV3": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"additionalProperties": false,
|
|
102
|
+
"required": ["mapping_id", "source_refs", "consumer_capability", "propagation", "reapproval_condition", "evidence_refs"],
|
|
103
|
+
"properties": {
|
|
104
|
+
"mapping_id": {"type": "string", "pattern": "^mapping\\.[a-z0-9][a-z0-9-]*$"},
|
|
105
|
+
"source_refs": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "pattern": "^(rule|scenario|invariant)\\.[a-z0-9][a-z0-9-]*$"}},
|
|
106
|
+
"consumer_capability": {"enum": ["backend-technical-design", "frontend-engineering-design", "delivery-coordination"]},
|
|
107
|
+
"propagation": {"enum": ["direct", "transitive", "not-applicable", "stale"]},
|
|
108
|
+
"reapproval_condition": {"type": "string", "minLength": 1},
|
|
109
|
+
"evidence_refs": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "minLength": 1}}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
87
112
|
"approval": {
|
|
88
113
|
"type": "object",
|
|
89
114
|
"required": ["approval_ref", "approver", "persisted_ref", "current_version"],
|
|
@@ -94,5 +119,30 @@
|
|
|
94
119
|
"current_version": {"type": "string", "pattern": "^v[0-9]+$"}
|
|
95
120
|
}
|
|
96
121
|
}
|
|
97
|
-
}
|
|
122
|
+
},
|
|
123
|
+
"allOf": [
|
|
124
|
+
{
|
|
125
|
+
"if": {"properties": {"schema_version": {"const": 3}}, "required": ["schema_version"]},
|
|
126
|
+
"then": {
|
|
127
|
+
"properties": {
|
|
128
|
+
"success_criteria": {"items": {"$ref": "#/$defs/recordV3"}},
|
|
129
|
+
"test_seams": {"items": {"$ref": "#/$defs/recordV3"}},
|
|
130
|
+
"confirmed_decisions": {"items": {"$ref": "#/$defs/recordV3"}},
|
|
131
|
+
"assumptions": {"items": {"$ref": "#/$defs/recordV3"}},
|
|
132
|
+
"constraints": {"items": {"$ref": "#/$defs/recordV3"}},
|
|
133
|
+
"downstream_mapping": {"items": {"$ref": "#/$defs/mappingV3"}}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"else": {
|
|
137
|
+
"properties": {
|
|
138
|
+
"success_criteria": {"items": {"type": "string", "minLength": 1}},
|
|
139
|
+
"test_seams": {"items": {"type": "string", "minLength": 1}},
|
|
140
|
+
"confirmed_decisions": {"items": {"type": "string", "minLength": 1}},
|
|
141
|
+
"assumptions": {"items": {"type": "string", "minLength": 1}},
|
|
142
|
+
"constraints": {"items": {"type": "string", "minLength": 1}},
|
|
143
|
+
"downstream_mapping": {"items": {"$ref": "#/$defs/mapping"}}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
]
|
|
98
148
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
验证分为结构、引用和语义三层:
|
|
4
4
|
|
|
5
|
-
1. **结构**:Schema
|
|
6
|
-
2.
|
|
5
|
+
1. **结构**:Schema 版本、全局稳定 ID 唯一性、状态枚举、必填字段、条件字段和非空证据格式。
|
|
6
|
+
2. **引用**:上下文端点、规则、场景、不变量、决定、测试 seam、`context_snapshot.term_refs` 和下游 mapping 来源必须可解析;`context_ref` 必须精确为根 `CONTEXT.md`,双摘要必须与当前内容一致。
|
|
7
7
|
3. **语义**:禁止关系自环、未知上下文、未批准 Shared Kernel、未解释的语义/技术方向差异、职责重叠、无责任人的不变量和跨上下文直接共享实体。
|
|
8
8
|
|
|
9
9
|
以下情况必须 `blocked`:关键规则所有权未知、关键术语冲突、上下文边界未定、关键失败场景缺失、事件语义无法解释、领域专家确认缺失。
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { parseArgs } from "node:util";
|
|
6
|
+
import { parseDocument } from "../../../../scripts/vendor/yaml.mjs";
|
|
7
|
+
|
|
8
|
+
function blocked(message) {
|
|
9
|
+
process.stderr.write(`${JSON.stringify({ result: "blocked", reason_code: "migration-required", errors: [message] }, null, 2)}\n`);
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function parse(source, label) {
|
|
14
|
+
const document = parseDocument(source, { maxAliasCount: 0, uniqueKeys: true });
|
|
15
|
+
if (document.errors.length) throw new TypeError(`${label} YAML 非法: ${document.errors[0].message}`);
|
|
16
|
+
const value = document.toJS({ maxAliasCount: 0 });
|
|
17
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`${label} 必须是对象`);
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function nextVersion(value) {
|
|
22
|
+
const matched = String(value ?? "v2").match(/^v(\d+)$/);
|
|
23
|
+
return `v${Math.max(3, Number(matched?.[1] ?? 2) + 1)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function token(value, fallback) {
|
|
27
|
+
const normalized = String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
28
|
+
return normalized || fallback;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resetApproval(value, version) {
|
|
32
|
+
value.status = "draft";
|
|
33
|
+
value.approval = {
|
|
34
|
+
approval_ref: "migration-required",
|
|
35
|
+
approver: "unassigned",
|
|
36
|
+
persisted_ref: value.approval?.persisted_ref || "migration-output-not-persisted",
|
|
37
|
+
current_version: version
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function migrateDomain(input) {
|
|
42
|
+
const output = structuredClone(input);
|
|
43
|
+
if (output.schema_version !== 2) throw new TypeError("Domain Strategy 迁移仅支持 schema_version: 2");
|
|
44
|
+
const evidence = Array.isArray(output.evidence_refs) && output.evidence_refs.length ? output.evidence_refs : ["migration-required:evidence"];
|
|
45
|
+
const rules = [];
|
|
46
|
+
const statementToId = new Map();
|
|
47
|
+
for (const [scenarioIndex, scenario] of (output.scenarios ?? []).entries()) {
|
|
48
|
+
scenario.rule_refs = [];
|
|
49
|
+
for (const [ruleIndex, statement] of (scenario.rules ?? []).entries()) {
|
|
50
|
+
let ruleId = statementToId.get(statement);
|
|
51
|
+
if (!ruleId) {
|
|
52
|
+
ruleId = `rule.${token(scenario.scenario_id?.replace(/^scenario\./, ""), `scenario-${scenarioIndex + 1}`)}-${ruleIndex + 1}`;
|
|
53
|
+
statementToId.set(statement, ruleId);
|
|
54
|
+
rules.push({ rule_id: ruleId, statement, responsible_context: scenario.responsible_context, status: "confirmed", evidence_refs: [...evidence] });
|
|
55
|
+
}
|
|
56
|
+
scenario.rule_refs.push(ruleId);
|
|
57
|
+
}
|
|
58
|
+
scenario.critical = false;
|
|
59
|
+
scenario.success_results = Array.isArray(scenario.events) && scenario.events.length ? [...scenario.events] : ["migration-required: 补充成功结果"];
|
|
60
|
+
scenario.evidence_refs = [...evidence];
|
|
61
|
+
}
|
|
62
|
+
for (const [index, invariant] of (output.invariants ?? []).entries()) {
|
|
63
|
+
let ruleId = statementToId.get(invariant.statement);
|
|
64
|
+
if (!ruleId) {
|
|
65
|
+
ruleId = `rule.${token(invariant.invariant_id?.replace(/^invariant\./, ""), `invariant-${index + 1}`)}`;
|
|
66
|
+
statementToId.set(invariant.statement, ruleId);
|
|
67
|
+
rules.push({ rule_id: ruleId, statement: invariant.statement, responsible_context: invariant.responsible_context, status: "confirmed", evidence_refs: [...evidence] });
|
|
68
|
+
}
|
|
69
|
+
invariant.rule_ref = ruleId;
|
|
70
|
+
invariant.evidence_refs = [...evidence];
|
|
71
|
+
}
|
|
72
|
+
const sourceRefs = [...(output.scenarios ?? []).map((item) => item.scenario_id), ...(output.invariants ?? []).map((item) => item.invariant_id)].filter(Boolean);
|
|
73
|
+
output.downstream_mapping = (output.downstream_mapping ?? []).map((mapping, index) => {
|
|
74
|
+
const impacts = Array.isArray(mapping.impacts) ? mapping.impacts : ["migration-required"];
|
|
75
|
+
const isFrontend = impacts.some((item) => /frontend|ui|visual/i.test(item));
|
|
76
|
+
return {
|
|
77
|
+
mapping_id: `mapping.${token(mapping.domain_change, `migrated-${index + 1}`)}`,
|
|
78
|
+
source_refs: sourceRefs.length ? sourceRefs : [rules[0]?.rule_id].filter(Boolean),
|
|
79
|
+
consumer_capability: isFrontend ? "frontend-engineering-design" : "backend-technical-design",
|
|
80
|
+
impacts,
|
|
81
|
+
propagation: mapping.propagation,
|
|
82
|
+
reapproval_condition: mapping.reapproval_condition,
|
|
83
|
+
evidence_refs: [...evidence]
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
output.schema_version = 3;
|
|
87
|
+
output.traceability_version = 1;
|
|
88
|
+
output.rule_catalog = rules;
|
|
89
|
+
output.domain_version = nextVersion(output.domain_version);
|
|
90
|
+
resetApproval(output, output.domain_version);
|
|
91
|
+
return output;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function migrateStage(input, root) {
|
|
95
|
+
const output = structuredClone(input);
|
|
96
|
+
if (output.schema_version !== 2) throw new TypeError("Stage Decision 迁移仅支持 schema_version: 2");
|
|
97
|
+
const evidence = Array.isArray(output.evidence_refs) && output.evidence_refs.length ? output.evidence_refs : ["migration-required:evidence"];
|
|
98
|
+
let sourceRefs = [];
|
|
99
|
+
try {
|
|
100
|
+
const domainSource = await readFile(resolve(root, output.domain_strategy_ref.persisted_ref), "utf8");
|
|
101
|
+
const domain = parse(domainSource, "Domain Strategy");
|
|
102
|
+
sourceRefs = [...(domain.rule_catalog ?? []).map((item) => item.rule_id), ...(domain.scenarios ?? []).map((item) => item.scenario_id), ...(domain.invariants ?? []).map((item) => item.invariant_id)].filter(Boolean);
|
|
103
|
+
} catch {
|
|
104
|
+
sourceRefs = [];
|
|
105
|
+
}
|
|
106
|
+
const prefixes = { success_criteria: "success-criterion", test_seams: "test-seam", confirmed_decisions: "decision", assumptions: "assumption", constraints: "constraint" };
|
|
107
|
+
for (const [field, prefix] of Object.entries(prefixes)) {
|
|
108
|
+
output[field] = (output[field] ?? []).map((statement, index) => ({
|
|
109
|
+
id: `${prefix}.${token(statement, `migrated-${index + 1}`)}`,
|
|
110
|
+
statement,
|
|
111
|
+
source_refs: sourceRefs.slice(0, 1),
|
|
112
|
+
evidence_refs: [...evidence],
|
|
113
|
+
status: "candidate"
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
output.downstream_mapping = (output.downstream_mapping ?? []).map((mapping, index) => ({
|
|
117
|
+
mapping_id: `mapping.${token(mapping.domain_change, `migrated-${index + 1}`)}`,
|
|
118
|
+
source_refs: sourceRefs.slice(0, 1),
|
|
119
|
+
consumer_capability: /frontend|ui/i.test(mapping.consumer ?? "") ? "frontend-engineering-design" : /coord/i.test(mapping.consumer ?? "") ? "delivery-coordination" : "backend-technical-design",
|
|
120
|
+
propagation: mapping.propagation,
|
|
121
|
+
reapproval_condition: mapping.reapproval_condition,
|
|
122
|
+
evidence_refs: [...evidence]
|
|
123
|
+
}));
|
|
124
|
+
output.schema_version = 3;
|
|
125
|
+
output.package_version = nextVersion(output.package_version);
|
|
126
|
+
resetApproval(output, output.package_version);
|
|
127
|
+
return output;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const { values, positionals } = parseArgs({
|
|
132
|
+
options: { kind: { type: "string" }, root: { type: "string", default: process.cwd() } },
|
|
133
|
+
allowPositionals: true,
|
|
134
|
+
strict: true
|
|
135
|
+
});
|
|
136
|
+
const file = positionals[0];
|
|
137
|
+
if (!file || !["domain-strategy", "stage-decision"].includes(values.kind)) throw new TypeError("用法: migrate-contract-v3.mjs <contract.yaml> --kind <domain-strategy|stage-decision> [--root <project-root>]");
|
|
138
|
+
const value = parse(await readFile(file, "utf8"), "合同");
|
|
139
|
+
const migrated = values.kind === "domain-strategy" ? migrateDomain(value) : await migrateStage(value, values.root);
|
|
140
|
+
process.stdout.write(`${JSON.stringify(migrated, null, 2)}\n`);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
blocked(error.message);
|
|
143
|
+
}
|