create-yss-spec 2.1.2 → 2.1.4

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 (253) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/template/.agents/skills/code-review/SKILL.md +38 -10
  4. package/template/.agents/skills/yss-api-integration/SKILL.md +25 -7
  5. package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
  6. package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
  7. package/template/.agents/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
  8. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
  9. package/template/.agents/skills/yss-design-system/SKILL.md +1 -1
  10. package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
  11. package/template/.agents/skills/yss-openapi-draft-review/SKILL.md +13 -17
  12. package/template/.agents/skills/yss-openapi-governance/SKILL.md +89 -114
  13. package/template/.agents/skills/yss-openapi-governance/agents/openai.yaml +2 -2
  14. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +11 -5
  15. package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  16. package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
  17. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
  18. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +7 -2
  19. package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +8 -0
  20. package/template/.agents/skills/yss-router/SKILL.md +2 -2
  21. package/template/.agents/skills/yss-router/references/router-contract.yaml +4 -6
  22. package/template/.agents/skills/yss-router/references/slice-implementation-contract.md +1 -1
  23. package/template/.agents/skills/yss-router/references/yss-skill-execution-result.md +2 -1
  24. package/template/.claude/skills/code-review/SKILL.md +38 -10
  25. package/template/.claude/skills/yss-api-integration/SKILL.md +25 -7
  26. package/template/.claude/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
  27. package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
  28. package/template/.claude/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
  29. package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
  30. package/template/.claude/skills/yss-design-system/SKILL.md +1 -1
  31. package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
  32. package/template/.claude/skills/yss-openapi-draft-review/SKILL.md +13 -17
  33. package/template/.claude/skills/yss-openapi-governance/SKILL.md +89 -114
  34. package/template/.claude/skills/yss-openapi-governance/agents/openai.yaml +2 -2
  35. package/template/.claude/skills/yss-product-lifecycle/SKILL.md +11 -5
  36. package/template/.claude/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  37. package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
  38. package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
  39. package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +7 -2
  40. package/template/.claude/skills/yss-product-lifecycle/references/state-model.md +8 -0
  41. package/template/.claude/skills/yss-router/SKILL.md +2 -2
  42. package/template/.claude/skills/yss-router/references/router-contract.yaml +4 -6
  43. package/template/.claude/skills/yss-router/references/slice-implementation-contract.md +1 -1
  44. package/template/.claude/skills/yss-router/references/yss-skill-execution-result.md +2 -1
  45. package/template/.codex/skills/code-review/SKILL.md +38 -10
  46. package/template/.codex/skills/yss-api-integration/SKILL.md +25 -7
  47. package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
  48. package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
  49. package/template/.codex/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
  50. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
  51. package/template/.codex/skills/yss-design-system/SKILL.md +1 -1
  52. package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
  53. package/template/.codex/skills/yss-openapi-draft-review/SKILL.md +13 -17
  54. package/template/.codex/skills/yss-openapi-governance/SKILL.md +89 -114
  55. package/template/.codex/skills/yss-openapi-governance/agents/openai.yaml +2 -2
  56. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +11 -5
  57. package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  58. package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
  59. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
  60. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +7 -2
  61. package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +8 -0
  62. package/template/.codex/skills/yss-router/SKILL.md +2 -2
  63. package/template/.codex/skills/yss-router/references/router-contract.yaml +4 -6
  64. package/template/.codex/skills/yss-router/references/slice-implementation-contract.md +1 -1
  65. package/template/.codex/skills/yss-router/references/yss-skill-execution-result.md +2 -1
  66. package/template/.hermes/skills/code-review/SKILL.md +38 -10
  67. package/template/.hermes/skills/yss-api-integration/SKILL.md +25 -7
  68. package/template/.hermes/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
  69. package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
  70. package/template/.hermes/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
  71. package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
  72. package/template/.hermes/skills/yss-design-system/SKILL.md +1 -1
  73. package/template/.hermes/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
  74. package/template/.hermes/skills/yss-openapi-draft-review/SKILL.md +13 -17
  75. package/template/.hermes/skills/yss-openapi-governance/SKILL.md +89 -114
  76. package/template/.hermes/skills/yss-openapi-governance/agents/openai.yaml +2 -2
  77. package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +11 -5
  78. package/template/.hermes/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  79. package/template/.hermes/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
  80. package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
  81. package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +7 -2
  82. package/template/.hermes/skills/yss-product-lifecycle/references/state-model.md +8 -0
  83. package/template/.hermes/skills/yss-router/SKILL.md +2 -2
  84. package/template/.hermes/skills/yss-router/references/router-contract.yaml +4 -6
  85. package/template/.hermes/skills/yss-router/references/slice-implementation-contract.md +1 -1
  86. package/template/.hermes/skills/yss-router/references/yss-skill-execution-result.md +2 -1
  87. package/template/.pi/skills/code-review/SKILL.md +38 -10
  88. package/template/.pi/skills/yss-api-integration/SKILL.md +25 -7
  89. package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
  90. package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
  91. package/template/.pi/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
  92. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
  93. package/template/.pi/skills/yss-design-system/SKILL.md +1 -1
  94. package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
  95. package/template/.pi/skills/yss-openapi-draft-review/SKILL.md +13 -17
  96. package/template/.pi/skills/yss-openapi-governance/SKILL.md +89 -114
  97. package/template/.pi/skills/yss-openapi-governance/agents/openai.yaml +2 -2
  98. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +11 -5
  99. package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  100. package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
  101. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
  102. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +7 -2
  103. package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +8 -0
  104. package/template/.pi/skills/yss-router/SKILL.md +2 -2
  105. package/template/.pi/skills/yss-router/references/router-contract.yaml +4 -6
  106. package/template/.pi/skills/yss-router/references/slice-implementation-contract.md +1 -1
  107. package/template/.pi/skills/yss-router/references/yss-skill-execution-result.md +2 -1
  108. package/template/.qoder/skills/code-review/SKILL.md +38 -10
  109. package/template/.qoder/skills/yss-api-integration/SKILL.md +25 -7
  110. package/template/.qoder/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
  111. package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
  112. package/template/.qoder/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
  113. package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
  114. package/template/.qoder/skills/yss-design-system/SKILL.md +1 -1
  115. package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
  116. package/template/.qoder/skills/yss-openapi-draft-review/SKILL.md +13 -17
  117. package/template/.qoder/skills/yss-openapi-governance/SKILL.md +89 -114
  118. package/template/.qoder/skills/yss-openapi-governance/agents/openai.yaml +2 -2
  119. package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +11 -5
  120. package/template/.qoder/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  121. package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
  122. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
  123. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +7 -2
  124. package/template/.qoder/skills/yss-product-lifecycle/references/state-model.md +8 -0
  125. package/template/.qoder/skills/yss-router/SKILL.md +2 -2
  126. package/template/.qoder/skills/yss-router/references/router-contract.yaml +4 -6
  127. package/template/.qoder/skills/yss-router/references/slice-implementation-contract.md +1 -1
  128. package/template/.qoder/skills/yss-router/references/yss-skill-execution-result.md +2 -1
  129. package/template/.trae/skills/code-review/SKILL.md +38 -10
  130. package/template/.trae/skills/yss-api-integration/SKILL.md +25 -7
  131. package/template/.trae/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
  132. package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
  133. package/template/.trae/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
  134. package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
  135. package/template/.trae/skills/yss-design-system/SKILL.md +1 -1
  136. package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
  137. package/template/.trae/skills/yss-openapi-draft-review/SKILL.md +13 -17
  138. package/template/.trae/skills/yss-openapi-governance/SKILL.md +89 -114
  139. package/template/.trae/skills/yss-openapi-governance/agents/openai.yaml +2 -2
  140. package/template/.trae/skills/yss-product-lifecycle/SKILL.md +11 -5
  141. package/template/.trae/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  142. package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
  143. package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
  144. package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +7 -2
  145. package/template/.trae/skills/yss-product-lifecycle/references/state-model.md +8 -0
  146. package/template/.trae/skills/yss-router/SKILL.md +2 -2
  147. package/template/.trae/skills/yss-router/references/router-contract.yaml +4 -6
  148. package/template/.trae/skills/yss-router/references/slice-implementation-contract.md +1 -1
  149. package/template/.trae/skills/yss-router/references/yss-skill-execution-result.md +2 -1
  150. package/template/AGENTS.md +6 -4
  151. package/template/CONTEXT.md +15 -1
  152. package/template/README.md +2 -1
  153. package/template/__yss_dotfile__.gitignore +4 -0
  154. package/template/docs/adr/0003-machine-readable-lifecycle-registry.md +5 -0
  155. package/template/docs/adr/0004-split-lifecycle-and-router-registry-domains.md +5 -0
  156. package/template/docs/adr/0005-cross-repository-ecosystem-release-manifest.md +5 -0
  157. package/template/docs/adr/0006-stable-lifecycle-ids-and-generated-structure.md +5 -0
  158. package/template/docs/adr/0007-separate-skill-routing-registry-from-integrity-lock.md +5 -0
  159. package/template/docs/agents/issue-tracker.md +1 -0
  160. package/template/docs/api/templates/openapi-draft-review-checklist.md +8 -6
  161. package/template/docs/api/templates/openapi-freeze-record-template.md +8 -2
  162. package/template/docs/api/templates/openapi-json-export-record-template.md +60 -0
  163. package/template/docs/architecture/templates/architecture-review-checklist.md +6 -19
  164. package/template/docs/architecture/templates/functional-architecture-template.md +4 -4
  165. package/template/docs/architecture/templates/system-overview-design-template.md +10 -5
  166. package/template/docs/architecture/templates/tech-design-template.md +4 -11
  167. package/template/docs/discovery/templates/discovery-template.md +0 -1
  168. package/template/docs/implementation/create-yss-spec-repository-mode-contract.md +2 -2
  169. package/template/docs/process/harness-process-tailoring.md +2 -0
  170. package/template/docs/process/harness-work-unit-map.md +14 -10
  171. package/template/docs/process/lifecycle-artifact-map.md +75 -39
  172. package/template/docs/process/lifecycle-registry-baseline.json +61 -0
  173. package/template/docs/process/lifecycle-registry.yaml +255 -0
  174. package/template/docs/process/schemas/lifecycle-registry.schema.json +35 -0
  175. package/template/docs/reviews/lifecycle-registry-phase0-1-red-green-2026-08-17.md +61 -0
  176. package/template/docs/reviews/matt-yss-p0-ticket-review-git-red-green-2026-08-17.md +91 -0
  177. package/template/docs/reviews/openapi-skill-primary-source-research-2026-08-16.md +76 -0
  178. package/template/docs/reviews/openapi-yaml-first-independent-review-2026-08-16.md +121 -0
  179. package/template/docs/reviews/openapi-yaml-first-pressure-scenarios-2026-08-16.md +191 -0
  180. package/template/docs/reviews/openapi-yaml-first-red-green-2026-08-16.md +76 -0
  181. package/template/docs/reviews/openapi-yaml-json-output-independent-review-2026-08-16.md +30 -0
  182. package/template/docs/reviews/openapi-yaml-json-output-scope-red-green-2026-08-16.md +154 -0
  183. package/template/docs/reviews/research-create-yss-spec-refresh-2026-08-16.md +164 -0
  184. package/template/docs/reviews/security-permission-lifecycle-simplification-red-green-2026-08-16.md +43 -0
  185. package/template/docs/reviews/template-release-review-remediation-red-green-2026-08-17.md +41 -0
  186. package/template/docs/templates/agent-brief-template.md +2 -2
  187. package/template/docs/templates/build-architecture-checklist-template.md +3 -4
  188. package/template/docs/templates/implementation-repo-registry-template.md +0 -2
  189. package/template/docs/templates/implementation-routing-template.md +6 -6
  190. package/template/docs/templates/openapi-spec-template.yaml +0 -6
  191. package/template/docs/templates/review-report-template.md +2 -1
  192. package/template/docs/templates/spec-delta-template.md +1 -1
  193. package/template/docs/templates/spec-template.md +0 -1
  194. package/template/docs/templates/vertical-slice-ticket-template.md +2 -2
  195. package/template/docs/user-guide//344/272/247/345/223/201/347/224/237/345/221/275/345/221/250/346/234/237/345/267/245/344/275/234/346/265/201.md +6 -6
  196. package/template/docs/user-guide//344/272/247/345/223/201/347/240/224/345/217/221/345/205/250/347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
  197. package/template/docs/user-guide//345/244/226/351/203/250/345/221/275/344/273/244/350/241/214/345/267/245/345/205/267/345/256/236/350/267/265/346/214/207/345/215/227.md +1 -1
  198. package/template/docs/user-guide//347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +1 -1
  199. package/template/scripts/generate-lifecycle-artifacts +26 -0
  200. package/template/scripts/lifecycle-registry.rb +194 -0
  201. package/template/scripts/sync-skills +1 -0
  202. package/template/scripts/test-export-yss-skills.rb +8 -6
  203. package/template/scripts/test-lifecycle-registry.rb +74 -0
  204. package/template/scripts/update-skill-lock +1 -0
  205. package/template/scripts/verify-governance-release +39 -0
  206. package/template/scripts/verify-lifecycle-registry +67 -0
  207. package/template/scripts/verify-lifecycle-scenarios +114 -17
  208. package/template/scripts/verify-matt-yss-integration-scenarios +297 -1
  209. package/template/scripts/verify-openapi-json-handoff-scenarios +270 -0
  210. package/template/scripts/verify-openapi-yaml-first-scenarios +120 -0
  211. package/template/scripts/verify-template +37 -5
  212. package/template/scripts/verify-yss-router-scenarios +42 -14
  213. package/template/skills-lock.json +9 -24
  214. package/template/wiki/raw/skills-lock.json +0 -15
  215. package/template/wiki/wiki/OpenAPI/345/245/221/347/272/246.md +1 -1
  216. package/template/wiki/wiki/YSS/345/267/245/347/250/213/346/212/200/350/203/275/344/275/223/347/263/273.md +1 -1
  217. package/template/yss-public-skills.json +3 -5
  218. package/template.snapshot.json +4 -4
  219. package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
  220. package/template/.agents/skills/yss-openapi/SKILL.md +0 -116
  221. package/template/.agents/skills/yss-openapi/agents/openai.yaml +0 -4
  222. package/template/.agents/skills/yss-openapi/img.png +0 -0
  223. package/template/.agents/skills/yss-openapi/img_1.png +0 -0
  224. package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
  225. package/template/.claude/skills/yss-openapi/SKILL.md +0 -116
  226. package/template/.claude/skills/yss-openapi/agents/openai.yaml +0 -4
  227. package/template/.claude/skills/yss-openapi/img.png +0 -0
  228. package/template/.claude/skills/yss-openapi/img_1.png +0 -0
  229. package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
  230. package/template/.codex/skills/yss-openapi/SKILL.md +0 -116
  231. package/template/.codex/skills/yss-openapi/agents/openai.yaml +0 -4
  232. package/template/.codex/skills/yss-openapi/img.png +0 -0
  233. package/template/.codex/skills/yss-openapi/img_1.png +0 -0
  234. package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
  235. package/template/.hermes/skills/yss-openapi/SKILL.md +0 -116
  236. package/template/.hermes/skills/yss-openapi/agents/openai.yaml +0 -4
  237. package/template/.hermes/skills/yss-openapi/img.png +0 -0
  238. package/template/.hermes/skills/yss-openapi/img_1.png +0 -0
  239. package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
  240. package/template/.pi/skills/yss-openapi/SKILL.md +0 -116
  241. package/template/.pi/skills/yss-openapi/agents/openai.yaml +0 -4
  242. package/template/.pi/skills/yss-openapi/img.png +0 -0
  243. package/template/.pi/skills/yss-openapi/img_1.png +0 -0
  244. package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
  245. package/template/.qoder/skills/yss-openapi/SKILL.md +0 -116
  246. package/template/.qoder/skills/yss-openapi/agents/openai.yaml +0 -4
  247. package/template/.qoder/skills/yss-openapi/img.png +0 -0
  248. package/template/.qoder/skills/yss-openapi/img_1.png +0 -0
  249. package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
  250. package/template/.trae/skills/yss-openapi/SKILL.md +0 -116
  251. package/template/.trae/skills/yss-openapi/agents/openai.yaml +0 -4
  252. package/template/.trae/skills/yss-openapi/img.png +0 -0
  253. package/template/.trae/skills/yss-openapi/img_1.png +0 -0
@@ -175,7 +175,7 @@ skills 是让 AI 按规程工作的“操作手册”,不是关键词装饰。
175
175
  - 因为是 YSS 项目就一次性加载所有 YSS skills。
176
176
  - 把 `需求澄清` 用来重复机会探索,而不是在正式变更中做技术方案。
177
177
  - 有 UI 的功能从 Spec 初稿直接跳 OpenAPI,跳过页面、原型、状态矩阵和 `prototype-review`。
178
- - 在 OpenAPI Freeze 前让 `yss-openapi` 生成生产客户端。
178
+ - 在 OpenAPI Freeze 前将 Draft YAML 或手工 JSON 用作生产客户端输入。
179
179
 
180
180
  ### 1.5.4 如何使用 agents
181
181
 
@@ -804,7 +804,7 @@ TDD 顺序示例:
804
804
  | 持久化 | `yss-repository`、需要分页/批量/数据源时加 `yss-mybatis` |
805
805
  | Web 接口 | `yss-web-controller`、`yss-dto` |
806
806
  | 前端页面 | `yss-ui`、`yss-page-module-development`、`api-integration` |
807
- | OpenAPI client 刷新 | `yss-openapi`,只在 Freeze 后或按实现契约刷新时使用 |
807
+ | OpenAPI client 刷新 | `yss-openapi-governance` 从冻结 YAML 派生 JSON,随后 `api-integration` 运行 Orval;只在 Freeze 后或按实现契约刷新时使用 |
808
808
 
809
809
  阶段门禁:
810
810
 
@@ -1071,7 +1071,7 @@ docs/user-guide/
1071
1071
  使用 yss-router。
1072
1072
  输入资产:<Spec 路径>、<交互设计路径>、<OpenAPI Freeze 路径或无 API 影响记录>、<架构设计路径>、<垂直切片路径>。
1073
1073
  目标:选择最小 YSS 技能集。
1074
- 请说明每个候选技能需要或不需要的理由,尤其是 yss-domain、yss-repository、yss-mybatis、yss-web-controller、yss-ui、api-integration、yss-openapi。
1074
+ 请说明每个候选技能需要或不需要的理由,尤其是 yss-domain、yss-repository、yss-mybatis、yss-web-controller、yss-ui、yss-openapi-governance、api-integration。
1075
1075
  边界:不要实现代码,只输出技能路由、实施顺序、测试 seam 和验证建议。
1076
1076
  ```
1077
1077
 
@@ -114,4 +114,4 @@ YSS_SPEC_TEMPLATE_REF=<pinned-commit> npm test
114
114
  YSS_SPEC_TEMPLATE_REF=<pinned-commit> npm pack --dry-run
115
115
  ```
116
116
 
117
- 发布顺序为:模板修复与验证 → CLI 绑定 commit 并完成跨仓库测试 → 独立审查 → 发布 CLI `2.1.0`。任一仓库未通过共同验证时,不声明整体可发布。
117
+ 发布顺序为:模板修复与验证 → CLI 绑定 commit 并完成跨仓库测试 → 独立审查 → 发布 CLI `2.1.4`。任一仓库未通过共同验证时,不声明整体可发布。
@@ -258,7 +258,7 @@ Competitive Matrix
258
258
 
259
259
  | 场景 | 主技能 | 常见补充 |
260
260
  |---|---|---|
261
- | 新建完整 Vue 业务页面 | `yss-ui` | `yss-page-module-development`、`api-integration`、`yss-openapi` |
261
+ | 新建完整 Vue 业务页面 | `yss-ui` | `yss-page-module-development`、`yss-openapi-governance`、`api-integration` |
262
262
  | YTable / YTree / YssFormily 页面 | `yss-ui` | `yss-use-table-height`、`yss-use-tree-height`、`yss-formily` |
263
263
  | 从零创建后端服务 | `yss-ddd-scaffold-generator` | 后续接 `yss-domain`、`yss-repository`、`yss-web-controller` |
264
264
  | 领域建模和状态规则 | `yss-domain` | `yss-backend-scaffold-domain` |
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "optparse"
5
+ require_relative "lifecycle-registry"
6
+
7
+ options = { check: false, write: false, registry: LifecycleRegistry::DEFAULT_REGISTRY }
8
+ OptionParser.new do |parser|
9
+ parser.on("--check", "仅校验派生文档是否与注册表一致") { options[:check] = true }
10
+ parser.on("--write", "写入派生文档的受管结构区") { options[:write] = true }
11
+ parser.on("--registry PATH", "使用指定注册表") { |path| options[:registry] = Pathname.new(path) }
12
+ end.parse!
13
+
14
+ abort("--check 与 --write 不能同时使用") if options[:check] && options[:write]
15
+
16
+ registry = LifecycleRegistry.validate!(LifecycleRegistry.load_registry(options[:registry]))
17
+ targets = [
18
+ [LifecycleRegistry::ROOT.join("docs/process/lifecycle-artifact-map.md"), "<!-- lifecycle-registry:structure:start -->", "<!-- lifecycle-registry:structure:end -->", LifecycleRegistry.render_lifecycle_structure(registry)],
19
+ [LifecycleRegistry::ROOT.join("docs/process/harness-work-unit-map.md"), "<!-- lifecycle-registry:work-units:start -->", "<!-- lifecycle-registry:work-units:end -->", LifecycleRegistry.render_work_units(registry)]
20
+ ]
21
+
22
+ targets.each do |path, start_marker, end_marker, rendered|
23
+ LifecycleRegistry.replace_region!(path, start_marker, end_marker, rendered, check: options[:check])
24
+ end
25
+
26
+ puts(options[:check] ? "生命周期派生产物与注册表一致" : "生命周期派生产物已更新")
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "pathname"
5
+ require "json"
6
+ require "digest"
7
+ require "yaml"
8
+
9
+ module LifecycleRegistry
10
+ ROOT = Pathname.new(__dir__).join("..").realpath
11
+ DEFAULT_REGISTRY = ROOT.join("docs/process/lifecycle-registry.yaml")
12
+ DEFAULT_BASELINE = ROOT.join("docs/process/lifecycle-registry-baseline.json")
13
+ ID_PATTERN = /\A(stage|gate|artifact|work-unit|evidence)\.[a-z0-9][a-z0-9-]*\z/
14
+
15
+ module_function
16
+
17
+ def load_registry(path = DEFAULT_REGISTRY)
18
+ YAML.safe_load(Pathname.new(path).read, permitted_classes: [], aliases: false)
19
+ rescue Psych::Exception => error
20
+ raise ArgumentError, "无法解析生命周期注册表: #{error.message}"
21
+ end
22
+
23
+ def validate!(registry, baseline: DEFAULT_BASELINE)
24
+ required_top_level = %w[schema_version registry_id status id_policy stages gates artifacts work_units evidence]
25
+ missing = required_top_level - registry.keys
26
+ raise ArgumentError, "生命周期注册表缺少字段: #{missing.join(', ')}" unless missing.empty?
27
+ raise ArgumentError, "仅支持 lifecycle registry schema_version: 1" unless registry["schema_version"] == 1
28
+ raise ArgumentError, "registry_id 必须为 yss.lifecycle" unless registry["registry_id"] == "yss.lifecycle"
29
+ raise ArgumentError, "status 必须为 shadow 或 active" unless %w[shadow active].include?(registry["status"])
30
+
31
+ policy = registry.fetch("id_policy")
32
+ %w[pattern published_ids_immutable baseline deprecated_ids].each do |key|
33
+ raise ArgumentError, "id_policy 缺少字段: #{key}" unless policy.key?(key)
34
+ end
35
+ raise ArgumentError, "published_ids_immutable 必须为 true" unless policy["published_ids_immutable"] == true
36
+ raise ArgumentError, "id_policy.pattern 不符合固定命名空间" unless policy["pattern"] == "^(stage|gate|artifact|work-unit|evidence)\\.[a-z0-9][a-z0-9-]*$"
37
+ raise ArgumentError, "id_policy.baseline 必须指向发布基线" unless policy["baseline"] == "docs/process/lifecycle-registry-baseline.json"
38
+ raise ArgumentError, "deprecated_ids 必须是数组" unless policy["deprecated_ids"].is_a?(Array)
39
+
40
+ ids = {}
41
+ %w[stages gates artifacts work_units evidence].each do |collection|
42
+ records = registry.fetch(collection)
43
+ raise ArgumentError, "#{collection} 必须是非空数组" unless records.is_a?(Array) && !records.empty?
44
+ records.each do |record|
45
+ id = record["id"]
46
+ raise ArgumentError, "#{collection} 中存在无效 ID: #{id.inspect}" unless id.is_a?(String) && id.match?(ID_PATTERN)
47
+ raise ArgumentError, "生命周期 ID 重复: #{id}" if ids.key?(id)
48
+ expected_prefix = collection == "work_units" ? "work-unit." : collection.delete_suffix("s") + "."
49
+ raise ArgumentError, "#{id} 与 #{collection} 类型不匹配" unless id.start_with?(expected_prefix)
50
+ raise ArgumentError, "#{id} 缺少名称" unless record["name"].is_a?(String) && !record["name"].empty?
51
+ ids[id] = collection
52
+ end
53
+ end
54
+
55
+ registry.fetch("gates").each do |gate|
56
+ require_reference!(ids, gate.fetch("stage"), "#{gate["id"]}.stage")
57
+ unless ids[gate.fetch("stage")] == "stages"
58
+ raise ArgumentError, "#{gate["id"]}.stage 必须引用 stage.*"
59
+ end
60
+ evidence = gate.fetch("evidence")
61
+ raise ArgumentError, "#{gate["id"]}.evidence 必须是非空数组" unless evidence.is_a?(Array) && !evidence.empty?
62
+ evidence.each do |reference|
63
+ require_reference!(ids, reference, "#{gate["id"]}.evidence")
64
+ raise ArgumentError, "#{gate["id"]}.evidence 必须引用 evidence.*" unless ids[reference] == "evidence"
65
+ end
66
+ end
67
+
68
+ registry.fetch("artifacts").each do |artifact|
69
+ require_reference!(ids, artifact.fetch("stage"), "#{artifact["id"]}.stage")
70
+ raise ArgumentError, "#{artifact["id"]}.stage 必须引用 stage.*" unless ids[artifact.fetch("stage")] == "stages"
71
+ end
72
+ validate_baseline!(registry, ids, Pathname.new(baseline)) if baseline
73
+ registry
74
+ end
75
+
76
+ def require_reference!(ids, reference, field)
77
+ raise ArgumentError, "#{field} 引用了不存在的引用: #{reference}" unless ids.key?(reference)
78
+ end
79
+
80
+ def semantic_projection(registry)
81
+ %w[stages gates artifacts work_units evidence].flat_map do |collection|
82
+ registry.fetch(collection).map do |record|
83
+ {
84
+ "kind" => collection,
85
+ "record" => canonicalize(record)
86
+ }
87
+ end
88
+ end.sort_by { |entry| entry.fetch("record").fetch("id") }
89
+ end
90
+
91
+ def canonicalize(value)
92
+ case value
93
+ when Hash
94
+ value.keys.sort.to_h { |key| [key, canonicalize(value.fetch(key))] }
95
+ when Array
96
+ value.map { |item| canonicalize(item) }
97
+ else
98
+ value
99
+ end
100
+ end
101
+
102
+ def semantic_digest(registry)
103
+ Digest::SHA256.hexdigest(JSON.generate(semantic_projection(registry)))
104
+ end
105
+
106
+ def validate_baseline!(registry, ids, baseline_path)
107
+ raise ArgumentError, "缺少生命周期已发布基线: #{baseline_path.relative_path_from(ROOT)}" unless baseline_path.file?
108
+ baseline = JSON.parse(baseline_path.read)
109
+ unless baseline["schema_version"] == 1 && baseline["registry_id"] == registry["registry_id"]
110
+ raise ArgumentError, "生命周期已发布基线版本或 registry_id 不匹配"
111
+ end
112
+ published_ids = baseline["published_ids"]
113
+ raise ArgumentError, "生命周期已发布基线缺少 published_ids" unless published_ids.is_a?(Array) && published_ids.uniq == published_ids
114
+ published_ids.each do |id|
115
+ raise ArgumentError, "生命周期已发布基线包含无效 ID: #{id.inspect}" unless id.is_a?(String) && id.match?(ID_PATTERN)
116
+ end
117
+
118
+ active_ids = ids.keys.sort
119
+ deprecated_ids = registry.fetch("id_policy").fetch("deprecated_ids")
120
+ unless deprecated_ids.uniq == deprecated_ids && deprecated_ids.all? { |id| published_ids.include?(id) } && (deprecated_ids & active_ids).empty?
121
+ raise ArgumentError, "deprecated_ids 必须唯一、来自已发布 ID,且不得仍为活跃对象"
122
+ end
123
+ expected_active_ids = (published_ids - deprecated_ids).sort
124
+ raise ArgumentError, "生命周期活跃 ID 与已发布基线不一致;新增、移除或弃用必须先更新发布基线" unless active_ids == expected_active_ids
125
+ raise ArgumentError, "生命周期稳定 ID 的语义快照已变化;不得复用已发布 ID" unless baseline["semantic_sha256"] == semantic_digest(registry)
126
+ rescue JSON::ParserError => error
127
+ raise ArgumentError, "无法解析生命周期已发布基线: #{error.message}"
128
+ end
129
+
130
+ def render_lifecycle_structure(registry)
131
+ lines = []
132
+ lines << "<!-- lifecycle-registry:structure:start -->"
133
+ lines << "> 此结构区由 `docs/process/lifecycle-registry.yaml` 生成。当前为 `#{registry.fetch("status")}` 模式:它校验结构和派生文档,不改变运行时状态 schema 或人工批准语义。"
134
+ lines << ""
135
+ lines << "## 1. 主阶段"
136
+ lines << ""
137
+ lines << "| 稳定 ID | 阶段 | 目标 | 退出标准 |"
138
+ lines << "|---|---|---|---|"
139
+ registry.fetch("stages").each { |stage| lines << "| `#{stage["id"]}` | #{stage["name"]} | #{stage["goal"]} | #{stage["exit_criteria"]} |" }
140
+ lines << ""
141
+ lines << "## 2. 生命周期对象"
142
+ lines << ""
143
+ lines << "门禁是需要裁决的审查点;产物、工作单元和证据不是门禁的同义词。未命中条件的门禁记录 `not-applicable` 及原因,不生成空文档。"
144
+ lines << ""
145
+ lines << "### 2.1 条件门禁"
146
+ lines << ""
147
+ lines << "| 稳定 ID | 门禁 | 所属阶段 | 触发条件 | 必须留下的证据 |"
148
+ lines << "|---|---|---|---|---|"
149
+ registry.fetch("gates").each do |gate|
150
+ evidence = gate.fetch("evidence").map { |id| "`#{id}`" }.join("、")
151
+ lines << "| `#{gate["id"]}` | #{gate["name"]} | `#{gate["stage"]}` | #{gate["trigger"]} | #{evidence} |"
152
+ end
153
+ lines << ""
154
+ lines << "### 2.2 生命周期产物"
155
+ lines << ""
156
+ lines << "| 稳定 ID | 产物 | 所属阶段 | 触发条件 |"
157
+ lines << "|---|---|---|---|"
158
+ registry.fetch("artifacts").each { |artifact| lines << "| `#{artifact["id"]}` | #{artifact["name"]} | `#{artifact["stage"]}` | #{artifact["trigger"]} |" }
159
+ lines << ""
160
+ lines << "### 2.3 执行证据"
161
+ lines << ""
162
+ lines << "| 稳定 ID | 证据 | 说明 |"
163
+ lines << "|---|---|---|"
164
+ registry.fetch("evidence").each { |evidence| lines << "| `#{evidence["id"]}` | #{evidence["name"]} | #{evidence["description"]} |" }
165
+ lines << "<!-- lifecycle-registry:structure:end -->"
166
+ lines.join("\n") + "\n"
167
+ end
168
+
169
+ def render_work_units(registry)
170
+ lines = []
171
+ lines << "<!-- lifecycle-registry:work-units:start -->"
172
+ lines << "> 此表由 `docs/process/lifecycle-registry.yaml` 生成;它只描述 `template-source` 的 Harness 工作单元。"
173
+ lines << ""
174
+ lines << "| 稳定 ID | 工作单元 | 输入 | 输出 | 完成条件 |"
175
+ lines << "|---|---|---|---|---|"
176
+ registry.fetch("work_units").each do |unit|
177
+ lines << "| `#{unit["id"]}` | #{unit["name"]} | #{unit["input"]} | #{unit["output"]} | #{unit["completion"]} |"
178
+ end
179
+ lines << "<!-- lifecycle-registry:work-units:end -->"
180
+ lines.join("\n") + "\n"
181
+ end
182
+
183
+ def replace_region!(path, start_marker, end_marker, replacement, check: false)
184
+ body = path.read
185
+ expression = /#{Regexp.escape(start_marker)}.*?#{Regexp.escape(end_marker)}\n?/m
186
+ raise ArgumentError, "派生文档缺少生成区: #{path.relative_path_from(ROOT)}" unless body.match?(expression)
187
+ expected = body.sub(expression, replacement)
188
+ if check
189
+ raise ArgumentError, "派生文档与注册表漂移: #{path.relative_path_from(ROOT)};运行 scripts/generate-lifecycle-artifacts --write" unless expected == body
190
+ else
191
+ path.write(expected)
192
+ end
193
+ end
194
+ end
@@ -38,6 +38,7 @@ OBSOLETE_SKILLS = %w[
38
38
  yss-quality
39
39
  yss-sql-condition
40
40
  yss-sql-tpl
41
+ yss-openapi
41
42
  ].freeze
42
43
 
43
44
  def skill_names(root)
@@ -18,6 +18,7 @@ REMOVED_SKILLS = %w[
18
18
  yss-quality
19
19
  yss-sql-condition
20
20
  yss-sql-tpl
21
+ yss-openapi
21
22
  ].freeze
22
23
 
23
24
  class ExportYssSkillsTest < Minitest::Test
@@ -31,19 +32,19 @@ class ExportYssSkillsTest < Minitest::Test
31
32
  stdout, stderr, result = run_export(output)
32
33
 
33
34
  assert result.success?, "#{stdout}\n#{stderr}"
34
- assert_equal 46, Dir.glob(output.join("skills", "*").to_s).count { |path| File.directory?(path) }
35
+ assert_equal 44, Dir.glob(output.join("skills", "*").to_s).count { |path| File.directory?(path) }
35
36
 
36
37
  manifest = JSON.parse(output.join(".yss-export-manifest.json").read)
37
- assert_equal 46, manifest.fetch("skills").length
38
- assert_operator manifest.fetch("generated_files_sha256").length, :>, 46
38
+ assert_equal 44, manifest.fetch("skills").length
39
+ assert_operator manifest.fetch("generated_files_sha256").length, :>, 44
39
40
  REMOVED_SKILLS.each do |skill_name|
40
41
  refute output.join("skills", skill_name).exist?, "removed skill was exported: #{skill_name}"
41
42
  end
42
43
 
43
44
  page = JSON.parse(output.join("skills.sh.json").read)
44
45
  grouped = page.fetch("groupings").flat_map { |group| group.fetch("skills") }
45
- assert_equal 46, grouped.uniq.length
46
- assert_equal 46, grouped.length
46
+ assert_equal 44, grouped.uniq.length
47
+ assert_equal 44, grouped.length
47
48
 
48
49
  exported_text = Dir.glob(output.join("skills", "**", "*").to_s)
49
50
  .select { |path| File.file?(path) }
@@ -51,7 +52,8 @@ class ExportYssSkillsTest < Minitest::Test
51
52
  .select(&:valid_encoding?)
52
53
  .join("\n")
53
54
  REMOVED_SKILLS.each do |skill_name|
54
- refute_match(/\b#{Regexp.escape(skill_name)}\b/, exported_text, "removed skill is still referenced: #{skill_name}")
55
+ pattern = Regexp.new("(?<![a-z0-9-])#{Regexp.escape(skill_name)}(?![a-z0-9-])")
56
+ refute_match(pattern, exported_text, "removed skill is still referenced: #{skill_name}")
55
57
  end
56
58
 
57
59
  formily_examples = output.join("skills", "yss-formily", "references", "examples.md").read
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "minitest/autorun"
5
+ require "open3"
6
+ require "pathname"
7
+ require "tmpdir"
8
+ require "yaml"
9
+
10
+ ROOT = Pathname.new(__dir__).join("..").realpath
11
+
12
+ class LifecycleRegistryTest < Minitest::Test
13
+ def run_command(*command)
14
+ output, status = Open3.capture2e(*command, chdir: ROOT)
15
+ [output, status]
16
+ end
17
+
18
+ def test_registry_verifier_and_generated_views_are_current
19
+ output, status = run_command("scripts/verify-lifecycle-registry")
20
+ assert status.success?, output
21
+
22
+ output, status = run_command("scripts/generate-lifecycle-artifacts", "--check")
23
+ assert status.success?, output
24
+ end
25
+
26
+ def test_verifier_rejects_unknown_cross_reference
27
+ Dir.mktmpdir("yss-lifecycle-registry") do |directory|
28
+ registry_path = Pathname.new(directory).join("broken.yaml")
29
+ registry = YAML.safe_load(ROOT.join("docs/process/lifecycle-registry.yaml").read, aliases: false)
30
+ registry.fetch("gates").first.fetch("evidence") << "evidence.unknown"
31
+ registry_path.write(YAML.dump(registry))
32
+
33
+ output, status = run_command("scripts/verify-lifecycle-registry", "--registry", registry_path.to_s)
34
+ refute status.success?, output
35
+ assert_includes output, "不存在的引用"
36
+ end
37
+ end
38
+
39
+ def test_verifier_executes_json_schema_and_stable_id_baseline
40
+ Dir.mktmpdir("yss-lifecycle-registry") do |directory|
41
+ schema_broken = Pathname.new(directory).join("schema-broken.yaml")
42
+ semantic_broken = Pathname.new(directory).join("semantic-broken.yaml")
43
+ registry = YAML.safe_load(ROOT.join("docs/process/lifecycle-registry.yaml").read, aliases: false)
44
+
45
+ registry.fetch("stages").first.delete("goal")
46
+ schema_broken.write(YAML.dump(registry))
47
+ output, status = run_command("scripts/verify-lifecycle-registry", "--registry", schema_broken.to_s)
48
+ refute status.success?, output
49
+ assert_includes output, "JSON Schema 校验失败"
50
+
51
+ registry = YAML.safe_load(ROOT.join("docs/process/lifecycle-registry.yaml").read, aliases: false)
52
+ registry.fetch("gates").first["trigger"] = "被静默改变的语义。"
53
+ semantic_broken.write(YAML.dump(registry))
54
+ output, status = run_command("scripts/verify-lifecycle-registry", "--registry", semantic_broken.to_s)
55
+ refute status.success?, output
56
+ assert_includes output, "语义快照已变化"
57
+ end
58
+ end
59
+
60
+ def test_policy_documents_do_not_reintroduce_stale_counts
61
+ forbidden_count = /\d+\s*个(?:主阶段|门禁|工作单元|职责点)/
62
+ assert_match forbidden_count, "必须按 8 个主阶段推进"
63
+
64
+ [
65
+ "AGENTS.md",
66
+ "README.md",
67
+ "docs/user-guide/产品生命周期工作流.md",
68
+ ".agents/skills/yss-product-lifecycle/SKILL.md"
69
+ ].each do |relative_path|
70
+ body = ROOT.join(relative_path).read
71
+ refute_match(forbidden_count, body, relative_path)
72
+ end
73
+ end
74
+ end
@@ -37,6 +37,7 @@ OBSOLETE_SKILLS = %w[
37
37
  yss-quality
38
38
  yss-sql-condition
39
39
  yss-sql-tpl
40
+ yss-openapi
40
41
  ].freeze
41
42
  LOCK_GROUPS = %w[shared platform].freeze
42
43
  GIT_WORKTREE = system(
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "pathname"
6
+ require "yaml"
7
+
8
+ ROOT = Pathname.new(__dir__).join("..").realpath
9
+ failures = []
10
+
11
+ {
12
+ "docs/architecture/templates/system-overview-design-template.md" => "已明确的认证、授权、租户隔离、敏感数据或合规行为",
13
+ "docs/architecture/templates/tech-design-template.md" => "已明确的认证、授权、租户隔离、敏感数据或合规行为"
14
+ }.each do |relative_path, marker|
15
+ body = ROOT.join(relative_path).read
16
+ failures << "#{relative_path} 缺少条件性安全/权限架构承载" unless body.include?(marker)
17
+ end
18
+
19
+ {
20
+ "docs/adr/0003-machine-readable-lifecycle-registry.md" => "状态:部分实施(Phase 1)",
21
+ "docs/adr/0004-split-lifecycle-and-router-registry-domains.md" => "状态:proposed",
22
+ "docs/adr/0005-cross-repository-ecosystem-release-manifest.md" => "状态:proposed",
23
+ "docs/adr/0006-stable-lifecycle-ids-and-generated-structure.md" => "状态:部分实施(Phase 1)",
24
+ "docs/adr/0007-separate-skill-routing-registry-from-integrity-lock.md" => "状态:proposed"
25
+ }.each do |relative_path, marker|
26
+ body = ROOT.join(relative_path).read
27
+ failures << "#{relative_path} 未声明当前实现状态" unless body.include?(marker)
28
+ end
29
+
30
+ scenario_verifier = ROOT.join("scripts/verify-lifecycle-scenarios").read
31
+ failures << "生命周期场景未校验稳定 ID 映射" unless scenario_verifier.include?("ROUTE_REGISTRY_IDS")
32
+
33
+ unless failures.empty?
34
+ warn failures.join("\n")
35
+ exit 1
36
+ end
37
+
38
+ warn failures.join("\n") unless failures.empty?
39
+ exit(failures.empty? ? 0 : 1)
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "open3"
6
+ require "optparse"
7
+ require_relative "lifecycle-registry"
8
+
9
+ options = { registry: LifecycleRegistry::DEFAULT_REGISTRY }
10
+ OptionParser.new do |parser|
11
+ parser.on("--registry PATH", "使用指定注册表") { |path| options[:registry] = Pathname.new(path) }
12
+ end.parse!
13
+
14
+ begin
15
+ schema_path = LifecycleRegistry::ROOT.join("docs/process/schemas/lifecycle-registry.schema.json")
16
+ schema = JSON.parse(schema_path.read)
17
+ raise ArgumentError, "生命周期注册表 JSON Schema 缺少 schema_version 约束" unless schema.dig("properties", "schema_version", "const") == 1
18
+ json_schema_program = <<~'PYTHON'
19
+ import json
20
+ import sys
21
+ from jsonschema import Draft202012Validator
22
+
23
+ with open(sys.argv[1], encoding="utf-8") as schema_file:
24
+ schema = json.load(schema_file)
25
+ registry = json.load(sys.stdin)
26
+ errors = sorted(Draft202012Validator(schema).iter_errors(registry), key=lambda error: list(error.absolute_path))
27
+ if errors:
28
+ for error in errors:
29
+ location = ".".join(str(part) for part in error.absolute_path) or "<root>"
30
+ print(f"{location}: {error.message}", file=sys.stderr)
31
+ sys.exit(1)
32
+ PYTHON
33
+ registry_json = JSON.generate(LifecycleRegistry.load_registry(options[:registry]))
34
+ output, status = Open3.capture2e("python3", "-c", json_schema_program, schema_path.to_s, stdin_data: registry_json)
35
+ raise ArgumentError, "JSON Schema 校验失败: #{output}" unless status.success?
36
+ registry = LifecycleRegistry.validate!(LifecycleRegistry.load_registry(options[:registry]))
37
+
38
+ if options[:registry] == LifecycleRegistry::DEFAULT_REGISTRY
39
+ command = [LifecycleRegistry::ROOT.join("scripts/generate-lifecycle-artifacts").to_s, "--check"]
40
+ output, status = Open3.capture2e(*command, chdir: LifecycleRegistry::ROOT)
41
+ raise ArgumentError, output unless status.success?
42
+
43
+ tracked_sources = %w[docs/process/lifecycle-registry.yaml docs/process/lifecycle-registry-baseline.json docs/process/schemas/lifecycle-registry.schema.json]
44
+ tracked_sources.each do |relative_path|
45
+ _output, ignored = Open3.capture2e("git", "check-ignore", "-q", relative_path, chdir: LifecycleRegistry::ROOT)
46
+ raise ArgumentError, "权威注册表资产不得被 Git 忽略: #{relative_path}" if ignored.success?
47
+ end
48
+
49
+ stale_count_paths = %w[AGENTS.md README.md docs/user-guide/产品生命周期工作流.md .agents/skills/yss-product-lifecycle/SKILL.md docs/process/lifecycle-artifact-map.md docs/process/harness-work-unit-map.md]
50
+ stale_count_paths.each do |relative_path|
51
+ body = LifecycleRegistry::ROOT.join(relative_path).read
52
+ if body.match?(/\d+\s*个(?:主阶段|门禁|工作单元|职责点)/)
53
+ raise ArgumentError, "#{relative_path} 不得手工声明生命周期对象数量;请引用 lifecycle-registry.yaml"
54
+ end
55
+ end
56
+
57
+ public_skills = JSON.parse(LifecycleRegistry::ROOT.join("yss-public-skills.json").read)
58
+ groups = public_skills.fetch("groupings").to_h { |group| [group.fetch("title"), group.fetch("skills")] }
59
+ raise ArgumentError, "yss-web-controller 必须在后端分组" unless groups.fetch("后端").include?("yss-web-controller")
60
+ raise ArgumentError, "yss-web-controller 不得在前端分组" if groups.fetch("前端").include?("yss-web-controller")
61
+ end
62
+
63
+ puts "生命周期注册表验证通过(#{registry.fetch("status")})"
64
+ rescue ArgumentError, KeyError, JSON::ParserError => error
65
+ warn "生命周期注册表验证失败: #{error.message}"
66
+ exit 1
67
+ end