create-yss-spec 2.1.3 → 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 +27 -3
  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
@@ -0,0 +1,270 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "digest"
5
+ require "json"
6
+ require "tmpdir"
7
+ require "yaml"
8
+
9
+ # This validates the YAML-to-JSON handoff contract rather than invoking
10
+ # Redocly or any frontend generator. These fixtures prove that a JSON
11
+ # derivative preserves the frozen OpenAPI semantics and can be handed to an
12
+ # implementation repository as unchanged bytes.
13
+ module OpenapiJsonHandoff
14
+ module_function
15
+
16
+ def validate!(source_yaml:, source_json:, materialized_json:, handoff:, **_unused)
17
+ validate_source_paths!(handoff)
18
+ assert!(handoff.fetch("freeze_status") == "approved", "OpenAPI Freeze 未批准")
19
+ assert!(handoff.fetch("export_status") == "exported", "JSON 导出未完成")
20
+ assert!(!handoff.fetch("freeze_record").to_s.empty?, "缺少 OpenAPI Freeze 记录")
21
+ assert!(!handoff.fetch("export_record").to_s.empty?, "缺少 OpenAPI JSON 派生记录")
22
+
23
+ yaml_documents = YAML.load_stream(File.binread(source_yaml).force_encoding("UTF-8"))
24
+ assert!(yaml_documents.length == 1, "YAML 必须是单一 document")
25
+ assert!(yaml_documents.first.is_a?(Hash) && yaml_documents.first["openapi"] == "3.1.0", "YAML 必须是 OAS 3.1")
26
+
27
+ json_document = JSON.parse(File.binread(source_json))
28
+ assert!(json_document["openapi"] == "3.1.0", "JSON 必须是 OAS 3.1")
29
+ validate_operation_contract!(yaml_documents.first, json_document)
30
+ validate_json_refs!(json_document)
31
+ assert!(Digest::SHA256.file(source_yaml).hexdigest == handoff.fetch("yaml_sha256"), "YAML SHA-256 不匹配")
32
+ assert!(Digest::SHA256.file(source_json).hexdigest == handoff.fetch("json_sha256"), "JSON SHA-256 不匹配")
33
+ assert!(Digest::SHA256.file(materialized_json).hexdigest == handoff.fetch("json_sha256"), "前端物化 JSON 与导出记录不一致")
34
+
35
+ bundle_command = handoff.fetch("bundle_command")
36
+ %w[pnpm\ exec\ redocly\ bundle --ext\ json --component-renaming-conflicts-severity=error].each do |marker|
37
+ assert!(bundle_command.include?(marker), "bundle 命令缺少 #{marker}")
38
+ end
39
+ assert!(bundle_command.include?(handoff.fetch("source_yaml")), "bundle 命令未使用冻结 YAML")
40
+ assert!(bundle_command.include?(handoff.fetch("source_json")), "bundle 命令未写入记录的 JSON")
41
+ assert!(!bundle_command.match?(/(?:\bmvn\b|smart[ _-]?doc)/i), "bundle 命令包含已移除的 Maven OpenAPI 链路")
42
+
43
+ end
44
+
45
+ def validate_operation_contract!(yaml_document, json_document)
46
+ yaml_operations = operation_contracts(yaml_document)
47
+ json_operations = operation_contracts(json_document)
48
+ assert!(!yaml_operations.empty?, "YAML 缺少可生成客户端的操作")
49
+ assert!(yaml_operations == json_operations, "JSON 未保留 YAML 的路径、方法、operationId、请求或响应契约")
50
+ ids = yaml_operations.values.map { |contract| contract.fetch("operationId") }
51
+ assert!(ids.all? { |operation_id| operation_id.is_a?(String) && !operation_id.empty? }, "operationId 必须为非空字符串")
52
+ assert!(ids.uniq.length == ids.length, "operationId 必须唯一")
53
+ end
54
+
55
+ def operation_contracts(document)
56
+ methods = %w[get put post delete options head patch trace]
57
+ paths = document.fetch("paths", {})
58
+ paths.each_with_object({}) do |(path, path_item), operations|
59
+ next unless path_item.is_a?(Hash)
60
+
61
+ path_item.each do |method, operation|
62
+ next unless methods.include?(method.to_s.downcase) && operation.is_a?(Hash)
63
+
64
+ operations["#{method.to_s.upcase} #{path}"] = {
65
+ "operationId" => operation["operationId"],
66
+ "parameters" => operation.fetch("parameters", []),
67
+ "requestBody" => operation["requestBody"],
68
+ "responses" => operation.fetch("responses", {})
69
+ }
70
+ end
71
+ end
72
+ end
73
+
74
+ def validate_json_refs!(document)
75
+ refs = []
76
+ collect_refs(document, refs)
77
+ refs.each do |ref|
78
+ assert!(ref.start_with?("#/"), "JSON 不得包含外部或远程 $ref: #{ref}")
79
+ resolve_json_pointer!(document, ref)
80
+ end
81
+ end
82
+
83
+ def collect_refs(value, refs)
84
+ case value
85
+ when Hash
86
+ refs << value["$ref"] if value["$ref"].is_a?(String)
87
+ value.each_value { |child| collect_refs(child, refs) }
88
+ when Array
89
+ value.each { |child| collect_refs(child, refs) }
90
+ end
91
+ end
92
+
93
+ def resolve_json_pointer!(document, ref)
94
+ ref.delete_prefix("#/").split("/").reduce(document) do |node, segment|
95
+ key = segment.gsub("~1", "/").gsub("~0", "~")
96
+ assert!(node.is_a?(Hash) && node.key?(key), "JSON $ref 无法解析: #{ref}")
97
+ node.fetch(key)
98
+ end
99
+ end
100
+
101
+ def validate_source_paths!(handoff)
102
+ yaml_path = handoff.fetch("source_yaml")
103
+ json_path = handoff.fetch("source_json")
104
+ match = %r{\Adocs/\.scratch/([^/]+)/api/([^/]+)\.yaml\z}.match(yaml_path)
105
+ assert!(!match.nil? && match[1] == match[2], "冻结 YAML 路径不符合 feature 约定")
106
+ assert!(json_path == "docs/.scratch/#{match[1]}/api/#{match[2]}.json", "JSON 必须与冻结 YAML 同 feature 同目录")
107
+ end
108
+
109
+ def assert!(condition, message)
110
+ raise ArgumentError, message unless condition
111
+ end
112
+ end
113
+
114
+ def build_context(root)
115
+ feature = "order"
116
+ api_dir = File.join(root, "docs", ".scratch", feature, "api")
117
+ frontend_dir = File.join(root, "frontend", "openapi")
118
+ Dir.mkdir(File.join(root, "docs"))
119
+ Dir.mkdir(File.join(root, "docs", ".scratch"))
120
+ Dir.mkdir(File.join(root, "docs", ".scratch", feature))
121
+ Dir.mkdir(api_dir)
122
+ Dir.mkdir(File.join(root, "frontend"))
123
+ Dir.mkdir(frontend_dir)
124
+
125
+ source_yaml = File.join(api_dir, "#{feature}.yaml")
126
+ source_json = File.join(api_dir, "#{feature}.json")
127
+ materialized_json = File.join(frontend_dir, "openapi.json")
128
+ File.write(source_yaml, <<~YAML)
129
+ openapi: 3.1.0
130
+ info:
131
+ title: Order API
132
+ version: 1.0.0
133
+ paths:
134
+ /api/v1/orders/{orderId}:
135
+ get:
136
+ operationId: getOrder
137
+ parameters:
138
+ - name: orderId
139
+ in: path
140
+ required: true
141
+ schema:
142
+ type: string
143
+ responses:
144
+ '200':
145
+ description: success
146
+ content:
147
+ application/json:
148
+ schema:
149
+ $ref: '#/components/schemas/Order'
150
+ components:
151
+ schemas:
152
+ Order:
153
+ type: object
154
+ required: [id]
155
+ properties:
156
+ id:
157
+ type: string
158
+ YAML
159
+ json_document = {
160
+ "openapi" => "3.1.0",
161
+ "info" => { "title" => "Order API", "version" => "1.0.0" },
162
+ "paths" => {
163
+ "/api/v1/orders/{orderId}" => {
164
+ "get" => {
165
+ "operationId" => "getOrder",
166
+ "parameters" => [{ "name" => "orderId", "in" => "path", "required" => true, "schema" => { "type" => "string" } }],
167
+ "responses" => {
168
+ "200" => {
169
+ "description" => "success",
170
+ "content" => { "application/json" => { "schema" => { "$ref" => "#/components/schemas/Order" } } }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ },
176
+ "components" => {
177
+ "schemas" => {
178
+ "Order" => {
179
+ "type" => "object",
180
+ "required" => ["id"],
181
+ "properties" => { "id" => { "type" => "string" } }
182
+ }
183
+ }
184
+ }
185
+ }
186
+ File.write(source_json, JSON.generate(json_document))
187
+ File.binwrite(materialized_json, File.binread(source_json))
188
+
189
+ source_yaml_path = "docs/.scratch/#{feature}/api/#{feature}.yaml"
190
+ source_json_path = "docs/.scratch/#{feature}/api/#{feature}.json"
191
+ handoff = {
192
+ "freeze_status" => "approved",
193
+ "export_status" => "exported",
194
+ "freeze_record" => "docs/.scratch/#{feature}/api/#{feature}-freeze.md",
195
+ "export_record" => "docs/.scratch/#{feature}/api/#{feature}-json-export.md",
196
+ "source_yaml" => source_yaml_path,
197
+ "source_json" => source_json_path,
198
+ "yaml_sha256" => Digest::SHA256.file(source_yaml).hexdigest,
199
+ "json_sha256" => Digest::SHA256.file(source_json).hexdigest,
200
+ "bundle_command" => "pnpm exec redocly bundle #{source_yaml_path} --output #{source_json_path} --ext json --component-renaming-conflicts-severity=error"
201
+ }
202
+ {
203
+ source_yaml: source_yaml,
204
+ source_json: source_json,
205
+ materialized_json: materialized_json,
206
+ handoff: handoff
207
+ }
208
+ end
209
+
210
+ def expect_rejected(label)
211
+ yield
212
+ raise "负向场景未被阻断: #{label}"
213
+ rescue ArgumentError
214
+ true
215
+ end
216
+
217
+ Dir.mktmpdir("openapi-handoff-") do |root|
218
+ context = build_context(root)
219
+ OpenapiJsonHandoff.validate!(**context)
220
+
221
+ expect_rejected("Draft 不能导出") do
222
+ OpenapiJsonHandoff.validate!(**context.merge(handoff: context.fetch(:handoff).merge("freeze_status" => "draft")))
223
+ end
224
+
225
+ expect_rejected("Maven 链路不能作为导出命令") do
226
+ OpenapiJsonHandoff.validate!(**context.merge(handoff: context.fetch(:handoff).merge("bundle_command" => "mvn package")))
227
+ end
228
+
229
+ expect_rejected("运行时 URL 不能替代治理 JSON") do
230
+ OpenapiJsonHandoff.validate!(**context.merge(handoff: context.fetch(:handoff).merge("source_json" => "https://example.invalid/openapi.json")))
231
+ end
232
+
233
+ original_json = File.binread(context.fetch(:source_json))
234
+
235
+ changed_operation = JSON.parse(original_json)
236
+ changed_operation.fetch("paths").fetch("/api/v1/orders/{orderId}").fetch("get")["operationId"] = "getOtherOrder"
237
+ File.write(context.fetch(:source_json), JSON.generate(changed_operation))
238
+ expect_rejected("JSON 必须保留冻结 YAML 的 operationId") do
239
+ OpenapiJsonHandoff.validate!(**context.merge(handoff: context.fetch(:handoff).merge("json_sha256" => Digest::SHA256.file(context.fetch(:source_json)).hexdigest)))
240
+ end
241
+
242
+ invalid_ref = JSON.parse(original_json)
243
+ invalid_ref.fetch("paths").fetch("/api/v1/orders/{orderId}").fetch("get").fetch("responses").fetch("200").fetch("content").fetch("application/json").fetch("schema")["$ref"] = "#/components/schemas/Missing"
244
+ File.write(context.fetch(:source_json), JSON.generate(invalid_ref))
245
+ expect_rejected("JSON $ref 必须可解析") do
246
+ OpenapiJsonHandoff.validate!(**context.merge(handoff: context.fetch(:handoff).merge("json_sha256" => Digest::SHA256.file(context.fetch(:source_json)).hexdigest)))
247
+ end
248
+
249
+ changed_response = JSON.parse(original_json)
250
+ changed_response.fetch("paths").fetch("/api/v1/orders/{orderId}").fetch("get").fetch("responses").fetch("200").fetch("content").fetch("application/json").fetch("schema")["$ref"] = "#/components/schemas/ChangedOrder"
251
+ changed_response.fetch("components").fetch("schemas")["ChangedOrder"] = { "type" => "string" }
252
+ File.write(context.fetch(:source_json), JSON.generate(changed_response))
253
+ expect_rejected("JSON 必须保留冻结 YAML 的请求和响应契约") do
254
+ OpenapiJsonHandoff.validate!(**context.merge(handoff: context.fetch(:handoff).merge("json_sha256" => Digest::SHA256.file(context.fetch(:source_json)).hexdigest)))
255
+ end
256
+
257
+ File.binwrite(context.fetch(:source_json), original_json)
258
+ File.write(context.fetch(:materialized_json), "{\"openapi\":\"3.1.0\",\"paths\":{\"/tampered\":{}}}")
259
+ expect_rejected("前端 JSON 被手改") do
260
+ OpenapiJsonHandoff.validate!(**context)
261
+ end
262
+
263
+ File.binwrite(context.fetch(:materialized_json), original_json)
264
+ File.write(context.fetch(:source_json), "{\"openapi\":\"3.1.0\",\"paths\":{\"/tampered-source\":{}}}")
265
+ expect_rejected("治理 JSON 被手改") do
266
+ OpenapiJsonHandoff.validate!(**context)
267
+ end
268
+ end
269
+
270
+ puts "OpenAPI YAML-first JSON handoff scenarios passed"
@@ -0,0 +1,120 @@
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
+ PROJECTION_ROOTS = %w[
10
+ .agents/skills
11
+ .claude/skills
12
+ .codex/skills
13
+ .hermes/skills
14
+ .pi/skills
15
+ .qoder/skills
16
+ .trae/skills
17
+ ].freeze
18
+
19
+ failures = []
20
+
21
+ template_path = ROOT.join("docs/templates/openapi-spec-template.yaml")
22
+ documents = YAML.load_stream(template_path.read)
23
+ failures << "OpenAPI YAML 模板必须是单一 YAML document" unless documents.length == 1
24
+ document = documents.first
25
+ unless document.is_a?(Hash) && document["openapi"] == "3.1.0"
26
+ failures << "OpenAPI YAML 模板必须是 OAS 3.1 文档"
27
+ end
28
+ %w[pipeline stage status owner].each do |field|
29
+ failures << "OpenAPI YAML 模板不得把生命周期元数据写入根字段: #{field}" if document.is_a?(Hash) && document.key?(field)
30
+ end
31
+
32
+ PROJECTION_ROOTS.each do |root|
33
+ failures << "已移除的 yss-openapi 仍存在: #{root}/yss-openapi" if ROOT.join(root, "yss-openapi").exist?
34
+ end
35
+
36
+ lock = JSON.parse(ROOT.join("skills-lock.json").read)
37
+ if lock.dig("skills", "shared", "yss-openapi")
38
+ failures << "skills-lock.json 仍登记 yss-openapi"
39
+ end
40
+
41
+ public_skills = JSON.parse(ROOT.join("yss-public-skills.json").read)
42
+ if public_skills.fetch("skills").include?("yss-openapi")
43
+ failures << "yss-public-skills.json 仍公开 yss-openapi"
44
+ end
45
+
46
+ router = ROOT.join(".agents/skills/yss-router/references/router-contract.yaml").read
47
+ removed_skill_pattern = /(?<![a-z0-9-])yss-openapi(?![a-z0-9-])/
48
+ failures << "Router 仍路由到 yss-openapi" if router.match?(removed_skill_pattern)
49
+ failures << "Router 脚手架合同仍允许旧 OpenAPI 基线" if router.include?("smart_doc_baseline")
50
+ unless router.include?("api-integration:\n when_regeneration: [yss-openapi-governance]")
51
+ failures << "Router 未将客户端重新生成路由到 yss-openapi-governance"
52
+ end
53
+
54
+ lifecycle_contract = ROOT.join(".agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml").read
55
+ failures << "Lifecycle 脚手架合同仍允许旧 OpenAPI 基线" if lifecycle_contract.include?("smart_doc_baseline")
56
+ lifecycle_skill = ROOT.join(".agents/skills/yss-product-lifecycle/SKILL.md").read
57
+ failures << "Lifecycle 说明仍保留旧 OpenAPI 基线" if lifecycle_skill.match?(/smart[ -]?doc/i)
58
+ implementation_routing_template = ROOT.join("docs/templates/implementation-routing-template.md").read
59
+ failures << "实现路由模板仍保留旧 OpenAPI 基线" if implementation_routing_template.match?(/smart[ -]?doc/i)
60
+
61
+ scaffold_pom = ROOT.join(".agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template").read
62
+ failures << "后端脚手架仍包含 smart-doc Maven 插件" if scaffold_pom.include?("smart-doc-maven-plugin")
63
+ failures << "后端脚手架仍保留 smart-doc 配置模板" if ROOT.join(".agents/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template").exist?
64
+
65
+ scaffold_generator = ROOT.join(".agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py").read
66
+ failures << "后端脚手架生成器仍生成 smart-doc 配置" if scaffold_generator.include?("smart-doc.json") || scaffold_generator.include?("smart-doc-maven-plugin")
67
+
68
+ governance = ROOT.join(".agents/skills/yss-openapi-governance/SKILL.md").read
69
+ %w[YAML-first 唯一权威 redocly\ bundle --ext\ json operationId].each do |marker|
70
+ failures << "OpenAPI Governance 缺少 YAML-first JSON 派生规则: #{marker}" unless governance.include?(marker)
71
+ end
72
+ failures << "OpenAPI Governance 仍依赖 smart-doc" if governance.include?("smart-doc")
73
+ %w[pnpm\ generate:api orval.config unsafeDisableValidation].each do |marker|
74
+ failures << "OpenAPI Governance 越界到前端代码生成或 Orval 配置: #{marker}" if governance.include?(marker)
75
+ end
76
+
77
+ api_integration = ROOT.join(".agents/skills/yss-api-integration/SKILL.md").read
78
+ %w[冻结的\ OpenAPI\ YAML redocly\ bundle 原样物化 既有前端代码生成流程].each do |marker|
79
+ failures << "API Integration 缺少冻结 JSON 的下游交接规则: #{marker}" unless api_integration.include?(marker)
80
+ end
81
+ failures << "API Integration 仍引用 yss-openapi" if api_integration.match?(removed_skill_pattern)
82
+ %w[docs/.scratch/<feature>/api/<feature>.json SHA-256 受控交接].each do |marker|
83
+ failures << "API Integration 未绑定治理 JSON 派生物: #{marker}" unless api_integration.include?(marker)
84
+ end
85
+ %w[orval.config unsafeDisableValidation].each do |marker|
86
+ failures << "API Integration 越界要求修改或核验 Orval 配置: #{marker}" if api_integration.include?(marker)
87
+ end
88
+
89
+ frontend_scaffold = ROOT.join(".agents/skills/yss-frontend-scaffold-generator/SKILL.md").read
90
+ failures << "前端脚手架仍接受任意 openapi_source" if frontend_scaffold.include?("openapi_source")
91
+ %w[OpenAPI\ Freeze\ 记录 OpenAPI\ JSON\ 派生记录 SHA-256 openapi/openapi.json 既有前端代码生成流程].each do |marker|
92
+ failures << "前端脚手架未绑定冻结 JSON 交接: #{marker}" unless frontend_scaffold.include?(marker)
93
+ end
94
+ %w[配置并读取实际\ `orval.config.*` unsafeDisableValidation].each do |marker|
95
+ failures << "前端脚手架越界修改或核验既有 Orval 配置: #{marker}" if frontend_scaffold.include?(marker)
96
+ end
97
+
98
+ export_record = ROOT.join("docs/api/templates/openapi-json-export-record-template.md")
99
+ failures << "缺少 OpenAPI JSON 派生记录模板" unless export_record.file?
100
+ if export_record.file?
101
+ export_record_text = export_record.read
102
+ %w[Orval\ 输入路径 orval.config unsafeDisableValidation pnpm\ generate:api].each do |marker|
103
+ failures << "JSON 派生记录越界记录前端 Orval 配置或执行: #{marker}" if export_record_text.include?(marker)
104
+ end
105
+ end
106
+
107
+ freeze_record = ROOT.join("docs/api/templates/openapi-freeze-record-template.md")
108
+ %w[orval.config unsafeDisableValidation].each do |marker|
109
+ failures << "OpenAPI Freeze 记录越界规定 Orval 配置: #{marker}" if freeze_record.read.include?(marker)
110
+ end
111
+
112
+ draft_checklist = ROOT.join("docs/api/templates/openapi-draft-review-checklist.md")
113
+ failures << "Draft 评审清单越界要求 Orval 输入路径" if draft_checklist.read.include?("Orval 输入路径")
114
+
115
+ unless failures.empty?
116
+ warn failures.join("\n")
117
+ exit 1
118
+ end
119
+
120
+ puts "OpenAPI YAML-first 场景验证通过"
@@ -29,6 +29,9 @@ required_files=(
29
29
  "AGENTS.md"
30
30
  "CONTEXT.md"
31
31
  "skills-lock.json"
32
+ "docs/process/lifecycle-registry.yaml"
33
+ "docs/process/lifecycle-registry-baseline.json"
34
+ "docs/process/schemas/lifecycle-registry.schema.json"
32
35
  "docs/process/lifecycle-artifact-map.md"
33
36
  "docs/process/harness-process-tailoring.md"
34
37
  "docs/templates/local-parent-ticket-template.md"
@@ -39,11 +42,17 @@ required_files=(
39
42
  "scripts/update-skill-lock"
40
43
  "scripts/implementation-path-policy.rb"
41
44
  "scripts/verify-lifecycle-scenarios"
45
+ "scripts/generate-lifecycle-artifacts"
46
+ "scripts/verify-lifecycle-registry"
47
+ "scripts/test-lifecycle-registry.rb"
48
+ "scripts/verify-governance-release"
42
49
  "scripts/verify-implementation-path-scenarios"
43
50
  "scripts/verify-scaffold-generator-scenarios"
44
51
  "scripts/verify-prototype-backend-scaffold-scenarios"
45
52
  "scripts/verify-matt-yss-integration-scenarios"
46
53
  "scripts/verify-yss-ui-scenarios"
54
+ "scripts/verify-openapi-yaml-first-scenarios"
55
+ "scripts/verify-openapi-json-handoff-scenarios"
47
56
  )
48
57
 
49
58
  required_skills=(
@@ -120,19 +129,28 @@ lock.fetch("skills", {}).fetch("shared", {}).each do |skill_name, metadata|
120
129
  end
121
130
 
122
131
  openapi_path = root.join("docs/templates/openapi-spec-template.yaml")
123
- openapi_text = openapi_path.binread.force_encoding("UTF-8").sub(/\A---\n.*?\n---\n/m, "")
124
- YAML.safe_load(openapi_text, permitted_classes: [], aliases: true)
132
+ documents = YAML.load_stream(openapi_path.binread.force_encoding("UTF-8"))
133
+ unless documents.length == 1 && documents.first.is_a?(Hash) && documents.first["openapi"] == "3.1.0"
134
+ warn "docs/templates/openapi-spec-template.yaml 必须是单一 OAS 3.1 YAML document"
135
+ exit 1
136
+ end
125
137
  RUBY
126
138
 
127
139
  scripts/sync-skills --check
128
140
  scripts/update-skill-lock --check
141
+ scripts/verify-lifecycle-registry
129
142
  scripts/verify-lifecycle-scenarios
143
+ scripts/verify-governance-release
130
144
  scripts/verify-implementation-path-scenarios
131
145
  scripts/verify-scaffold-generator-scenarios
132
146
  scripts/verify-prototype-backend-scaffold-scenarios
133
147
  ruby scripts/verify-matt-yss-integration-scenarios
134
148
  scripts/verify-yss-router-scenarios
135
149
  scripts/verify-yss-ui-scenarios
150
+ scripts/verify-openapi-yaml-first-scenarios
151
+ scripts/verify-openapi-json-handoff-scenarios
152
+ ruby scripts/test-lifecycle-registry.rb
153
+ ruby scripts/test-export-yss-skills.rb
136
154
 
137
155
  ruby <<'RUBY'
138
156
  # encoding: UTF-8
@@ -161,7 +179,8 @@ obsolete_names = [
161
179
  "obsidian-vault",
162
180
  "writing-great-skills",
163
181
  "code-review-process",
164
- "yss-domain-modeling"
182
+ "yss-domain-modeling",
183
+ "yss-openapi"
165
184
  ].freeze
166
185
 
167
186
  agent_roots.each do |agent_root|
@@ -266,6 +285,11 @@ ruby -c scripts/sync-skills >/dev/null
266
285
  ruby -c scripts/update-skill-lock >/dev/null
267
286
  ruby -c scripts/implementation-path-policy.rb >/dev/null
268
287
  ruby -c scripts/verify-lifecycle-scenarios >/dev/null
288
+ ruby -c scripts/lifecycle-registry.rb >/dev/null
289
+ ruby -c scripts/generate-lifecycle-artifacts >/dev/null
290
+ ruby -c scripts/verify-lifecycle-registry >/dev/null
291
+ ruby -c scripts/test-lifecycle-registry.rb >/dev/null
292
+ ruby -c scripts/verify-governance-release >/dev/null
269
293
  ruby -c scripts/verify-prototype-backend-scaffold-scenarios >/dev/null
270
294
  ruby -c scripts/verify-matt-yss-integration-scenarios >/dev/null
271
295
  ruby -c scripts/verify-yss-ui-scenarios >/dev/null
@@ -38,7 +38,7 @@ def routing_input_violations(contract, input)
38
38
  contract.fetch("exclusive_flags").each do |left, right|
39
39
  violations << "#{left}/#{right}" unless flags[left] != flags[right]
40
40
  end
41
- violations
41
+ violations.uniq
42
42
  end
43
43
 
44
44
  def active_impacts(input)
@@ -49,7 +49,8 @@ base_input = {
49
49
  "slice_id" => "order-create",
50
50
  "impact_flags" => {
51
51
  "ui_impact" => true, "api_impact" => true, "no_api_impact" => false,
52
- "data_impact" => false, "backend_impact" => false, "cross_repo" => false
52
+ "data_impact" => false, "backend_impact" => false, "cross_repo" => false,
53
+ "existing_frozen_baseline" => false
53
54
  },
54
55
  "lifecycle" => {}, "implementation" => {}, "acceptance" => {}
55
56
  }
@@ -60,6 +61,16 @@ failures << "Invalid lifecycle input type was accepted" if routing_input_violati
60
61
  both_api_modes = base_input["impact_flags"].merge("api_impact" => true, "no_api_impact" => true)
61
62
  failures << "API/no-API exclusivity was not enforced" if routing_input_violations(CONTRACT, base_input.merge("impact_flags" => both_api_modes)).empty?
62
63
 
64
+ legacy_posture_key = %w[security permission posture].join("_")
65
+ failures << "Router 输入仍要求已废弃的专项输入" if CONTRACT.fetch("routing_input_required").include?(legacy_posture_key)
66
+ failures << "Router 仍声明已废弃的专项合同" if CONTRACT.key?(legacy_posture_key)
67
+ legacy_impact_flags = CONTRACT.fetch("impact_flags_required").select do |flag|
68
+ %w[permission security].any? { |prefix| flag.start_with?("#{prefix}_") }
69
+ end
70
+ failures << "Router 仍要求安全 / 权限派生旗标" unless (CONTRACT.fetch("impact_flags_required") & legacy_impact_flags).empty?
71
+ explicit_authorization_input = base_input.merge("acceptance" => {"behavior" => "角色授权规则变化"})
72
+ failures << "显式权限行为无法按普通输入进入 Router" unless routing_input_violations(CONTRACT, explicit_authorization_input).empty?
73
+
63
74
  common_ready = CONTRACT.dig("readiness", "common").to_h { |key| [key, true] }
64
75
  ui_ready = CONTRACT.dig("readiness", "ui_impact").to_h { |key| [key, true] }
65
76
  api_ready = CONTRACT.dig("readiness", "api_impact").to_h { |key| [key, true] }
@@ -504,14 +515,26 @@ backend_skill_mutation["backend"]["required_skills"].delete("mapstruct")
504
515
  failures << "Backend contract accepted incomplete skill closure" unless slice_contract_decision_violations(CONTRACT, backend_input, backend_evidence, backend_skill_mutation, backend_expected_skills).include?("backend.required_skills")
505
516
  failures << "Backend contract accepted omitted skill closure" if slice_contract_decision_violations(CONTRACT, backend_input, backend_evidence, backend_slice, []).empty?
506
517
 
518
+ component_route_examples = {
519
+ "Current-user" => {"impact" => "current-user-context", "skills" => ["yss-userinfo"]},
520
+ "Audit" => {"impact" => "audit-event", "skills" => ["yss-audit-log", "yss-userinfo", "yss-dto"]},
521
+ "Encryption" => {"impact" => "encryption-or-signing", "skills" => ["yss-security-algorithm", "yss-exception"]}
522
+ }
523
+ component_route_examples.each do |label, example|
524
+ candidate = Marshal.load(Marshal.dump(backend_slice))
525
+ candidate["backend"]["component_impacts"] = [example.fetch("impact")]
526
+ required_skills = dependency_closure(CONTRACT, backend_expected_skills + example.fetch("skills"), {})
527
+ candidate["backend"]["required_skills"] = required_skills
528
+ candidate["common"]["required_skills"] = required_skills
529
+ failures << "#{label} component route was rejected" unless slice_contract_decision_violations(
530
+ CONTRACT, backend_input, backend_evidence, candidate, required_skills
531
+ ).empty?
532
+ end
507
533
  component_slice = Marshal.load(Marshal.dump(backend_slice))
508
534
  component_slice["backend"]["component_impacts"] = ["current-user-context"]
509
535
  component_skills = dependency_closure(CONTRACT, backend_expected_skills + ["yss-userinfo"], {})
510
536
  component_slice["backend"]["required_skills"] = component_skills
511
537
  component_slice["common"]["required_skills"] = component_skills
512
- failures << "Current-user component route was rejected" unless slice_contract_decision_violations(
513
- CONTRACT, backend_input, backend_evidence, component_slice, component_skills
514
- ).empty?
515
538
  unknown_component = Marshal.load(Marshal.dump(component_slice))
516
539
  unknown_component["backend"]["component_impacts"] = ["unknown-component"]
517
540
  unless slice_contract_decision_violations(CONTRACT, backend_input, backend_evidence, unknown_component, component_skills).include?("backend.component_impacts")
@@ -730,6 +753,17 @@ mutations = {
730
753
  "drift" => valid_result.merge("status" => "drift"),
731
754
  "violation" => valid_result.merge("status" => "violation")
732
755
  }
756
+
757
+ valid_deferred = valid_result.merge(
758
+ "status" => "seam-deferred",
759
+ "seam_deferred" => [{
760
+ "risk" => "temporary adapter", "owner" => "team", "follow_up_ticket" => "T-2",
761
+ "verification_plan" => "contract test", "target_version_or_release_date" => "2026-09-01"
762
+ }]
763
+ )
764
+ unless execution_violations(CONTRACT, valid_deferred, *valid_args).empty?
765
+ failures << "Valid seam-deferred result was rejected"
766
+ end
733
767
  mutations.each do |expected, result|
734
768
  blocker = expected.sub(/-(empty|command|contract-version|status|shape|work-unit|missing|implemented-with-seam|not-applicable-reason|identity|area)$/, "")
735
769
  actual = execution_violations(CONTRACT, result, *valid_args)
@@ -870,15 +904,9 @@ end
870
904
 
871
905
  scaffold_pom_template = ROOT.join(".agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template")
872
906
  scaffold_pom_body = scaffold_pom_template.read
873
- smart_doc_plugin_versions = scaffold_pom_body.scan(/<artifactId>smart-doc-maven-plugin<\/artifactId>\s*<version>([^<]+)<\/version>/).flatten
874
- failures << "smart-doc Maven plugin version must be fixed at yss-4.0.0" unless smart_doc_plugin_versions == ["yss-4.0.0"]
875
- smart_doc_template = ROOT.join(".agents/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template")
876
- smart_doc_body = smart_doc_template.file? ? smart_doc_template.read : ""
877
- %w[allInOne outPath packageFilters componentType].each do |marker|
878
- failures << "smart-doc template missing #{marker}" unless smart_doc_body.include?("\"#{marker}\"")
879
- end
880
- failures << "smart-doc packageFilters must use the supported single-star regex" unless smart_doc_body.include?("\"packageFilters\": \"{{base_package}}.*\"")
881
- failures << "smart-doc template contains environment secret settings" if smart_doc_body.match?(/appToken|openUrl|debugEnvUrl|serverUrl/)
907
+ failures << "后端脚手架不得保留旧 OpenAPI Maven 插件" if scaffold_pom_body.include?("smart-doc-maven-plugin")
908
+ legacy_openapi_template = ROOT.join(".agents/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template")
909
+ failures << "后端脚手架不得保留旧 OpenAPI 配置模板" if legacy_openapi_template.exist?
882
910
 
883
911
  %w[
884
912
  yss-domain/SKILL.md