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
@@ -2,9 +2,44 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "pathname"
5
+ require "set"
5
6
  require "yaml"
6
7
 
7
8
  ROOT = Pathname.new(__dir__).join("..").realpath
9
+ REGISTRY = YAML.safe_load(
10
+ ROOT.join("docs/process/lifecycle-registry.yaml").read,
11
+ permitted_classes: [],
12
+ aliases: false
13
+ )
14
+ REGISTRY_IDS = %w[stages gates artifacts work_units evidence].flat_map do |collection|
15
+ REGISTRY.fetch(collection).map { |record| record.fetch("id") }
16
+ end.to_set
17
+ ROUTE_REGISTRY_IDS = {
18
+ "impact-assessment" => "artifact.impact-assessment",
19
+ "ssot-update" => "work-unit.ssot-update",
20
+ "skill-projection-sync" => "work-unit.skill-projection-sync",
21
+ "pressure-scenarios" => "evidence.fresh-verification",
22
+ "fresh-verification" => "work-unit.fresh-verification",
23
+ "independent-review" => "work-unit.independent-review",
24
+ "tracker-sync" => "evidence.checkpoint-and-rollback",
25
+ "spec" => "artifact.spec",
26
+ "product-overview" => "artifact.product-overview",
27
+ "functional-architecture" => "artifact.functional-architecture",
28
+ "low-fidelity-prototype" => "artifact.low-fidelity-prototype",
29
+ "state-matrix" => "artifact.state-matrix",
30
+ "high-fidelity-html-prototype" => "artifact.high-fidelity-html-prototype",
31
+ "user-confirmation" => "gate.user-confirmation",
32
+ "openapi-draft" => "artifact.openapi-draft",
33
+ "draft-review" => "gate.openapi-draft-reviewed",
34
+ "design-review" => "gate.design-reviewed",
35
+ "openapi-freeze" => "gate.openapi-frozen",
36
+ "engineering-baseline" => "artifact.engineering-baseline",
37
+ "architecture-review" => "artifact.architecture-review",
38
+ "data-architecture" => "artifact.data-architecture",
39
+ "spec-delta" => "artifact.spec-delta",
40
+ "parent-ticket" => "artifact.parent-ticket",
41
+ "vertical-slice-tickets" => "artifact.vertical-slice-ticket"
42
+ }.freeze
8
43
 
9
44
  def route(facts)
10
45
  if facts.fetch(:repository_mode) == "template-source"
@@ -19,7 +54,10 @@ def route(facts)
19
54
  end
20
55
 
21
56
  gates = %w[impact-assessment tracker-sync fresh-verification]
22
- return gates if facts.fetch(:scale) == :small && !facts.fetch(:high_risk)
57
+ small_change = facts.fetch(:scale) == :small && !facts.fetch(:high_risk) &&
58
+ !facts.fetch(:ui_impact) && !facts.fetch(:api_impact) &&
59
+ !facts.fetch(:backend_impact) && !facts.fetch(:data_impact)
60
+ return gates if small_change
23
61
 
24
62
  gates.concat(%w[spec product-overview functional-architecture])
25
63
 
@@ -32,7 +70,7 @@ def route(facts)
32
70
  ])
33
71
  end
34
72
 
35
- gates.concat(%w[openapi-draft design-review openapi-freeze]) if facts.fetch(:api_impact)
73
+ gates.concat(%w[openapi-draft draft-review design-review openapi-freeze]) if facts.fetch(:api_impact)
36
74
 
37
75
  if facts.fetch(:backend_impact) || facts.fetch(:high_risk)
38
76
  gates.concat(%w[engineering-baseline architecture-review])
@@ -65,6 +103,16 @@ scenarios = [
65
103
  required: %w[spec product-overview functional-architecture openapi-draft engineering-baseline parent-ticket vertical-slice-tickets],
66
104
  forbidden: %w[low-fidelity-prototype state-matrix high-fidelity-html-prototype user-confirmation spec-delta]
67
105
  },
106
+ {
107
+ name: "普通 API 功能无需专项输入",
108
+ facts: {
109
+ repository_mode: "project-instance", scale: :small, high_risk: false,
110
+ ui_impact: false, api_impact: true, backend_impact: true,
111
+ data_impact: false, existing_frozen_baseline: false
112
+ },
113
+ required: %w[spec product-overview functional-architecture openapi-draft draft-review openapi-freeze engineering-baseline parent-ticket vertical-slice-tickets],
114
+ forbidden: %w[low-fidelity-prototype state-matrix high-fidelity-html-prototype user-confirmation spec-delta]
115
+ },
68
116
  {
69
117
  name: "有 UI 的新功能",
70
118
  facts: {
@@ -107,12 +155,22 @@ scenarios.each do |scenario|
107
155
  failures << "#{scenario.fetch(:name)} 错误触发: #{unexpected.join(', ')}" unless unexpected.empty?
108
156
  end
109
157
 
158
+ route_keys = scenarios.flat_map { |scenario| scenario.fetch(:required) + scenario.fetch(:forbidden) }.uniq
159
+ route_keys.each do |route_key|
160
+ registry_id = ROUTE_REGISTRY_IDS[route_key]
161
+ failures << "生命周期场景 route key 未映射稳定 ID: #{route_key}" unless registry_id
162
+ failures << "生命周期场景 route key 映射到不存在的稳定 ID: #{route_key} -> #{registry_id}" if registry_id && !REGISTRY_IDS.include?(registry_id)
163
+ end
164
+
110
165
  semantic_markers = {
111
166
  "AGENTS.md" => [
112
- "21 个门禁全部是条件强制门禁",
167
+ "生命周期注册表中的条件门禁全部按影响面强制",
113
168
  "只要进入 Spec 基线",
114
169
  "才构成产品设计影响",
115
170
  "Spec Delta 只记录相对既有冻结 Spec 基线",
171
+ "安全 / 权限不设独立生命周期资料或专属门禁",
172
+ "普通 action 注册",
173
+ "SQL / DDL / 迁移和上传 / 下载本身不构成安全 / 权限专项",
116
174
  "template-source",
117
175
  "apps/backend/<project>/",
118
176
  "apps/frontend/<project>/",
@@ -126,7 +184,17 @@ semantic_markers = {
126
184
  "不生成空文档",
127
185
  "最近可信阶段",
128
186
  "同一独立执行者",
129
- "集中 checkpoint"
187
+ "集中 checkpoint",
188
+ "安全 / 权限不单独分诊",
189
+ "不自动升级为安全专项"
190
+ ],
191
+ "docs/process/lifecycle-artifact-map.md" => [
192
+ "安全 / 权限不形成独立门禁",
193
+ "按实际 UI、API、Backend、Data、High-risk 影响"
194
+ ],
195
+ ".agents/skills/yss-product-lifecycle/references/artifact-dependencies.md" => [
196
+ "不使用独立影响类型",
197
+ "不增加安全 / 权限传播"
130
198
  ],
131
199
  "docs/process/implementation-repo-integration.md" => [
132
200
  "apps/backend/<project>/",
@@ -171,7 +239,7 @@ unless failures.empty?
171
239
  exit 1
172
240
  end
173
241
 
174
- puts "五类生命周期压力场景验证通过"
242
+ puts "六类生命周期压力场景验证通过"
175
243
 
176
244
  skill_root = ROOT.join(".agents/skills/yss-product-lifecycle")
177
245
  skill = skill_root.join("SKILL.md").read
@@ -235,7 +303,7 @@ reference_markers = {
235
303
  ]
236
304
  }.freeze
237
305
 
238
- removed_skills = %w[code-review-process yss-domain-modeling]
306
+ removed_skills = %w[code-review-process yss-domain-modeling yss-openapi]
239
307
  removed_skills.each do |skill_name|
240
308
  failures << "已移除 skill 仍存在: #{skill_name}" if ROOT.join(".agents/skills", skill_name).exist?
241
309
  end
@@ -250,7 +318,8 @@ tracked_policy_files = [
250
318
  tracked_policy_files.each do |relative_path|
251
319
  body = ROOT.join(relative_path).read
252
320
  removed_skills.each do |skill_name|
253
- failures << "#{relative_path} 仍引用已移除 skill: #{skill_name}" if body.include?(skill_name)
321
+ pattern = Regexp.new("(?<![a-z0-9-])#{Regexp.escape(skill_name)}(?![a-z0-9-])")
322
+ failures << "#{relative_path} 仍引用已移除 skill: #{skill_name}" if body.match?(pattern)
254
323
  end
255
324
  end
256
325
 
@@ -421,8 +490,9 @@ ready_required.each do |condition|
421
490
  end
422
491
 
423
492
  propagation = contract.fetch("impact_propagation")
424
- expected_types = %w[wording ui-state permission api-schema state-machine data-model service-boundary nfr deployment security]
493
+ expected_types = %w[wording ui-state api-schema state-machine data-model service-boundary nfr deployment]
425
494
  failures << "影响类型不完整" unless (expected_types - propagation.keys).empty?
495
+ failures << "安全 / 权限仍作为独立传播类型" unless (propagation.keys & %w[permission security]).empty?
426
496
 
427
497
  allowed_conditions = %w[always existing_frozen_baseline ui_impact api_impact data_impact backend_impact]
428
498
  propagation.each do |impact_type, definition|
@@ -464,14 +534,41 @@ expected_types.each do |impact_type|
464
534
  failures << "#{impact_type} 可执行传播结果为空" if targets.nil? || targets.empty?
465
535
  end
466
536
 
467
- new_module_permission = propagated_targets(
537
+ new_module_api = propagated_targets(
468
538
  propagation,
469
- "permission",
539
+ "api-schema",
470
540
  all_impacts_context.merge("existing_frozen_baseline" => false)
471
541
  )
472
- failures << "新模块错误激活 spec-delta" if new_module_permission.any? { |target| target["name"] == "spec-delta" }
473
- unless new_module_permission.any? { |target| target["kind"] == "gate" && target["name"] == "openapi-freeze" }
474
- failures << "permission API 影响未使 openapi-freeze gate stale"
542
+ failures << "新模块错误激活 spec-delta" if new_module_api.any? { |target| target["name"] == "spec-delta" }
543
+ unless new_module_api.any? { |target| target["kind"] == "gate" && target["name"] == "openapi-freeze" }
544
+ failures << "普通 API 影响未使 openapi-freeze gate stale"
545
+ end
546
+
547
+ legacy_posture_key = %w[security permission posture].join("_")
548
+ failures << "生命周期合同仍要求已废弃的专项输入" if contract.key?(legacy_posture_key)
549
+ ordinary_route = route(
550
+ repository_mode: "project-instance", scale: :medium, high_risk: false,
551
+ ui_impact: true, api_impact: true, backend_impact: true,
552
+ data_impact: false, existing_frozen_baseline: false
553
+ )
554
+ %w[openapi-draft openapi-freeze engineering-baseline].each do |gate|
555
+ failures << "普通功能错误移除 #{gate} 门禁" unless ordinary_route.include?(gate)
556
+ end
557
+
558
+ data_targets = propagated_targets(propagation, "data-model", all_impacts_context)
559
+ failures << "SQL / DDL 未按普通数据影响传播" unless data_targets.any? { |target| target["name"] == "data-architecture" }
560
+ api_targets = propagated_targets(propagation, "api-schema", all_impacts_context)
561
+ failures << "下载接口未按普通 API 影响传播" unless api_targets.any? { |target| target["name"] == "openapi-draft" }
562
+
563
+ seam_required = contract.fetch("seam_deferred_required")
564
+ def seam_field_filled?(value)
565
+ value.is_a?(Array) ? !value.empty? : !value.to_s.empty?
566
+ end
567
+ valid_seam = seam_required.to_h { |field| [field, "value"] }
568
+ failures << "完整 seam-deferred 证据被错误阻断" unless seam_required.all? { |field| seam_field_filled?(valid_seam[field]) }
569
+ %w[owner follow_up_ticket target_version_or_release_date].each do |field|
570
+ mutation = valid_seam.reject { |key, _| key == field }
571
+ failures << "seam-deferred 缺少 #{field} 时未阻断" if seam_required.all? { |required_field| seam_field_filled?(mutation[required_field]) }
475
572
  end
476
573
 
477
574
  no_api_ui = propagated_targets(
@@ -488,11 +585,11 @@ unless unknown_decision == {"action" => "pause", "reason_code" => "impact-classi
488
585
  failures << "未知 impact type 未返回结构化暂停"
489
586
  end
490
587
 
491
- permission_gate_stale = new_module_permission.any? { |target| target["kind"] == "gate" }
492
- permission_artifact_stale = new_module_permission.any? { |target| target["kind"] == "artifact" }
588
+ api_gate_stale = new_module_api.any? { |target| target["kind"] == "gate" }
589
+ api_artifact_stale = new_module_api.any? { |target| target["kind"] == "artifact" }
493
590
  linked_ready_facts = ready_slice.merge(
494
- "gates_satisfied" => !permission_gate_stale,
495
- "no_stale_artifacts" => !permission_artifact_stale
591
+ "gates_satisfied" => !api_gate_stale,
592
+ "no_stale_artifacts" => !api_artifact_stale
496
593
  )
497
594
  failures << "传播后未撤销 ready-for-agent" if ready_for_agent?(ready_required, linked_ready_facts)
498
595
 
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "pathname"
5
5
  require "yaml"
6
+ require "digest"
6
7
 
7
8
  ROOT = Pathname.new(__dir__).join("..").realpath
8
9
 
@@ -76,6 +77,46 @@ def flow_decision(definition, repository_mode:, flow:)
76
77
  {"result" => "allowed", "reason" => nil}
77
78
  end
78
79
 
80
+ def git_operation_authorized?(definition, facts)
81
+ return false unless definition["requires_explicit_user_authorization"] == true
82
+ return false unless definition["authorized_value"] == true
83
+
84
+ required = definition.fetch("required", [])
85
+ return false unless required.all? { |field| facts.key?(field) }
86
+
87
+ authorization_fields = required.grep(/_authorized\z/)
88
+ return false unless authorization_fields.all? { |field| facts[field] == definition["authorized_value"] }
89
+
90
+ definition.fetch("non_empty", []).all? { |field| !facts.fetch(field, "").to_s.empty? }
91
+ end
92
+
93
+ def uint64be(value)
94
+ [value].pack("Q>")
95
+ end
96
+
97
+ def uint32be(value)
98
+ [value].pack("N")
99
+ end
100
+
101
+ def canonical_worktree_candidate_stream(snapshot, tracked_diff:, untracked:)
102
+ header = snapshot.fetch("header_ascii").b + [Integer(snapshot.fetch("terminator_byte"))].pack("C")
103
+ tracked = snapshot.fetch("tracked_record")
104
+ stream = header + [Integer(tracked.fetch("type_byte"))].pack("C") + uint64be(tracked_diff.bytesize) + tracked_diff
105
+ kinds = snapshot.fetch("untracked_record").fetch("entry_kinds")
106
+
107
+ untracked.sort_by { |entry| entry.fetch(:path).b }.each do |entry|
108
+ path = entry.fetch(:path).b
109
+ content = entry.fetch(:content).b
110
+ kind = entry.fetch(:kind).to_s
111
+ stream << [Integer(snapshot.fetch("untracked_record").fetch("type_byte"))].pack("C")
112
+ stream << uint64be(path.bytesize) << path
113
+ stream << uint32be(entry.fetch(:mode))
114
+ stream << [Integer(kinds.fetch(kind))].pack("C")
115
+ stream << uint64be(content.bytesize) << content
116
+ end
117
+ stream
118
+ end
119
+
79
120
  entry = contract.fetch("entry_routing", {})
80
121
  require_equal(failures, "entry manifest", entry["manifest"], "yss-project.yaml")
81
122
  require_equal(failures, "entry valid modes", entry["valid_modes"], %w[template-source project-instance])
@@ -196,6 +237,222 @@ ready_required = contract.dig("ready_for_agent", "required") || []
196
237
  (preconditions.dig("implement", "required") || []).reject { |field| field == "ready_for_agent" }.each do |field|
197
238
  require_include(failures, "ready-for-agent 与 implement 前置条件", ready_required, field)
198
239
  end
240
+
241
+ ticket_role_transition = contract.fetch("ticket_role_transition", {})
242
+ require_equal(
243
+ failures,
244
+ "YSS to-tickets initial role",
245
+ ticket_role_transition.dig("yss_active", "to_tickets_initial_role"),
246
+ "ready-for-human"
247
+ )
248
+ require_equal(
249
+ failures,
250
+ "YSS ticket promotion owner",
251
+ ticket_role_transition.dig("yss_active", "promotion_owner"),
252
+ "yss-product-lifecycle"
253
+ )
254
+ require_equal(
255
+ failures,
256
+ "YSS ticket promoted role",
257
+ ticket_role_transition.dig("yss_active", "promoted_role"),
258
+ "ready-for-agent"
259
+ )
260
+ require_equal(
261
+ failures,
262
+ "YSS ticket promotion condition",
263
+ ticket_role_transition.dig("yss_active", "promotion_requires"),
264
+ "ready_for_agent"
265
+ )
266
+
267
+ review_input = contract.fetch("review_input", {})
268
+ require_equal(failures, "review input schema", review_input["schema_version"], 1)
269
+ %w[
270
+ review_mode
271
+ review_base_ref
272
+ implementation_candidate_ref
273
+ candidate_snapshot_ref
274
+ candidate_digest
275
+ spec_ref
276
+ ticket_ref
277
+ slice_contract_ref
278
+ build_architecture_checklist_ref
279
+ yss_execution_result_refs
280
+ ].each do |field|
281
+ require_include(failures, "review input required fields", review_input["required"] || [], field)
282
+ end
283
+ %w[committed worktree].each do |mode|
284
+ require_include(failures, "review modes", review_input["modes"] || [], mode)
285
+ end
286
+ %w[committed staged unstaged untracked].each do |candidate_part|
287
+ require_include(
288
+ failures,
289
+ "worktree review coverage",
290
+ review_input.dig("worktree", "required_coverage") || [],
291
+ candidate_part
292
+ )
293
+ end
294
+ require_equal(
295
+ failures,
296
+ "worktree untracked inventory",
297
+ review_input.dig("worktree", "untracked_inventory_command"),
298
+ "git ls-files -z --others --exclude-standard"
299
+ )
300
+ require_equal(
301
+ failures,
302
+ "worktree tracked binary diff",
303
+ review_input.dig("worktree", "tracked_diff_command"),
304
+ "git diff --no-ext-diff --binary --full-index <merge-base>"
305
+ )
306
+ require_equal(
307
+ failures,
308
+ "worktree untracked binary diff",
309
+ review_input.dig("worktree", "untracked_diff_command"),
310
+ "git diff --no-index --no-ext-diff --binary --full-index -- /dev/null <path>"
311
+ )
312
+ require_equal(failures, "worktree capture once", review_input.dig("worktree", "capture_once"), true)
313
+ require_equal(failures, "worktree verify unchanged", review_input.dig("worktree", "verify_unchanged_after_review"), true)
314
+ require_equal(failures, "review snapshot immutable", review_input.dig("snapshot", "immutable"), true)
315
+ require_equal(failures, "review digest algorithm", review_input.dig("snapshot", "digest_algorithm"), "sha256")
316
+ require_equal(
317
+ failures,
318
+ "review digest framing",
319
+ review_input.dig("snapshot", "digest_framing"),
320
+ "length-prefixed-path-and-bytes"
321
+ )
322
+ require_equal(failures, "review digest path order", review_input.dig("snapshot", "path_order"), "bytewise")
323
+ require_equal(failures, "review digest change action", review_input.dig("snapshot", "on_digest_change"), "blocked")
324
+ require_equal(failures, "review completion digest guard", review_input.dig("snapshot", "completion_requires_current_digest"), true)
325
+ require_equal(failures, "review snapshot protocol", review_input.dig("snapshot", "protocol"), "yss-worktree-candidate-v1")
326
+ require_equal(failures, "review snapshot path encoding", review_input.dig("snapshot", "path_encoding"), "raw-bytes")
327
+ require_equal(failures, "review snapshot length encoding", review_input.dig("snapshot", "length_encoding"), "uint64-big-endian")
328
+ require_equal(failures, "review snapshot header", review_input.dig("snapshot", "header_ascii"), "YSS-WORKTREE-CANDIDATE-V1")
329
+ require_equal(failures, "review snapshot terminator", review_input.dig("snapshot", "terminator_byte"), "0x00")
330
+ require_equal(failures, "review snapshot tracked record", review_input.dig("snapshot", "tracked_record", "type_byte"), "0x54")
331
+ require_equal(failures, "review snapshot untracked record", review_input.dig("snapshot", "untracked_record", "type_byte"), "0x55")
332
+ require_equal(failures, "review snapshot unsupported entry action", review_input.dig("snapshot", "unsupported_entry_action"), "blocked")
333
+ require_equal(
334
+ failures,
335
+ "review snapshot tracked fields",
336
+ review_input.dig("snapshot", "tracked_record", "fields"),
337
+ %w[type_byte uint64be_content_length binary_diff_bytes]
338
+ )
339
+ require_equal(
340
+ failures,
341
+ "review snapshot untracked fields",
342
+ review_input.dig("snapshot", "untracked_record", "fields"),
343
+ %w[type_byte uint64be_path_length raw_path_bytes uint32be_file_mode entry_kind_byte uint64be_content_length content_bytes]
344
+ )
345
+ require_equal(
346
+ failures,
347
+ "review snapshot entry kinds",
348
+ review_input.dig("snapshot", "untracked_record", "entry_kinds"),
349
+ {"regular" => "0x52", "symlink" => "0x4c"}
350
+ )
351
+ fixture_tracked_diff = "COMMITTED\\nSTAGED\\nUNSTAGED\\nDELETE\\nMODE-CHANGE\\n".b
352
+ fixture_untracked = [
353
+ {path: "z\\nname".b, mode: 0o100644, kind: :regular, content: "untracked-bytes\\n".b},
354
+ {path: "a-link".b, mode: 0o120777, kind: :symlink, content: "target\\nname".b}
355
+ ]
356
+ fixture_stream = canonical_worktree_candidate_stream(
357
+ review_input.fetch("snapshot"),
358
+ tracked_diff: fixture_tracked_diff,
359
+ untracked: fixture_untracked
360
+ )
361
+ require_equal(
362
+ failures,
363
+ "review snapshot canonical digest",
364
+ Digest::SHA256.hexdigest(fixture_stream),
365
+ "cc1b30990cc0d2a11721140cd94cb92a275f9dd24c6663e21ad7e5ea47898b7d"
366
+ )
367
+ reordered_stream = canonical_worktree_candidate_stream(
368
+ review_input.fetch("snapshot"),
369
+ tracked_diff: fixture_tracked_diff,
370
+ untracked: fixture_untracked.reverse
371
+ )
372
+ require_equal(failures, "review snapshot bytewise ordering", reordered_stream, fixture_stream)
373
+ review_return_digest = Digest::SHA256.hexdigest(fixture_stream)
374
+ completion_digest = Digest::SHA256.hexdigest(fixture_stream)
375
+ require_equal(failures, "review return digest guard", review_return_digest, Digest::SHA256.hexdigest(fixture_stream))
376
+ require_equal(failures, "review completion digest guard behavior", completion_digest, Digest::SHA256.hexdigest(fixture_stream))
377
+ drift_stream = canonical_worktree_candidate_stream(
378
+ review_input.fetch("snapshot"),
379
+ tracked_diff: fixture_tracked_diff,
380
+ untracked: fixture_untracked.map { |entry| entry.merge(content: entry[:content] + "changed".b) }
381
+ )
382
+ failures << "review return digest drift 未阻断" if Digest::SHA256.hexdigest(drift_stream) == review_return_digest
383
+ failures << "review completion digest drift 未阻断" if Digest::SHA256.hexdigest(drift_stream) == completion_digest
384
+ %w[merge_base tracked_diff_command untracked_inventory_command untracked_diff_command untracked_files commit_list_command].each do |field|
385
+ require_include(
386
+ failures,
387
+ "worktree manifest required fields",
388
+ review_input.dig("manifest_required_by_mode", "worktree") || [],
389
+ field
390
+ )
391
+ end
392
+ %w[merge_base tracked_diff_command commit_list_command].each do |field|
393
+ require_include(
394
+ failures,
395
+ "committed manifest required fields",
396
+ review_input.dig("manifest_required_by_mode", "committed") || [],
397
+ field
398
+ )
399
+ end
400
+
401
+ git_authorization = contract.fetch("git_authorization", {})
402
+ {
403
+ "commit" => %w[commit_authorized commit_scope commit_authorization_ref],
404
+ "push" => %w[push_authorized push_scope push_authorization_ref]
405
+ }.each do |operation, required_fields|
406
+ require_equal(
407
+ failures,
408
+ "#{operation} explicit authorization",
409
+ git_authorization.dig(operation, "requires_explicit_user_authorization"),
410
+ true
411
+ )
412
+ required_fields.each do |field|
413
+ require_include(failures, "#{operation} authorization fields", git_authorization.dig(operation, "required") || [], field)
414
+ end
415
+ require_equal(
416
+ failures,
417
+ "#{operation} authorization value",
418
+ git_authorization.dig(operation, "authorized_value"),
419
+ true
420
+ )
421
+ required_fields.reject { |field| field.end_with?("_authorized") }.each do |field|
422
+ require_include(
423
+ failures,
424
+ "#{operation} non-empty authorization fields",
425
+ git_authorization.dig(operation, "non_empty") || [],
426
+ field
427
+ )
428
+ end
429
+ require_equal(
430
+ failures,
431
+ "#{operation} unauthorized action",
432
+ git_authorization.dig(operation, "unauthorized_action"),
433
+ "checkpoint-only"
434
+ )
435
+
436
+ definition = git_authorization.fetch(operation, {})
437
+ valid_facts = required_fields.to_h do |field|
438
+ [field, field.end_with?("_authorized") ? true : "explicit-value"]
439
+ end
440
+ allowed = git_operation_authorized?(definition, valid_facts)
441
+ failures << "#{operation} 完整显式授权被错误阻断" unless allowed
442
+
443
+ false_authorization = valid_facts.merge("#{operation}_authorized" => false)
444
+ false_allowed = git_operation_authorized?(definition, false_authorization)
445
+ failures << "#{operation} authorized=false 未阻断" if false_allowed
446
+
447
+ required_fields.reject { |field| field.end_with?("_authorized") }.each do |field|
448
+ blank = valid_facts.merge(field => "")
449
+ blank_allowed = git_operation_authorized?(definition, blank)
450
+ failures << "#{operation} #{field} 为空时未阻断" if blank_allowed
451
+ end
452
+
453
+ false_contract = definition.merge("authorized_value" => false)
454
+ failures << "#{operation} authorized_value=false 未阻断" if git_operation_authorized?(false_contract, valid_facts)
455
+ end
199
456
  {
200
457
  "to-spec" => %w[user_problem mvp_and_non_goals success_criteria test_seam terminology_review]
201
458
  }.each do |flow, required|
@@ -447,6 +704,7 @@ end
447
704
 
448
705
  adapter = read(ROOT, ".agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md")
449
706
  to_spec = read(ROOT, ".agents/skills/to-spec/SKILL.md")
707
+ code_review = read(ROOT, ".agents/skills/code-review/SKILL.md")
450
708
  require_markers(
451
709
  failures,
452
710
  "Matt to-spec core contract",
@@ -466,17 +724,55 @@ require_markers(
466
724
  "发布提示由本适配层覆盖为 `ready-for-human`",
467
725
  "to-spec",
468
726
  "to-tickets",
727
+ "YSS active 的 `to-tickets`",
728
+ "`review_mode`",
729
+ "`commit_authorized`",
730
+ "`push_authorized`",
469
731
  "Release",
470
732
  "Retrospective"
471
733
  ]
472
734
  )
735
+ require_markers(
736
+ failures,
737
+ "Matt code-review candidate modes",
738
+ code_review,
739
+ [
740
+ "Committed candidate",
741
+ "Worktree candidate",
742
+ "git diff --no-ext-diff --binary --full-index <merge-base>",
743
+ "git diff --no-index --no-ext-diff --binary --full-index -- /dev/null <path>",
744
+ "git ls-files -z --others --exclude-standard",
745
+ "staged",
746
+ "unstaged",
747
+ "untracked",
748
+ "candidate manifest",
749
+ "captured candidate",
750
+ "yss-worktree-candidate-v1",
751
+ "unsigned 64-bit big-endian",
752
+ "candidate_digest",
753
+ "stale candidate",
754
+ "immutable",
755
+ "length-prefixed",
756
+ "bytewise path order",
757
+ "return `blocked`"
758
+ ]
759
+ )
473
760
 
474
761
  lifecycle_skill = read(ROOT, ".agents/skills/yss-product-lifecycle/SKILL.md")
475
762
  require_markers(
476
763
  failures,
477
764
  "lifecycle template-source guard",
478
765
  lifecycle_skill,
479
- ["template-source", "必须返回 `blocked`", "template-source-product-artifact-forbidden", "YSS active 调用 `to-spec` 时", "ready-for-agent` 发布提示归一化为 Spec `ready-for-human`"]
766
+ [
767
+ "template-source",
768
+ "必须返回 `blocked`",
769
+ "template-source-product-artifact-forbidden",
770
+ "YSS active 调用 `to-spec` 时",
771
+ "ready-for-agent` 发布提示归一化为 Spec `ready-for-human`",
772
+ "YSS active 调用 `to-tickets` 时",
773
+ "`commit_authorized`",
774
+ "`push_authorized`"
775
+ ]
480
776
  )
481
777
  orchestration = read(ROOT, ".agents/skills/yss-product-lifecycle/references/orchestration.md")
482
778
  require_markers(