create-yss-spec 2.2.8 → 2.2.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.
Files changed (88) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +2 -0
  4. package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
  5. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +42 -1
  6. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +6 -0
  7. package/template/.agents/skills/yss-router/references/router-contract.yaml +30 -3
  8. package/template/.agents/skills/yss-router/references/slice-implementation-contract.md +14 -0
  9. package/template/.agents/skills/yss-router/references/yss-skill-execution-result.md +5 -0
  10. package/template/.claude/skills/yss-product-lifecycle/SKILL.md +2 -0
  11. package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
  12. package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +42 -1
  13. package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +6 -0
  14. package/template/.claude/skills/yss-router/references/router-contract.yaml +30 -3
  15. package/template/.claude/skills/yss-router/references/slice-implementation-contract.md +14 -0
  16. package/template/.claude/skills/yss-router/references/yss-skill-execution-result.md +5 -0
  17. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +2 -0
  18. package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
  19. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +42 -1
  20. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +6 -0
  21. package/template/.codex/skills/yss-router/references/router-contract.yaml +30 -3
  22. package/template/.codex/skills/yss-router/references/slice-implementation-contract.md +14 -0
  23. package/template/.codex/skills/yss-router/references/yss-skill-execution-result.md +5 -0
  24. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +2 -0
  25. package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
  26. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +42 -1
  27. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +6 -0
  28. package/template/.cursor/skills/yss-router/references/router-contract.yaml +30 -3
  29. package/template/.cursor/skills/yss-router/references/slice-implementation-contract.md +14 -0
  30. package/template/.cursor/skills/yss-router/references/yss-skill-execution-result.md +5 -0
  31. package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +2 -0
  32. package/template/.hermes/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
  33. package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +42 -1
  34. package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +6 -0
  35. package/template/.hermes/skills/yss-router/references/router-contract.yaml +30 -3
  36. package/template/.hermes/skills/yss-router/references/slice-implementation-contract.md +14 -0
  37. package/template/.hermes/skills/yss-router/references/yss-skill-execution-result.md +5 -0
  38. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +2 -0
  39. package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
  40. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +42 -1
  41. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +6 -0
  42. package/template/.pi/skills/yss-router/references/router-contract.yaml +30 -3
  43. package/template/.pi/skills/yss-router/references/slice-implementation-contract.md +14 -0
  44. package/template/.pi/skills/yss-router/references/yss-skill-execution-result.md +5 -0
  45. package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +2 -0
  46. package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
  47. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +42 -1
  48. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +6 -0
  49. package/template/.qoder/skills/yss-router/references/router-contract.yaml +30 -3
  50. package/template/.qoder/skills/yss-router/references/slice-implementation-contract.md +14 -0
  51. package/template/.qoder/skills/yss-router/references/yss-skill-execution-result.md +5 -0
  52. package/template/.trae/skills/yss-product-lifecycle/SKILL.md +2 -0
  53. package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
  54. package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +42 -1
  55. package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +6 -0
  56. package/template/.trae/skills/yss-router/references/router-contract.yaml +30 -3
  57. package/template/.trae/skills/yss-router/references/slice-implementation-contract.md +14 -0
  58. package/template/.trae/skills/yss-router/references/yss-skill-execution-result.md +5 -0
  59. package/template/AGENTS.md +1 -0
  60. package/template/CONTEXT.md +2 -2
  61. package/template/DESIGN.md +203 -0
  62. package/template/docs/agents/digital-human-roles.md +1 -1
  63. package/template/docs/agents/digital-human-roles.yaml +17 -21
  64. package/template/docs/agents/yss-plugin-dependency-contract.md +45 -0
  65. package/template/docs/agents/yss-skill-registry.yaml +30 -1
  66. package/template/docs/architecture/templates/engineering-baseline-review-template.md +19 -0
  67. package/template/docs/design/README.md +12 -1
  68. package/template/docs/design/design-system-sync.yaml +12 -0
  69. package/template/docs/design/design.md +22 -2
  70. package/template/docs/design/preview-dark.html +15 -0
  71. package/template/docs/design/preview.html +20 -0
  72. package/template/docs/design/tokens/.design-md-projection.json +13 -0
  73. package/template/docs/discovery/reports/agent-governance-options.md +71 -0
  74. package/template/docs/process/harness-process-tailoring.md +7 -0
  75. package/template/docs/process/lifecycle-registry-baseline.json +1 -1
  76. package/template/docs/process/lifecycle-registry.yaml +1 -1
  77. package/template/docs/process/template-verification-profiles.yaml +7 -0
  78. package/template/docs/templates/build-architecture-checklist-template.md +2 -0
  79. package/template/docs/templates/implementation-routing-template.md +23 -0
  80. package/template/docs/user-guide//346/210/230/346/234/257/350/256/276/350/256/241/345/255/220/351/241/271/347/233/256/347/224/250/346/210/267/346/211/213/345/206/214.md +218 -0
  81. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +55 -2
  82. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214/347/264/242/345/274/225.md +21 -0
  83. package/template/scripts/lib/digital-human-roles.mjs +0 -1
  84. package/template/scripts/lib/skill-registry.mjs +70 -0
  85. package/template/scripts/verify-digital-human-roles-scenarios +1 -1
  86. package/template/skills-lock.json +2 -2
  87. package/template.manifest.json +1 -0
  88. package/template.snapshot.json +5 -5
@@ -46,6 +46,13 @@
46
46
  5. 模板正式发布仍执行一次完整 `scripts/verify-template`,但不因 L3 额外冻结候选或派发正式独立审查。
47
47
  6. 模板维护与产品切片使用同一 finding 闭环:`violation` / 机器检查失败 / 适用行空白由实施者修复后重新验证并按本表强度复审;`drift` / `new_impacts` 升级影响面并重新分级,禁止在旧合同或旧 checkpoint 上继续编码。审查者不得写实现。未命中的条件项才 `not-applicable`;命中后不得豁免。
48
48
 
49
+ ## 5. 上下文、反证与质量基线裁剪
50
+
51
+ - Slice Contract 的 `common.context_plan` 是实现上下文的唯一轻量计划:先读 `CONTEXT.md`、已批准 Spec、当前合同和适用 ADR / 工程基线,再按影响面按需加载 references;达到最小充分证据后停止扩展。缺失权威上下文只能 `blocked` 或 `reroute`。
52
+ - 质量标准在 `engineering-baseline` 中定义一次,以 `baseline_id` / `baseline_version` 被 Slice Contract、YSS Skill Execution Result、`code-review` 和发布检查复用;切片不得重定义同一标准。约束结果统一写入 `constraint_results`。
53
+ - 只有命中高风险影响时才要求 Doubt-Driven 在途反证:API / 数据迁移、跨仓契约、发布回滚、实际改变的安全行为、生命周期或生成语义。反证写入现有决策 / 架构 / 契约 / 发布审查记录,不新增生命周期阶段;缺少反证、证据不足或残余风险未处理即阻断。
54
+ - Wayfinder 是超长工作的可选规划模式,不改变阶段、门禁或 Ticket 状态;地图收敛后按 `wayfinder → handoff → to-spec` 返回主链。
55
+
49
56
  模板维护默认停在 `implementation-ready`,不自动冻结候选或派发审查。需要独立审查时显式提升到 `review-ready`;完成独立审查和最终完整门禁后才能成为 `release-ready`。三个核验入口由 `docs/process/template-verification-profiles.yaml` 统一定义:
50
57
 
51
58
  - `scripts/verify-template-fast`:按 Git 影响面运行快速检查;未映射路径或核心核验资产变化时 fail-safe 升级为完整门禁。
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": 1,
3
3
  "registry_id": "yss.lifecycle",
4
- "semantic_sha256": "49ca553e83efb9cffae220d9e6fca434b1d27096126a640f8f8e172e048808df",
4
+ "semantic_sha256": "15375e8d7da599e2117e19399cb5e14b9c53aa4e4ce7c94c4e9c135a499e55e6",
5
5
  "published_ids": [
6
6
  "artifact.architecture-review",
7
7
  "artifact.data-architecture",
@@ -360,7 +360,7 @@ work_units:
360
360
  - id: work-unit.stage-decision
361
361
  name: 阶段决策包综合
362
362
  scope: project-instance
363
- input: Discovery、DDD 战略设计、产品和商务输入。
363
+ input: Discovery、DDD 战略设计以及产品经理负责的商业约束输入。
364
364
  output: 带版本、digest、证据和下游映射的阶段决策包。
365
365
  completion: 必填字段、引用、影响面和下游消费验证通过;批准门禁完成。
366
366
  - id: work-unit.spec-synthesis
@@ -32,6 +32,7 @@ core_escalation_patterns:
32
32
  - scripts/cache-template-commit
33
33
  - scripts/capture-maintenance-candidate
34
34
  - scripts/inspect-maintenance-candidate
35
+ - .template-source/tooling/node/scripts/design-md.mjs
35
36
  required_files:
36
37
  - yss-project.yaml
37
38
  - AGENTS.md
@@ -129,6 +130,8 @@ syntax_files:
129
130
  - scripts/verify-maintenance-review-workflow-scenarios
130
131
  - scripts/verify-template-cache-scenarios
131
132
  routing:
133
+ - patterns: [DESIGN.md, "docs/design/**", ".template-source/tooling/node/scripts/design-md.mjs"]
134
+ groups: [design-system]
132
135
  - patterns: [AGENTS.md, CONTEXT.md, yss-project.yaml, package.json, .gitignore, README.md, "docs/**"]
133
136
  groups: [hygiene]
134
137
  - patterns: [AGENTS.md, yss-project.yaml, "docs/process/template-engineering-overview.md"]
@@ -156,6 +159,10 @@ routing:
156
159
  - patterns: ["scripts/**"]
157
160
  groups: [hygiene]
158
161
  groups:
162
+ design-system:
163
+ commands:
164
+ - { run: "node .template-source/tooling/node/scripts/design-md.mjs lint DESIGN.md", when: template-source }
165
+ - { run: "node .template-source/tooling/node/scripts/design-md.mjs drift", when: template-source }
159
166
  hygiene:
160
167
  commands: []
161
168
  tooling:
@@ -46,6 +46,8 @@ owner: ai
46
46
  | 工程项目路径:每个 Harness 内项目必须有具体项目段,禁止直接写入容器根或单数 `app/...` | `docs/process/implementation-repo-integration.md` / implementation path validator | | `implemented` / `seam-deferred` / `drift` / `violation` / `not-applicable` | | 路径违规时停止 build,并回到实现路由 |
47
47
  | 文档语言:持久化生命周期文档、实施记录、审查报告、发布说明和 Git checkpoint 正文必须使用中文,英文 skill / 模板不得原样落地 | `AGENTS.md` / `yss-product-lifecycle` | | `implemented` / `seam-deferred` / `drift` / `violation` / `not-applicable` | | 仅保留必要英文技术标识、命令和 metadata |
48
48
  | 高风险变更:按已批准的普通影响面结论记录验证证据、责任人和回滚约束 | `AGENTS.md` / Spec / 架构记录 | | `implemented` / `seam-deferred` / `drift` / `violation` / `not-applicable` | | 缺验证证据或责任人时不得发布或合并 |
49
+ | 质量基线:`baseline_id` / `baseline_version` 只从 `engineering-baseline` 引用,Slice、Execution Result、审查和发布不得重复定义 | `engineering-baseline` / `orchestration-contract.yaml` | | `implemented` / `seam-deferred` / `drift` / `violation` / `not-applicable` | | 缺少基线引用或出现重复标准时阻断并回到工程基线 |
50
+ | Doubt-Driven:命中 API、数据、跨仓、发布回滚、实际安全行为或生命周期 / 生成语义时具备主张、反证、证据、残余风险和审查引用 | Router Contract / `orchestration-contract.yaml` | | `implemented` / `seam-deferred` / `drift` / `violation` / `not-applicable` | | 缺反证、证据不足或残余风险未处理时阻断 |
49
51
  | | | | `implemented` / `seam-deferred` / `drift` / `violation` / `not-applicable` | | |
50
52
 
51
53
  状态说明:
@@ -95,11 +95,34 @@ owner: ai
95
95
  | verification_commands | |
96
96
  | human_review_points | |
97
97
  | full_reroute_triggers | 新 API/schema、状态机、数据模型、写目录、仓库、skill、风险、seam、交付顺序或其他未冻结行为等变化 |
98
+ | quality_baseline_ref | 工程基线的 `baseline_id` / `baseline_version`;切片不得重新定义质量标准 |
99
+ | context_plan | 必需上下文、按需上下文、停止规则和缺失动作 |
100
+ | doubt_driven_review | 高风险影响的主张、反证、证据、残余风险和审查引用;未命中时 `not-applicable` |
98
101
 
99
102
  | 不适用 skill | 原因 |
100
103
  |---|---|
101
104
  | | |
102
105
 
106
+ ### Context Plan(上下文工程)
107
+
108
+ | 字段 | 内容 |
109
+ |---|---|
110
+ | required_context_refs | `CONTEXT.md`、已批准 Spec、当前 Slice Contract、适用 ADR / 工程基线 |
111
+ | on_demand_context_refs | 命中影响面后再加载的专项 references、实现仓库文件和历史证据 |
112
+ | context_stop_rule | `minimal-sufficient-evidence` |
113
+ | missing_context_action | `blocked` / `reroute`;不得猜测补齐 |
114
+
115
+ ### Doubt-Driven 高风险反证
116
+
117
+ | 字段 | 内容 |
118
+ |---|---|
119
+ | status | `not-applicable` / `required` / `completed` / `blocked` |
120
+ | trigger_impacts | API、数据迁移、跨仓契约、发布回滚、实际安全行为、生命周期 / 生成语义 |
121
+ | claim / counterclaim | | |
122
+ | evidence_refs | |
123
+ | residual_risks | |
124
+ | reviewer_ref | |
125
+
103
126
  ## 3. YSS skill 最小集合
104
127
 
105
128
  | 领域 | skill | 使用原因 | 是否必需 |
@@ -0,0 +1,218 @@
1
+ # 战术设计子项目用户手册
2
+
3
+ 第一次接触 Tactical Design,不需要先会写代码,也不需要背诵 DDD 术语。
4
+
5
+ 这本手册把已经确认的 Strategic Design Handoff,继续细化成研发团队可以实现、测试和评审的领域模型。全文使用虚构的“客户合同审批”作为例子;示例只用于学习,不要把示例名称直接写入真实项目。
6
+
7
+ ## 这本手册适合谁
8
+
9
+ - 产品经理、业务专家:想知道业务规则在技术设计中如何被保护。
10
+ - 架构师、开发者:需要把业务边界细化为聚合、状态和一致性规则。
11
+ - 测试人员:需要找到可以独立验证的领域行为。
12
+ - AI Agent 操作者:需要知道何时让 Agent 起草、何时要求人工确认、何时必须停下。
13
+
14
+ 不懂代码也可以读完“业务读者篇”;“研发接手篇”会出现少量工程术语,但每个术语都会先用白话解释。
15
+
16
+ ## 看完能做什么
17
+
18
+ 1. 说清 Strategic Design 和 Tactical Design 的分工。
19
+ 2. 判断轻量 `Tactical DDD Check` 是否足够,还是需要独立的 Tactical Design 产物。
20
+ 3. 把一个业务场景拆成聚合、Entity、Value Object、领域服务和领域事件。
21
+ 4. 说明不变量、一致性边界、Repository / Gateway 和 API 的隔离方式。
22
+ 5. 形成可评审、可测试、可交给实现团队的战术设计结果。
23
+
24
+ ## 先记住:它解决什么问题
25
+
26
+ Strategic Design 解决“业务应该怎样分工和划边界”;Tactical Design 解决“在一个边界里面,具体由哪些对象协作,以及规则如何不被破坏”。
27
+
28
+ | 工作 | 大白话 | 典型结果 |
29
+ |---|---|---|
30
+ | Strategic Design | 决定业务地图和上下文边界 | 子域、限界上下文、统一语言、Context Map |
31
+ | Tactical Design | 决定一个上下文内部怎样组织规则 | 聚合、状态机、不变量、领域服务、领域事件 |
32
+ | 工程实现 | 把设计变成可运行的软件 | OpenAPI、代码、数据映射、测试和发布 |
33
+
34
+ 本手册的终点是“战术设计已评审并可交给实现”;OpenAPI Freeze、代码和发布仍由下游研发流程负责。
35
+
36
+ ## 开始前:确认输入和仓库身份
37
+
38
+ ### 输入必须来自已确认的交接包
39
+
40
+ 开始前应能找到批准且版本当前的 `Strategic Design Handoff`,其中至少包括:
41
+
42
+ - 已确认的业务术语和上下文边界;
43
+ - 关键场景、业务不变量和领域事件候选;
44
+ - Spec、原型或业务级 Ticket 的版本引用;
45
+ - 交给 Tactical Design 裁决的问题,例如聚合边界、状态、一致性和持久化;
46
+ - 未决问题、责任人和后续验证计划。
47
+
48
+ 如果交接包缺失、过期或与当前 Spec 不一致,先回到上游处理,不要凭经验补写模型。
49
+
50
+ ### 确认项目实例
51
+
52
+ 打开项目根目录的 `yss-project.yaml`:
53
+
54
+ | 配置 | 含义 | 处理方式 |
55
+ |---|---|---|
56
+ | `repository_mode: project-instance` | 真实业务项目 | 可以记录真实战术设计 |
57
+ | `repository_mode: template-source` | 模板源 | 只能维护通用模板,不能写具体产品模型 |
58
+ | 文件缺失或值不合法 | 身份不清楚 | 先停止并做迁移检查 |
59
+
60
+ 在项目实例中,先让 Agent 只读分诊:
61
+
62
+ ```text
63
+ 使用 yss-product-lifecycle,以 route 模式检查“客户合同审批”的 Tactical Design 输入。
64
+ 请先读取 yss-project.yaml、CONTEXT.md、Strategic Design Handoff 和当前已有架构资料。
65
+ 本轮只读,不要修改文件。请用普通话告诉我:
66
+ 1. 上游交接包是否批准且仍然有效;
67
+ 2. 当前是轻量 Tactical DDD Check 还是需要独立 Tactical Design;
68
+ 3. 已确认、待确认和冲突的业务规则分别是什么;
69
+ 4. 下一步只做哪一件事。
70
+ 正式 ID 放在普通话解释后面。
71
+ ```
72
+
73
+ ## 业务读者篇:用白话理解核心概念
74
+
75
+ ### 1. 聚合(Aggregate)
76
+
77
+ 聚合是一组必须一起守规则的对象。聚合根是这组对象对外唯一的入口;外部不能绕过聚合根直接修改内部对象。
78
+
79
+ 例子:一次“客户合同审批”可以由 `Contract` 聚合根管理审批状态和审批记录。审批记录如果只能随合同一起新增、退回和查询,就可以放在这个聚合内;不相关的通知不要硬塞进来。
80
+
81
+ 判断一个对象是否属于同一聚合,可以问:
82
+
83
+ - 这些数据是否必须在同一次事务中保持一致?
84
+ - 修改其中一个对象时,是否必须立即检查另一个对象?
85
+ - 聚合变得很大后,是否会造成锁、并发或性能问题?
86
+
87
+ 不要按数据库表的外键关系画聚合;表关系图和业务一致性边界不是一回事。
88
+
89
+ ### 2. Entity(实体)
90
+
91
+ 实体有自己的身份,即使其他属性变化,它仍然是“同一个东西”。例如合同有 `contractId`,合同名称或金额修改后仍是同一份合同。
92
+
93
+ ### 3. Value Object(值对象)
94
+
95
+ 值对象由它的值决定身份,没有单独的业务身份。例如合同金额、客户地址、审批意见或时间范围。两个值完全相同的金额可以互相替换;值对象通常应尽量不可变。
96
+
97
+ ### 4. 不变量(Invariant)
98
+
99
+ 不变量是无论哪条入口执行,都不能被破坏的规则。例如:
100
+
101
+ - 合同资料完整且校验通过后才能提交审批;
102
+ - 已通过审批的合同不能直接改回草稿;
103
+ - 同一份合同不能同时存在两个正在处理的审批流程;
104
+ - 每次审批都必须留下操作人、时间、动作和意见。
105
+
106
+ 每条不变量都要能对应至少一个测试场景。不要把“页面上有一个发布按钮”当成不变量。
107
+
108
+ ### 5. 状态机
109
+
110
+ 状态机把允许的状态变化写清楚。合同示例:`草稿 → 待审批 → 审批中 → 已通过`;审批人退回时回到“草稿”,但“已通过”不能直接回到“草稿”。
111
+
112
+ | 当前状态 | 动作 | 下一状态 | 必须满足 |
113
+ |---|---|---|---|
114
+ | 草稿 | 提交审批 | 待审批 | 合同资料完整 |
115
+ | 待审批 | 审批人接单 | 审批中 | 已分配审批人 |
116
+ | 审批中 | 审批通过 | 已通过 | 规则检查通过 |
117
+ | 审批中 | 退回 | 草稿 | 必须填写退回原因 |
118
+ | 已通过 | 修改 | 不允许 | 创建新的合同草稿 |
119
+
120
+ ### 6. 领域服务(Domain Service)
121
+
122
+ 当一条业务规则不自然属于某个实体,或需要协调多个聚合时,可以使用领域服务。领域服务只表达业务决策,不负责 HTTP、数据库连接或页面跳转。
123
+
124
+ ### 7. 领域事件(Domain Event)
125
+
126
+ 领域事件记录“业务上已经发生了什么”,例如 `ContractApproved`。它适合通知订阅者、触发异步处理或留下审计线索;事件名称应使用业务语言,不要直接暴露数据库表名。
127
+
128
+ ## 研发接手篇:从场景形成战术设计
129
+
130
+ ### 第一步:从用户场景开始,不从类名开始
131
+
132
+ 以“提交客户合同审批”为例,先写出:谁发起、前置条件、动作、结果、失败方式和后续影响。
133
+
134
+ ```text
135
+ 角色:销售人员
136
+ 前置条件:合同资料完整,且当前没有正在处理的审批流程
137
+ 动作:提交合同审批
138
+ 成功:合同进入“待审批”,产生 ContractSubmitted 事件
139
+ 失败:保留原状态,返回可理解的失败原因
140
+ ```
141
+
142
+ ### 第二步:列出规则并划一致性边界
143
+
144
+ 把规则分成“必须立即成立”和“可以稍后完成”:
145
+
146
+ | 规则 | 一致性要求 | 设计提示 |
147
+ |---|---|---|
148
+ | 提交前资料必须完整 | 立即成立 | 放在合同聚合的不变量中 |
149
+ | 同一合同不能重复提交 | 立即成立 | 由聚合 + Repository 检查并发冲突 |
150
+ | 审批结果通知销售 | 可稍后完成 | 审批完成后发送领域事件 |
151
+ | 统计报表更新 | 可稍后完成 | 使用异步订阅,不阻塞审批事务 |
152
+
153
+ 跨聚合流程由 Application 编排;核心规则仍放在 Domain。不要把所有规则塞进 Controller 或 Application Service。
154
+
155
+ ### 第三步:画出对象职责,而不是字段清单
156
+
157
+ 至少记录以下内容:
158
+
159
+ | 对象 | 类型 | 负责什么 | 不负责什么 |
160
+ |---|---|---|---|
161
+ | `Contract` | Aggregate Root / Entity | 状态变化、提交前检查 | 发送 HTTP、直接操作表 |
162
+ | `ApprovalRecord` | Entity 或 Value Object(需裁决) | 表达审批动作、意见和时间 | 决定整个流程 |
163
+ | `ApproveContract` | Domain Service(必要时) | 协调跨对象的审批规则 | 事务提交和接口适配 |
164
+ | `ContractRepository` | Repository seam | 保存和加载聚合 | 对外暴露数据库结构 |
165
+ | `ContractApproved` | Domain Event | 描述审批已通过 | 代替主事务中的规则检查 |
166
+
167
+ “Value Object 还是 Entity”不是凭习惯决定的:如果版本需要独立追踪身份、生命周期或并发操作,可能是 Entity;如果它只是不可变的版本值,可能是 Value Object。把裁决理由写下来。
168
+
169
+ ### 第四步:隔离 Repository、Gateway 和 API
170
+
171
+ - `Repository` 面向领域模型的保存 / 加载,不让领域层依赖 ORM 或表结构。
172
+ - `Gateway` 面向外部系统能力,例如通知、文件存储或规则服务;领域层只依赖抽象接口。
173
+ - API schema 面向调用方,不直接暴露聚合内部对象、Repository 或持久化表。
174
+ - Application 负责用例编排、事务边界和跨聚合协调;Domain 负责核心业务规则。
175
+
176
+ ### 第五步:写测试 seam
177
+
178
+ 每条关键规则都要有可执行的验证入口:
179
+
180
+ - 聚合行为测试:给定状态和动作,验证状态变化或拒绝原因;
181
+ - Repository / Gateway 契约测试:验证抽象接口的输入输出;
182
+ - Application 用例测试:验证事务边界和跨聚合协调;
183
+ - API 契约测试:验证公开 wire shape,不验证内部类名。
184
+
185
+ ## 什么时候需要独立 Tactical Design
186
+
187
+ 大多数简单变更,在系统概要设计中的 `Tactical DDD Check` 写清楚即可。只有当以下内容复杂到无法在一节中审查时,才升级为独立 Tactical Design 产物:
188
+
189
+ - 多个聚合之间有复杂的一致性或并发规则;
190
+ - 状态机有分支、补偿、重试或不可逆状态;
191
+ - 持久化映射会隐藏或破坏领域边界;
192
+ - Gateway、领域事件或最终一致性需要明确时序;
193
+ - 评审者无法仅凭概要设计复现关键业务行为。
194
+
195
+ 升级不是为了增加文档数量,而是为了让复杂决策可读、可测试、可追责。无论采用轻量检查还是独立文档,都必须引用同一份 `tactical-design` contract 和 `evidence.tactical-design-review`,不能产生两套互相矛盾的事实源。
196
+
197
+ ## 评审前自检
198
+
199
+ - [ ] 输入来自批准且版本当前的 `Strategic Design Handoff`。
200
+ - [ ] 统一语言与 `CONTEXT.md` 一致,没有临时创造同义词。
201
+ - [ ] 聚合根、Entity、Value Object 的身份和边界有理由。
202
+ - [ ] 每个聚合的不变量和允许的状态转换都写清楚。
203
+ - [ ] 一致性规则区分了立即成立与最终一致。
204
+ - [ ] Application、Domain、Repository、Gateway 和 API 的职责没有混淆。
205
+ - [ ] 领域事件表达业务事实,不暴露内部表结构。
206
+ - [ ] 关键规则都有测试 seam 和失败场景。
207
+ - [ ] 已判断轻量 `Tactical DDD Check` 是否足够;需要升级时写明原因。
208
+ - [ ] 未决问题有负责人、后续 Ticket、验证计划和目标版本。
209
+
210
+ ## 与其他文档怎么分工
211
+
212
+ - [用户手册索引](./用户手册索引.md):所有入门手册的入口。
213
+ - [战略设计子项目用户手册](../../submodules/yss-strategic-design-harness/docs/user-guide/战略设计子项目用户手册.md):上游 Discovery、DDD 战略设计、Spec、原型和 Strategic Design Handoff。
214
+ - [系统概要设计模板](../architecture/templates/system-overview-design-template.md):轻量 Tactical DDD Check 的记录位置。
215
+ - [架构评审清单](../architecture/templates/architecture-review-checklist.md):设计评审时的结构化检查项。
216
+ - `yss-router` 与后端 / 前端专项技能:批准后的实现合同、代码和验证规则。
217
+
218
+ 本手册是模板源中的通用分发资产。真实项目应使用自己的术语、规则、合同版本和批准记录;不要把“客户合同审批”示例当成真实业务结论。
@@ -173,6 +173,60 @@ CLI 初始化、接管或同步成功后,再准备:
173
173
  每完成一步,请告诉我改了什么、证据在哪里、下一步是什么。
174
174
  ```
175
175
 
176
+ ## 可选:使用个人 Codex Plugin
177
+
178
+ 本节介绍的是个人、本机的可选工具,不属于 YSS 模板交付物。它不会自动安装到其他成员的环境,也不会改变项目的事实源、生命周期阶段或门禁。
179
+
180
+ ### 适合谁
181
+
182
+ 当前示例插件 `yss-backend-harness` 只服务后端工程角色。产品、项目、前端和测试角色应使用各自职责对应的工具或 Plugin,不要把后端插件当成全团队通用插件。
183
+
184
+ ### 安装和触发
185
+
186
+ 在已经安装 Codex、并且本机存在 `personal` marketplace 的环境中执行:
187
+
188
+ ```bash
189
+ codex plugin add yss-backend-harness@personal
190
+ ```
191
+
192
+ 安装后刷新或重启 Codex,再在已登记的实现仓库中调用。例如:
193
+
194
+ ```text
195
+ 请读取当前 YSS 任务包和 Slice Contract,按 role.backend-engineer 生成或执行后端任务。
196
+ ```
197
+
198
+ 插件只能在以下条件满足后执行具体实现:
199
+
200
+ - 仓库是 `project-instance`,不是 `template-source`;
201
+ - 实现仓库、项目根目录、分支和验证命令已经登记;
202
+ - OpenAPI 已 Freeze,或已记录无 API 影响;
203
+ - Slice Contract 已批准并处于 `ready-for-agent`;
204
+ - 任务包明确了允许写入的路径、行为和测试 seam。
205
+
206
+ ### 插件不会替代什么
207
+
208
+ Plugin 是运行时适配器,不是新的事实源。它不会替代 `yss-product-lifecycle`、`yss-router` 或 `tdd`,不会设置 `ready-for-agent`,不会 Freeze OpenAPI,也不能承担独立审查。
209
+
210
+ 执行结果应包含 `Workflow Execution Result`(例如 `completed`、`blocked`、`needs-human` 或 `failed`)及对应证据。发现路径越界、合同过期、影响面变化或证据缺失时,应停止并回到路由流程。
211
+
212
+ ### 不可用时怎么办
213
+
214
+ 如果插件未安装、版本不兼容或执行失败,回退到通用的 `yss-router + tdd` 流程,并记录阻塞原因和实际验证命令。不要为了绕过插件故障而跳过生命周期门禁。
215
+
216
+ ### 其他应用的接入建议
217
+
218
+ 应用接入按项目需要逐步增加,不作为模板默认依赖:
219
+
220
+ 1. GitHub 或 GitLab:代码、分支、MR/PR 和 CI。
221
+ 2. Jira 或 Linear:父 Ticket、Slice Ticket、状态和责任人。
222
+ 3. GitHub Actions、GitLab CI 或 Jenkins:自动执行模板、前端和后端验证。
223
+ 4. Confluence、Notion 或飞书文档:团队说明和知识库,但不得替代仓库事实源。
224
+ 5. Figma:仅在产品设计和 UI 实现阶段接入。
225
+ 6. Slack、Teams 或企业微信:仅发送阻塞、审查和发布通知,不承载正式决策。
226
+ 7. Sentry、Grafana 或 Datadog:仅在具体产品实例上线后接入运行监控。
227
+
228
+ 推荐顺序是:本地 Git + Codex/Plugin → Git 平台 → Issue tracker → CI/CD → 知识库 → 设计、通知和监控。
229
+
176
230
  ## 一张表看懂完整路线
177
231
 
178
232
  | 你要解决的问题 | 正式阶段 | 完成后应该看到什么 |
@@ -630,12 +684,11 @@ ADR 是架构决策记录。
630
684
  | 角色 | 提前参与什么 | 交付前重点检查 |
631
685
  |---|---|---|
632
686
  | 需求经理 | 用户、范围、术语、成功标准 | Spec 是否还能被业务复述 |
633
- | 产品经理 | 优先级、页面流、状态和原型 | 实现是否偏离已确认体验 |
687
+ | 产品经理 | 优先级、页面流、状态、原型及商业约束、交付承诺和发布窗口 | 实现是否偏离已确认体验;对外承诺是否经过生物人批准 |
634
688
  | 前端工程师 | 原型可行性、API 是否好用 | 页面状态、截图、console、`pnpm` |
635
689
  | 后端工程师 | API、数据、领域规则、工程准备 | 行为测试、契约、`./mvnw` |
636
690
  | 测试工程师 | 测试入口、异常和恢复路径 | 独立审查、当次验证 |
637
691
  | 项目经理 | Ticket、依赖、仓库和风险 | 候选、发布顺序和回滚点 |
638
- | 商务 | 商业约束和交付窗口 | 对外承诺是否与实际范围一致 |
639
692
 
640
693
  角色可以由不同 Agent 运行时承载。实现者不能审查自己的候选。
641
694
 
@@ -0,0 +1,21 @@
1
+ # 用户手册索引
2
+
3
+ 这里集中放置 YSS 模板和生命周期的入门手册。第一次使用时,先看总览,再进入与你当前工作阶段对应的子项目手册。
4
+
5
+ ## 推荐阅读顺序
6
+
7
+ 1. [YSS 用户手册](./用户手册.md):了解仓库身份、生命周期主链和 Agent 使用模式。
8
+ 2. [战略设计子项目用户手册](../../submodules/yss-strategic-design-harness/docs/user-guide/战略设计子项目用户手册.md):从模糊想法形成 Strategic Design Handoff。
9
+ 3. [战术设计子项目用户手册](./战术设计子项目用户手册.md):把交接包细化为 Tactical Design,供研发实现和评审。
10
+
11
+ ## 按任务查找
12
+
13
+ | 你现在要做什么 | 推荐手册 |
14
+ |---|---|
15
+ | 创建、接管或更新 YSS 项目 | [YSS 用户手册](./用户手册.md) |
16
+ | 澄清需求、确定用户和范围 | [战略设计子项目用户手册](../../submodules/yss-strategic-design-harness/docs/user-guide/战略设计子项目用户手册.md) |
17
+ | 设计聚合、状态、不变量和领域事件 | [战术设计子项目用户手册](./战术设计子项目用户手册.md) |
18
+ | 了解完整生命周期和阶段门禁 | [产品生命周期工作流](../../submodules/yss-strategic-design-harness/docs/user-guide/产品生命周期工作流.md) |
19
+ | 查找长期协作习惯和反模式 | [生命周期最佳实践](../../submodules/yss-strategic-design-harness/docs/user-guide/生命周期最佳实践.md) |
20
+
21
+ > 本仓库是 `template-source`。手册中的业务名称和示例只用于教学;真实产品资料应在 `project-instance` 中建立,并遵守对应的生命周期门禁。
@@ -12,7 +12,6 @@ const RUNTIME_ID = /^runtime\.[a-z0-9][a-z0-9-]*$/;
12
12
  const REQUIRED_ROLES = [
13
13
  "role.requirements-manager",
14
14
  "role.product-manager",
15
- "role.business",
16
15
  "role.project-manager",
17
16
  "role.frontend-engineer",
18
17
  "role.backend-engineer",
@@ -9,6 +9,7 @@ const ROUTER_CONTRACT = path.join(ROOT, ".agents/skills/yss-router/references/ro
9
9
  const LIFECYCLE_CONTRACT = path.join(ROOT, ".agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml");
10
10
  const LAYERS = new Set(["core", "specialist", "compatibility", "maintainer-only"]);
11
11
  const MATURITIES = new Set(["draft", "verified", "supported", "deprecated"]);
12
+ const INVOCATION_MODES = new Set(["user", "model", "both"]);
12
13
  const ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
13
14
  const PLATFORM_ALIAS_PATTERN = /^[a-z0-9][a-z0-9-]*(?::[a-z0-9][a-z0-9-]*)?$/;
14
15
 
@@ -51,6 +52,74 @@ function requireObject(value, field) {
51
52
  if (!value || typeof value !== "object" || Array.isArray(value)) fail(`${field} 必须是对象`);
52
53
  }
53
54
 
55
+ function requireStringArray(value, field, { nonEmpty = false } = {}) {
56
+ if (!Array.isArray(value) || (nonEmpty && value.length === 0) || value.some((item) => typeof item !== "string" || !item.trim())) {
57
+ fail(`${field} 必须是${nonEmpty ? "非空" : ""}字符串数组`);
58
+ }
59
+ }
60
+
61
+ function validateInvocationContract(registry, skill) {
62
+ const contract = registry.invocation_contract;
63
+ requireObject(contract, "invocation_contract");
64
+ if (contract.schema_version !== 1) fail("invocation_contract.schema_version 必须为 1");
65
+ if (contract.scope !== "routing-and-dependencies-only") fail("invocation_contract.scope 必须限定为 routing-and-dependencies-only");
66
+ requireStringArray(contract.required_fields, "invocation_contract.required_fields", { nonEmpty: true });
67
+ const expected = ["invocation_mode", "trigger_conditions", "exclusion_conditions", "primary_output", "required_dependencies", "optional_dependencies"];
68
+ if (JSON.stringify(contract.required_fields) !== JSON.stringify(expected)) fail("invocation_contract.required_fields 顺序或字段不完整");
69
+ requireStringArray(contract.allowed_invocation_modes, "invocation_contract.allowed_invocation_modes", { nonEmpty: true });
70
+ if (![...INVOCATION_MODES].every((mode) => contract.allowed_invocation_modes.includes(mode))) {
71
+ fail("invocation_contract.allowed_invocation_modes 必须包含 user、model、both");
72
+ }
73
+ if (contract.trigger_source !== "impacts" || contract.trigger_encoding !== "impact:<impact>") {
74
+ fail("invocation_contract 必须从 impacts 生成 impact:<impact> 触发条件");
75
+ }
76
+ requireObject(contract.default, "invocation_contract.default");
77
+ requireObject(contract.layer_defaults, "invocation_contract.layer_defaults");
78
+ requireObject(contract.overrides, "invocation_contract.overrides");
79
+ for (const layer of LAYERS) {
80
+ const layerDefault = contract.layer_defaults[layer];
81
+ requireObject(layerDefault, `invocation_contract.layer_defaults.${layer}`);
82
+ if (!INVOCATION_MODES.has(layerDefault.invocation_mode)) fail(`${layer} 的 invocation_mode 无效`);
83
+ requireString(layerDefault.primary_output, `invocation_contract.layer_defaults.${layer}.primary_output`);
84
+ }
85
+ const defaultMode = contract.default.invocation_mode;
86
+ if (!INVOCATION_MODES.has(defaultMode)) fail("invocation_contract.default.invocation_mode 无效");
87
+ requireStringArray(contract.default.trigger_conditions, "invocation_contract.default.trigger_conditions", { nonEmpty: true });
88
+ requireStringArray(contract.default.exclusion_conditions, "invocation_contract.default.exclusion_conditions", { nonEmpty: true });
89
+ requireString(contract.default.primary_output, "invocation_contract.default.primary_output");
90
+ requireStringArray(contract.default.required_dependencies, "invocation_contract.default.required_dependencies");
91
+ requireStringArray(contract.default.optional_dependencies, "invocation_contract.default.optional_dependencies");
92
+ for (const [skillId, override] of Object.entries(contract.overrides)) {
93
+ requireObject(override, `invocation_contract.overrides.${skillId}`);
94
+ if (!ID_PATTERN.test(skillId)) fail(`invocation_contract.overrides id 非法: ${skillId}`);
95
+ if (override.invocation_mode && !INVOCATION_MODES.has(override.invocation_mode)) fail(`${skillId}.invocation_mode 无效`);
96
+ if (override.trigger_conditions) requireStringArray(override.trigger_conditions, `${skillId}.trigger_conditions`, { nonEmpty: true });
97
+ if (override.exclusion_conditions) requireStringArray(override.exclusion_conditions, `${skillId}.exclusion_conditions`, { nonEmpty: true });
98
+ if (override.primary_output) requireString(override.primary_output, `${skillId}.primary_output`);
99
+ if (override.required_dependencies) requireStringArray(override.required_dependencies, `${skillId}.required_dependencies`);
100
+ if (override.optional_dependencies) requireStringArray(override.optional_dependencies, `${skillId}.optional_dependencies`);
101
+ }
102
+ const overrideIds = Object.keys(contract.overrides);
103
+ const knownIds = new Set(registry.skills.map((item) => item?.id).filter(Boolean));
104
+ for (const skillId of overrideIds) if (!knownIds.has(skillId)) fail(`invocation_contract.overrides 引用了未登记技能: ${skillId}`);
105
+ const effective = {
106
+ ...contract.default,
107
+ ...contract.layer_defaults[skill.layer],
108
+ ...(contract.overrides[skill.id] ?? {})
109
+ };
110
+ effective.trigger_conditions = [...new Set([...(effective.trigger_conditions ?? []), ...skill.impacts.map((impact) => `impact:${impact}`)])];
111
+ if (!INVOCATION_MODES.has(effective.invocation_mode)) fail(`${skill.id}.invocation_mode 无效`);
112
+ requireStringArray(effective.trigger_conditions, `${skill.id}.trigger_conditions`, { nonEmpty: true });
113
+ requireStringArray(effective.exclusion_conditions, `${skill.id}.exclusion_conditions`, { nonEmpty: true });
114
+ requireString(effective.primary_output, `${skill.id}.primary_output`);
115
+ requireStringArray(effective.required_dependencies, `${skill.id}.required_dependencies`);
116
+ requireStringArray(effective.optional_dependencies, `${skill.id}.optional_dependencies`);
117
+ const impactTriggers = skill.impacts.map((impact) => `impact:${impact}`);
118
+ if (!impactTriggers.every((trigger) => effective.trigger_conditions.includes(trigger))) {
119
+ fail(`${skill.id} 的调用契约必须覆盖其 impacts 触发条件`);
120
+ }
121
+ }
122
+
54
123
  function requireStringSet(value, expected, field) {
55
124
  if (!Array.isArray(value)) fail(`${field} 必须是数组`);
56
125
  const missing = expected.filter((item) => !value.includes(item));
@@ -209,6 +278,7 @@ export function validateSkillRegistry(registry, { lock, routerContract, lifecycl
209
278
  if (!Array.isArray(skill.impacts) || skill.impacts.length === 0 || skill.impacts.some((item) => typeof item !== "string" || !item.trim())) {
210
279
  fail(`${skill.id} impacts 不能为空`);
211
280
  }
281
+ validateInvocationContract(registry, skill);
212
282
  }
213
283
  for (const skill of skills) {
214
284
  if (skill.replaced_by && !ids.has(skill.replaced_by)) fail(`${skill.id}.replaced_by 引用了未登记技能: ${skill.replaced_by}`);
@@ -54,7 +54,7 @@ const seven = [
54
54
  "role.lifecycle-orchestrator",
55
55
  "role.requirements-manager",
56
56
  "role.product-manager",
57
- "role.business",
57
+ "role.project-manager",
58
58
  "role.frontend-engineer",
59
59
  "role.backend-engineer",
60
60
  "role.test-engineer"
@@ -1420,7 +1420,7 @@
1420
1420
  "source": "project",
1421
1421
  "sourceType": "local",
1422
1422
  "skillPath": ".agents/skills/yss-product-lifecycle/SKILL.md",
1423
- "effectiveHash": "71b42d70464a1d05bc87270e21b0d0167ef5b7ebd2a9f84dd27eac6407660ec3",
1423
+ "effectiveHash": "a7283ff14706ed156d0ed4eea619407b9758e3f2dca521f112ab4bcdfad46f57",
1424
1424
  "targets": [
1425
1425
  ".agents/skills",
1426
1426
  ".claude/skills",
@@ -1484,7 +1484,7 @@
1484
1484
  "source": "project",
1485
1485
  "sourceType": "local",
1486
1486
  "skillPath": ".agents/skills/yss-router/SKILL.md",
1487
- "effectiveHash": "51842166ff9c3a64f4a0f357f5a669323d4f944ed5805edc44c0c20e54f510d0",
1487
+ "effectiveHash": "7b1cd0ed4fc3b99a313e125d68f2e7e9bbbf53b4369085575ba06f4d2872a3ca",
1488
1488
  "targets": [
1489
1489
  ".agents/skills",
1490
1490
  ".claude/skills",
@@ -18,6 +18,7 @@
18
18
  "AGENTS.md",
19
19
  "CLAUDE.md",
20
20
  "CONTEXT.md",
21
+ "DESIGN.md",
21
22
  "README.md",
22
23
  "skills-lock.json",
23
24
  "yss-project.yaml",
@@ -3,15 +3,15 @@
3
3
  "templateName": "yss-spec-project-template",
4
4
  "templateSource": "github:iloveZzz/yss-spec-project-template",
5
5
  "templateRepository": "https://github.com/iloveZzz/yss-spec-project-template.git",
6
- "requestedRef": "f9f97eb080519b3388be12fed07b2ce0e026b04b",
7
- "templateCommit": "f9f97eb080519b3388be12fed07b2ce0e026b04b",
8
- "manifestHash": "10d161eb3f0e426aeefad5d0b9e6c5522d8a4dbacb9edf6ed64285dcb40b1a65",
6
+ "requestedRef": "a7f2c1be9cb96569c1f6d41890edd72719a5f2af",
7
+ "templateCommit": "a7f2c1be9cb96569c1f6d41890edd72719a5f2af",
8
+ "manifestHash": "387b499e08cf3dfa03e08acbc5b5783ee287c61aca12d995c61e2140f5552f40",
9
9
  "encodedPaths": {
10
10
  ".codex/skills/data-analytics/.gitignore": ".codex/skills/data-analytics/__yss_dotfile__.gitignore",
11
11
  ".codex/skills/product-design/.npmignore": ".codex/skills/product-design/__yss_dotfile__.npmignore",
12
12
  ".codex/skills/product-design/templates/prototype/.npmrc": ".codex/skills/product-design/templates/prototype/__yss_dotfile__.npmrc",
13
13
  ".gitignore": "__yss_dotfile__.gitignore"
14
14
  },
15
- "snapshotHash": "c3bc9bef3468faa067fc44b9bd38711cb642536c724f2168fe8a72e40301f3d5",
16
- "generatedAt": "2026-09-01T17:17:08.650Z"
15
+ "snapshotHash": "9c3b6db377c9fc29f0ae947bcad5eb7ae181e1027fd2cc7b17cd000759a9ac59",
16
+ "generatedAt": "2026-09-02T16:32:00.623Z"
17
17
  }