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
@@ -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 场景验证通过"
@@ -4,7 +4,13 @@ set -euo pipefail
4
4
  ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
5
  cd "$ROOT_DIR"
6
6
 
7
+ # Ruby inherits US-ASCII under a C locale on some macOS installations. Keep
8
+ # all verification scripts UTF-8 capable because the template contains Chinese
9
+ # documentation and skill metadata.
10
+ export RUBYOPT="${RUBYOPT:+$RUBYOPT }-EUTF-8:UTF-8"
11
+
7
12
  ruby <<'RUBY'
13
+ # encoding: UTF-8
8
14
  require "pathname"
9
15
  require "yaml"
10
16
 
@@ -23,6 +29,9 @@ required_files=(
23
29
  "AGENTS.md"
24
30
  "CONTEXT.md"
25
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"
26
35
  "docs/process/lifecycle-artifact-map.md"
27
36
  "docs/process/harness-process-tailoring.md"
28
37
  "docs/templates/local-parent-ticket-template.md"
@@ -33,11 +42,17 @@ required_files=(
33
42
  "scripts/update-skill-lock"
34
43
  "scripts/implementation-path-policy.rb"
35
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"
36
49
  "scripts/verify-implementation-path-scenarios"
37
50
  "scripts/verify-scaffold-generator-scenarios"
38
51
  "scripts/verify-prototype-backend-scaffold-scenarios"
39
52
  "scripts/verify-matt-yss-integration-scenarios"
40
53
  "scripts/verify-yss-ui-scenarios"
54
+ "scripts/verify-openapi-yaml-first-scenarios"
55
+ "scripts/verify-openapi-json-handoff-scenarios"
41
56
  )
42
57
 
43
58
  required_skills=(
@@ -84,6 +99,7 @@ for skill_name in "${required_skills[@]}"; do
84
99
  done
85
100
 
86
101
  ruby <<'RUBY'
102
+ # encoding: UTF-8
87
103
  require "json"
88
104
  require "pathname"
89
105
  require "yaml"
@@ -113,21 +129,31 @@ lock.fetch("skills", {}).fetch("shared", {}).each do |skill_name, metadata|
113
129
  end
114
130
 
115
131
  openapi_path = root.join("docs/templates/openapi-spec-template.yaml")
116
- openapi_text = openapi_path.read.sub(/\A---\n.*?\n---\n/m, "")
117
- 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
118
137
  RUBY
119
138
 
120
139
  scripts/sync-skills --check
121
140
  scripts/update-skill-lock --check
141
+ scripts/verify-lifecycle-registry
122
142
  scripts/verify-lifecycle-scenarios
143
+ scripts/verify-governance-release
123
144
  scripts/verify-implementation-path-scenarios
124
145
  scripts/verify-scaffold-generator-scenarios
125
146
  scripts/verify-prototype-backend-scaffold-scenarios
126
147
  ruby scripts/verify-matt-yss-integration-scenarios
127
148
  scripts/verify-yss-router-scenarios
128
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
129
154
 
130
155
  ruby <<'RUBY'
156
+ # encoding: UTF-8
131
157
  require "pathname"
132
158
  require "json"
133
159
 
@@ -153,7 +179,8 @@ obsolete_names = [
153
179
  "obsidian-vault",
154
180
  "writing-great-skills",
155
181
  "code-review-process",
156
- "yss-domain-modeling"
182
+ "yss-domain-modeling",
183
+ "yss-openapi"
157
184
  ].freeze
158
185
 
159
186
  agent_roots.each do |agent_root|
@@ -225,8 +252,8 @@ unless legacy_hits.empty?
225
252
  exit 1
226
253
  end
227
254
 
228
- unless root.join("AGENTS.md").read.include?("正文统一使用简体中文") &&
229
- root.join("CONTEXT.md").read.include?("统一使用简体中文")
255
+ unless root.join("AGENTS.md").binread.force_encoding("UTF-8").include?("正文统一使用简体中文") &&
256
+ root.join("CONTEXT.md").binread.force_encoding("UTF-8").include?("统一使用简体中文")
230
257
  abort("AGENTS.md 与 CONTEXT.md 必须共同声明落地文档使用简体中文")
231
258
  end
232
259
 
@@ -258,6 +285,11 @@ ruby -c scripts/sync-skills >/dev/null
258
285
  ruby -c scripts/update-skill-lock >/dev/null
259
286
  ruby -c scripts/implementation-path-policy.rb >/dev/null
260
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
261
293
  ruby -c scripts/verify-prototype-backend-scaffold-scenarios >/dev/null
262
294
  ruby -c scripts/verify-matt-yss-integration-scenarios >/dev/null
263
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