create-yss-spec 3.4.1 → 3.4.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 (413) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -2
  3. package/template/.agents/skills/.strategic-design-skills-manifest.json +3 -3
  4. package/template/.agents/skills/archify/SKILL.md +1 -1
  5. package/template/.agents/skills/code-review/SKILL.md +12 -8
  6. package/template/.agents/skills/file-export-download/SKILL.md +1 -1
  7. package/template/.agents/skills/frontend-commit/SKILL.md +1 -1
  8. package/template/.agents/skills/java-backend-commit/SKILL.md +1 -1
  9. package/template/.agents/skills/llm-wiki/SKILL.md +1 -6
  10. package/template/.agents/skills/lombok/SKILL.md +10 -336
  11. package/template/.agents/skills/lombok/references/annotation-examples.md +307 -0
  12. package/template/.agents/skills/maintaining-skills/SKILL.md +2 -1
  13. package/template/.agents/skills/maintaining-skills/references/authoring.md +27 -0
  14. package/template/.agents/skills/mapstruct/SKILL.md +11 -318
  15. package/template/.agents/skills/mapstruct/references/annotation-examples.md +300 -0
  16. package/template/.agents/skills/page-form-module/SKILL.md +1 -1
  17. package/template/.agents/skills/page-skeleton/SKILL.md +1 -1
  18. package/template/.agents/skills/theme-token-usage/SKILL.md +1 -1
  19. package/template/.agents/skills/to-tickets/SKILL.md +1 -1
  20. package/template/.agents/skills/using-git-worktrees/SKILL.md +1 -1
  21. package/template/.agents/skills/wayfinder/SKILL.md +1 -1
  22. package/template/.agents/skills/yedit-table-usage/SKILL.md +1 -1
  23. package/template/.agents/skills/yss-api-integration/SKILL.md +1 -1
  24. package/template/.agents/skills/yss-audit-log/SKILL.md +1 -1
  25. package/template/.agents/skills/yss-cache/SKILL.md +1 -1
  26. package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +16 -3
  27. package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/application-pom.xml.template +1 -1
  28. package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/parent-pom.xml.template +15 -10
  29. package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/web-pom.xml.template +3 -3
  30. package/template/.agents/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +3 -3
  31. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +5 -1
  32. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +5 -2
  33. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +13 -10
  34. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +2 -1
  35. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +35 -3
  36. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +1 -1
  37. package/template/.agents/skills/yss-distributed-id/SKILL.md +1 -1
  38. package/template/.agents/skills/yss-dto/SKILL.md +5 -1
  39. package/template/.agents/skills/yss-excel-mvc/SKILL.md +1 -1
  40. package/template/.agents/skills/yss-exception/SKILL.md +5 -1
  41. package/template/.agents/skills/yss-formily-schema-generator/SKILL.md +1 -1
  42. package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +14 -6
  43. package/template/.agents/skills/yss-implementation-contract-compiler/agents/openai.yaml +1 -1
  44. package/template/.agents/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -0
  45. package/template/.agents/skills/yss-implementation-contract-compiler/references/slice-implementation-contract-v2.md +214 -0
  46. package/template/.agents/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +66 -204
  47. package/template/.agents/skills/yss-layered-mvc-scaffold-generator/SKILL.md +15 -2
  48. package/template/.agents/skills/yss-layered-mvc-scaffold-generator/scripts/generate_scaffold.mjs +28 -19
  49. package/template/.agents/skills/yss-layered-mvc-scaffold-generator/scripts/scaffold-generator.test.mjs +10 -10
  50. package/template/.agents/skills/yss-mybatis/SKILL.md +4 -0
  51. package/template/.agents/skills/yss-openapi-draft-review/SKILL.md +1 -1
  52. package/template/.agents/skills/yss-openapi-governance/SKILL.md +1 -1
  53. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +4 -4
  54. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +29 -7
  55. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +6 -2
  56. package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +3 -1
  57. package/template/.agents/skills/yss-product-lifecycle/references/user-decisions.md +24 -4
  58. package/template/.agents/skills/yss-prototype-stage/SKILL.md +1 -1
  59. package/template/.agents/skills/yss-repository/SKILL.md +4 -0
  60. package/template/.agents/skills/yss-research/SKILL.md +1 -1
  61. package/template/.agents/skills/yss-resilience4j/SKILL.md +1 -1
  62. package/template/.agents/skills/yss-security-algorithm/SKILL.md +1 -1
  63. package/template/.agents/skills/yss-stage-decision/SKILL.md +1 -1
  64. package/template/.agents/skills/yss-stage-decision/references/domain-strategy-contract.md +2 -0
  65. package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  66. package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +3 -3
  67. package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +3 -3
  68. package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +33 -0
  69. package/template/.agents/skills/yss-tactical-design/SKILL.md +5 -1
  70. package/template/.agents/skills/yss-technical-design/SKILL.md +5 -1
  71. package/template/.agents/skills/yss-technical-design/references/technical-design-contract.md +1 -1
  72. package/template/.agents/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
  73. package/template/.agents/skills/yss-technical-design/tests/run-scenarios.mjs +1 -1
  74. package/template/.agents/skills/yss-ui/SKILL.md +1 -1
  75. package/template/.agents/skills/yss-ui-business-page-generation/SKILL.md +1 -1
  76. package/template/.agents/skills/yss-up-springboot3/SKILL.md +1 -1
  77. package/template/.agents/skills/yss-use-table-height/SKILL.md +1 -1
  78. package/template/.agents/skills/yss-use-tree-height/SKILL.md +1 -1
  79. package/template/.agents/skills/yss-userinfo/SKILL.md +1 -1
  80. package/template/.agents/skills/yss-validation/SKILL.md +5 -1
  81. package/template/.agents/skills/yss-web-controller/SKILL.md +5 -1
  82. package/template/.agents/skills/yss-web-controller/scripts/generate_controller.mjs +5 -2
  83. package/template/.agents/skills/ytable-usage/SKILL.md +1 -1
  84. package/template/.agents/skills/ytree-usage/SKILL.md +1 -1
  85. package/template/.codex/skills/archify/SKILL.md +1 -1
  86. package/template/.codex/skills/code-review/SKILL.md +12 -8
  87. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/SKILL.md +1 -1
  88. package/template/.codex/skills/data-analytics/skills/build-dashboard/SKILL.md +1 -1
  89. package/template/.codex/skills/data-analytics/skills/build-report/SKILL.md +1 -1
  90. package/template/.codex/skills/data-analytics/skills/design-kpis/SKILL.md +1 -1
  91. package/template/.codex/skills/data-analytics/skills/gather-business-context/SKILL.md +1 -1
  92. package/template/.codex/skills/data-analytics/skills/index/SKILL.md +1 -1
  93. package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/SKILL.md +1 -1
  94. package/template/.codex/skills/data-analytics/skills/kpi-reporting/SKILL.md +1 -1
  95. package/template/.codex/skills/data-analytics/skills/market-sizing/SKILL.md +1 -1
  96. package/template/.codex/skills/data-analytics/skills/metric-diagnostics/SKILL.md +1 -1
  97. package/template/.codex/skills/data-analytics/skills/product-business-analysis/SKILL.md +1 -1
  98. package/template/.codex/skills/data-analytics/skills/spreadsheets/SKILL.md +1 -1
  99. package/template/.codex/skills/data-analytics/skills/validate-data/SKILL.md +1 -1
  100. package/template/.codex/skills/data-analytics/skills/visualize-data/SKILL.md +1 -1
  101. package/template/.codex/skills/file-export-download/SKILL.md +1 -1
  102. package/template/.codex/skills/frontend-commit/SKILL.md +1 -1
  103. package/template/.codex/skills/java-backend-commit/SKILL.md +1 -1
  104. package/template/.codex/skills/llm-wiki/SKILL.md +1 -6
  105. package/template/.codex/skills/lombok/SKILL.md +10 -336
  106. package/template/.codex/skills/lombok/references/annotation-examples.md +307 -0
  107. package/template/.codex/skills/maintaining-skills/SKILL.md +2 -1
  108. package/template/.codex/skills/maintaining-skills/references/authoring.md +27 -0
  109. package/template/.codex/skills/mapstruct/SKILL.md +11 -318
  110. package/template/.codex/skills/mapstruct/references/annotation-examples.md +300 -0
  111. package/template/.codex/skills/page-form-module/SKILL.md +1 -1
  112. package/template/.codex/skills/page-skeleton/SKILL.md +1 -1
  113. package/template/.codex/skills/product-design/skills/audit/SKILL.md +1 -1
  114. package/template/.codex/skills/product-design/skills/design-qa/SKILL.md +1 -1
  115. package/template/.codex/skills/product-design/skills/get-context/SKILL.md +1 -1
  116. package/template/.codex/skills/product-design/skills/ideate/SKILL.md +1 -1
  117. package/template/.codex/skills/product-design/skills/image-to-code/SKILL.md +1 -1
  118. package/template/.codex/skills/product-design/skills/index/SKILL.md +1 -1
  119. package/template/.codex/skills/product-design/skills/prototype/SKILL.md +1 -1
  120. package/template/.codex/skills/product-design/skills/research/SKILL.md +1 -1
  121. package/template/.codex/skills/product-design/skills/user-context/SKILL.md +1 -1
  122. package/template/.codex/skills/theme-token-usage/SKILL.md +1 -1
  123. package/template/.codex/skills/to-tickets/SKILL.md +1 -1
  124. package/template/.codex/skills/using-git-worktrees/SKILL.md +1 -1
  125. package/template/.codex/skills/wayfinder/SKILL.md +1 -1
  126. package/template/.codex/skills/yedit-table-usage/SKILL.md +1 -1
  127. package/template/.codex/skills/yss-api-integration/SKILL.md +1 -1
  128. package/template/.codex/skills/yss-audit-log/SKILL.md +1 -1
  129. package/template/.codex/skills/yss-cache/SKILL.md +1 -1
  130. package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +16 -3
  131. package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/application-pom.xml.template +1 -1
  132. package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/parent-pom.xml.template +15 -10
  133. package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/web-pom.xml.template +3 -3
  134. package/template/.codex/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +3 -3
  135. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +5 -1
  136. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +5 -2
  137. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +13 -10
  138. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +2 -1
  139. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +35 -3
  140. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +1 -1
  141. package/template/.codex/skills/yss-distributed-id/SKILL.md +1 -1
  142. package/template/.codex/skills/yss-dto/SKILL.md +5 -1
  143. package/template/.codex/skills/yss-excel-mvc/SKILL.md +1 -1
  144. package/template/.codex/skills/yss-exception/SKILL.md +5 -1
  145. package/template/.codex/skills/yss-formily-schema-generator/SKILL.md +1 -1
  146. package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +14 -6
  147. package/template/.codex/skills/yss-implementation-contract-compiler/agents/openai.yaml +1 -1
  148. package/template/.codex/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -0
  149. package/template/.codex/skills/yss-implementation-contract-compiler/references/slice-implementation-contract-v2.md +214 -0
  150. package/template/.codex/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +66 -204
  151. package/template/.codex/skills/yss-layered-mvc-scaffold-generator/SKILL.md +15 -2
  152. package/template/.codex/skills/yss-layered-mvc-scaffold-generator/scripts/generate_scaffold.mjs +28 -19
  153. package/template/.codex/skills/yss-layered-mvc-scaffold-generator/scripts/scaffold-generator.test.mjs +10 -10
  154. package/template/.codex/skills/yss-mybatis/SKILL.md +4 -0
  155. package/template/.codex/skills/yss-openapi-draft-review/SKILL.md +1 -1
  156. package/template/.codex/skills/yss-openapi-governance/SKILL.md +1 -1
  157. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +4 -4
  158. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +29 -7
  159. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +6 -2
  160. package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +3 -1
  161. package/template/.codex/skills/yss-product-lifecycle/references/user-decisions.md +24 -4
  162. package/template/.codex/skills/yss-prototype-stage/SKILL.md +1 -1
  163. package/template/.codex/skills/yss-repository/SKILL.md +4 -0
  164. package/template/.codex/skills/yss-research/SKILL.md +1 -1
  165. package/template/.codex/skills/yss-resilience4j/SKILL.md +1 -1
  166. package/template/.codex/skills/yss-security-algorithm/SKILL.md +1 -1
  167. package/template/.codex/skills/yss-stage-decision/SKILL.md +1 -1
  168. package/template/.codex/skills/yss-stage-decision/references/domain-strategy-contract.md +2 -0
  169. package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  170. package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +3 -3
  171. package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +3 -3
  172. package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +33 -0
  173. package/template/.codex/skills/yss-tactical-design/SKILL.md +5 -1
  174. package/template/.codex/skills/yss-technical-design/SKILL.md +5 -1
  175. package/template/.codex/skills/yss-technical-design/references/technical-design-contract.md +1 -1
  176. package/template/.codex/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
  177. package/template/.codex/skills/yss-technical-design/tests/run-scenarios.mjs +1 -1
  178. package/template/.codex/skills/yss-ui/SKILL.md +1 -1
  179. package/template/.codex/skills/yss-ui-business-page-generation/SKILL.md +1 -1
  180. package/template/.codex/skills/yss-up-springboot3/SKILL.md +1 -1
  181. package/template/.codex/skills/yss-use-table-height/SKILL.md +1 -1
  182. package/template/.codex/skills/yss-use-tree-height/SKILL.md +1 -1
  183. package/template/.codex/skills/yss-userinfo/SKILL.md +1 -1
  184. package/template/.codex/skills/yss-validation/SKILL.md +5 -1
  185. package/template/.codex/skills/yss-web-controller/SKILL.md +5 -1
  186. package/template/.codex/skills/yss-web-controller/scripts/generate_controller.mjs +5 -2
  187. package/template/.codex/skills/ytable-usage/SKILL.md +1 -1
  188. package/template/.codex/skills/ytree-usage/SKILL.md +1 -1
  189. package/template/.cursor/skills/archify/SKILL.md +1 -1
  190. package/template/.cursor/skills/code-review/SKILL.md +12 -8
  191. package/template/.cursor/skills/file-export-download/SKILL.md +1 -1
  192. package/template/.cursor/skills/frontend-commit/SKILL.md +1 -1
  193. package/template/.cursor/skills/java-backend-commit/SKILL.md +1 -1
  194. package/template/.cursor/skills/llm-wiki/SKILL.md +1 -6
  195. package/template/.cursor/skills/lombok/SKILL.md +10 -336
  196. package/template/.cursor/skills/lombok/references/annotation-examples.md +307 -0
  197. package/template/.cursor/skills/maintaining-skills/SKILL.md +2 -1
  198. package/template/.cursor/skills/maintaining-skills/references/authoring.md +27 -0
  199. package/template/.cursor/skills/mapstruct/SKILL.md +11 -318
  200. package/template/.cursor/skills/mapstruct/references/annotation-examples.md +300 -0
  201. package/template/.cursor/skills/page-form-module/SKILL.md +1 -1
  202. package/template/.cursor/skills/page-skeleton/SKILL.md +1 -1
  203. package/template/.cursor/skills/theme-token-usage/SKILL.md +1 -1
  204. package/template/.cursor/skills/to-tickets/SKILL.md +1 -1
  205. package/template/.cursor/skills/using-git-worktrees/SKILL.md +1 -1
  206. package/template/.cursor/skills/wayfinder/SKILL.md +1 -1
  207. package/template/.cursor/skills/yedit-table-usage/SKILL.md +1 -1
  208. package/template/.cursor/skills/yss-api-integration/SKILL.md +1 -1
  209. package/template/.cursor/skills/yss-audit-log/SKILL.md +1 -1
  210. package/template/.cursor/skills/yss-cache/SKILL.md +1 -1
  211. package/template/.cursor/skills/yss-ddd-scaffold-generator/SKILL.md +16 -3
  212. package/template/.cursor/skills/yss-ddd-scaffold-generator/assets/templates/pom/application-pom.xml.template +1 -1
  213. package/template/.cursor/skills/yss-ddd-scaffold-generator/assets/templates/pom/parent-pom.xml.template +15 -10
  214. package/template/.cursor/skills/yss-ddd-scaffold-generator/assets/templates/pom/web-pom.xml.template +3 -3
  215. package/template/.cursor/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +3 -3
  216. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +5 -1
  217. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +5 -2
  218. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +13 -10
  219. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +2 -1
  220. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +35 -3
  221. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +1 -1
  222. package/template/.cursor/skills/yss-distributed-id/SKILL.md +1 -1
  223. package/template/.cursor/skills/yss-dto/SKILL.md +5 -1
  224. package/template/.cursor/skills/yss-excel-mvc/SKILL.md +1 -1
  225. package/template/.cursor/skills/yss-exception/SKILL.md +5 -1
  226. package/template/.cursor/skills/yss-formily-schema-generator/SKILL.md +1 -1
  227. package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +14 -6
  228. package/template/.cursor/skills/yss-implementation-contract-compiler/agents/openai.yaml +1 -1
  229. package/template/.cursor/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -0
  230. package/template/.cursor/skills/yss-implementation-contract-compiler/references/slice-implementation-contract-v2.md +214 -0
  231. package/template/.cursor/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +66 -204
  232. package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/SKILL.md +15 -2
  233. package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/scripts/generate_scaffold.mjs +28 -19
  234. package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/scripts/scaffold-generator.test.mjs +10 -10
  235. package/template/.cursor/skills/yss-mybatis/SKILL.md +4 -0
  236. package/template/.cursor/skills/yss-openapi-draft-review/SKILL.md +1 -1
  237. package/template/.cursor/skills/yss-openapi-governance/SKILL.md +1 -1
  238. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +4 -4
  239. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +29 -7
  240. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +6 -2
  241. package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +3 -1
  242. package/template/.cursor/skills/yss-product-lifecycle/references/user-decisions.md +24 -4
  243. package/template/.cursor/skills/yss-prototype-stage/SKILL.md +1 -1
  244. package/template/.cursor/skills/yss-repository/SKILL.md +4 -0
  245. package/template/.cursor/skills/yss-research/SKILL.md +1 -1
  246. package/template/.cursor/skills/yss-resilience4j/SKILL.md +1 -1
  247. package/template/.cursor/skills/yss-security-algorithm/SKILL.md +1 -1
  248. package/template/.cursor/skills/yss-stage-decision/SKILL.md +1 -1
  249. package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-contract.md +2 -0
  250. package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  251. package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +3 -3
  252. package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +3 -3
  253. package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +33 -0
  254. package/template/.cursor/skills/yss-tactical-design/SKILL.md +5 -1
  255. package/template/.cursor/skills/yss-technical-design/SKILL.md +5 -1
  256. package/template/.cursor/skills/yss-technical-design/references/technical-design-contract.md +1 -1
  257. package/template/.cursor/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
  258. package/template/.cursor/skills/yss-technical-design/tests/run-scenarios.mjs +1 -1
  259. package/template/.cursor/skills/yss-ui/SKILL.md +1 -1
  260. package/template/.cursor/skills/yss-ui-business-page-generation/SKILL.md +1 -1
  261. package/template/.cursor/skills/yss-up-springboot3/SKILL.md +1 -1
  262. package/template/.cursor/skills/yss-use-table-height/SKILL.md +1 -1
  263. package/template/.cursor/skills/yss-use-tree-height/SKILL.md +1 -1
  264. package/template/.cursor/skills/yss-userinfo/SKILL.md +1 -1
  265. package/template/.cursor/skills/yss-validation/SKILL.md +5 -1
  266. package/template/.cursor/skills/yss-web-controller/SKILL.md +5 -1
  267. package/template/.cursor/skills/yss-web-controller/scripts/generate_controller.mjs +5 -2
  268. package/template/.cursor/skills/ytable-usage/SKILL.md +1 -1
  269. package/template/.cursor/skills/ytree-usage/SKILL.md +1 -1
  270. package/template/.pi/skills/archify/SKILL.md +1 -1
  271. package/template/.pi/skills/code-review/SKILL.md +12 -8
  272. package/template/.pi/skills/file-export-download/SKILL.md +1 -1
  273. package/template/.pi/skills/frontend-commit/SKILL.md +1 -1
  274. package/template/.pi/skills/java-backend-commit/SKILL.md +1 -1
  275. package/template/.pi/skills/llm-wiki/SKILL.md +1 -6
  276. package/template/.pi/skills/lombok/SKILL.md +10 -336
  277. package/template/.pi/skills/lombok/references/annotation-examples.md +307 -0
  278. package/template/.pi/skills/maintaining-skills/SKILL.md +2 -1
  279. package/template/.pi/skills/maintaining-skills/references/authoring.md +27 -0
  280. package/template/.pi/skills/mapstruct/SKILL.md +11 -318
  281. package/template/.pi/skills/mapstruct/references/annotation-examples.md +300 -0
  282. package/template/.pi/skills/page-form-module/SKILL.md +1 -1
  283. package/template/.pi/skills/page-skeleton/SKILL.md +1 -1
  284. package/template/.pi/skills/theme-token-usage/SKILL.md +1 -1
  285. package/template/.pi/skills/to-tickets/SKILL.md +1 -1
  286. package/template/.pi/skills/using-git-worktrees/SKILL.md +1 -1
  287. package/template/.pi/skills/wayfinder/SKILL.md +1 -1
  288. package/template/.pi/skills/yedit-table-usage/SKILL.md +1 -1
  289. package/template/.pi/skills/yss-api-integration/SKILL.md +1 -1
  290. package/template/.pi/skills/yss-audit-log/SKILL.md +1 -1
  291. package/template/.pi/skills/yss-cache/SKILL.md +1 -1
  292. package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +16 -3
  293. package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/application-pom.xml.template +1 -1
  294. package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/parent-pom.xml.template +15 -10
  295. package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/web-pom.xml.template +3 -3
  296. package/template/.pi/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +3 -3
  297. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +5 -1
  298. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +5 -2
  299. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +13 -10
  300. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +2 -1
  301. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +35 -3
  302. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +1 -1
  303. package/template/.pi/skills/yss-distributed-id/SKILL.md +1 -1
  304. package/template/.pi/skills/yss-dto/SKILL.md +5 -1
  305. package/template/.pi/skills/yss-excel-mvc/SKILL.md +1 -1
  306. package/template/.pi/skills/yss-exception/SKILL.md +5 -1
  307. package/template/.pi/skills/yss-formily-schema-generator/SKILL.md +1 -1
  308. package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +14 -6
  309. package/template/.pi/skills/yss-implementation-contract-compiler/agents/openai.yaml +1 -1
  310. package/template/.pi/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -0
  311. package/template/.pi/skills/yss-implementation-contract-compiler/references/slice-implementation-contract-v2.md +214 -0
  312. package/template/.pi/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +66 -204
  313. package/template/.pi/skills/yss-layered-mvc-scaffold-generator/SKILL.md +15 -2
  314. package/template/.pi/skills/yss-layered-mvc-scaffold-generator/scripts/generate_scaffold.mjs +28 -19
  315. package/template/.pi/skills/yss-layered-mvc-scaffold-generator/scripts/scaffold-generator.test.mjs +10 -10
  316. package/template/.pi/skills/yss-mybatis/SKILL.md +4 -0
  317. package/template/.pi/skills/yss-openapi-draft-review/SKILL.md +1 -1
  318. package/template/.pi/skills/yss-openapi-governance/SKILL.md +1 -1
  319. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +4 -4
  320. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +29 -7
  321. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +6 -2
  322. package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +3 -1
  323. package/template/.pi/skills/yss-product-lifecycle/references/user-decisions.md +24 -4
  324. package/template/.pi/skills/yss-prototype-stage/SKILL.md +1 -1
  325. package/template/.pi/skills/yss-repository/SKILL.md +4 -0
  326. package/template/.pi/skills/yss-research/SKILL.md +1 -1
  327. package/template/.pi/skills/yss-resilience4j/SKILL.md +1 -1
  328. package/template/.pi/skills/yss-security-algorithm/SKILL.md +1 -1
  329. package/template/.pi/skills/yss-stage-decision/SKILL.md +1 -1
  330. package/template/.pi/skills/yss-stage-decision/references/domain-strategy-contract.md +2 -0
  331. package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  332. package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +3 -3
  333. package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +3 -3
  334. package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +33 -0
  335. package/template/.pi/skills/yss-tactical-design/SKILL.md +5 -1
  336. package/template/.pi/skills/yss-technical-design/SKILL.md +5 -1
  337. package/template/.pi/skills/yss-technical-design/references/technical-design-contract.md +1 -1
  338. package/template/.pi/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
  339. package/template/.pi/skills/yss-technical-design/tests/run-scenarios.mjs +1 -1
  340. package/template/.pi/skills/yss-ui/SKILL.md +1 -1
  341. package/template/.pi/skills/yss-ui-business-page-generation/SKILL.md +1 -1
  342. package/template/.pi/skills/yss-up-springboot3/SKILL.md +1 -1
  343. package/template/.pi/skills/yss-use-table-height/SKILL.md +1 -1
  344. package/template/.pi/skills/yss-use-tree-height/SKILL.md +1 -1
  345. package/template/.pi/skills/yss-userinfo/SKILL.md +1 -1
  346. package/template/.pi/skills/yss-validation/SKILL.md +5 -1
  347. package/template/.pi/skills/yss-web-controller/SKILL.md +5 -1
  348. package/template/.pi/skills/yss-web-controller/scripts/generate_controller.mjs +5 -2
  349. package/template/.pi/skills/ytable-usage/SKILL.md +1 -1
  350. package/template/.pi/skills/ytree-usage/SKILL.md +1 -1
  351. package/template/AGENTS.md +1 -0
  352. package/template/CONTEXT.md +2 -1
  353. package/template/docs/agents/backend-architecture-profiles.md +1 -1
  354. package/template/docs/agents/digital-human-roles.yaml +29 -1
  355. package/template/docs/agents/issue-tracker.md +2 -0
  356. package/template/docs/architecture/templates/engineering-baseline-review-template.md +6 -6
  357. package/template/docs/engineering/backend-platforms.json +174 -0
  358. package/template/docs/engineering/backend-platforms.md +77 -0
  359. package/template/docs/process/MATT-POCOCK-ENGINEERING-SKILLS.md +1 -0
  360. package/template/docs/process/existing-ui-baseline.md +1 -1
  361. package/template/docs/process/harness-process-tailoring.md +9 -1
  362. package/template/docs/process/lifecycle-artifact-map.md +6 -5
  363. package/template/docs/process/lifecycle-registry-baseline.json +2 -1
  364. package/template/docs/process/lifecycle-registry.yaml +17 -8
  365. package/template/docs/process/schemas/backend-architecture-identity.schema.json +91 -0
  366. package/template/docs/process/schemas/digital-human-task-package.schema.json +3 -1
  367. package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +8 -0
  368. package/template/docs/process/schemas/project-scaffold-contract.schema.json +602 -83
  369. package/template/docs/process/schemas/review-bundle.schema.json +42 -0
  370. package/template/docs/process/schemas/scaffold-architecture-decisions.schema.json +323 -39
  371. package/template/docs/process/schemas/slice-implementation-contract-v3.schema.json +925 -0
  372. package/template/docs/process/strategic-handoff-package.md +5 -11
  373. package/template/docs/templates/approval-record-template.yaml +2 -0
  374. package/template/docs/templates/build-architecture-checklist-template.md +2 -2
  375. package/template/docs/templates/implementation-routing-template.md +4 -4
  376. package/template/docs/templates/review-bundle-template.yaml +26 -0
  377. package/template/docs/templates/vertical-slice-ticket-template.md +22 -31
  378. package/template/scripts/backend-platforms +14 -0
  379. package/template/scripts/lib/approval-record.mjs +52 -7
  380. package/template/scripts/lib/approved-execution-context.mjs +31 -8
  381. package/template/scripts/lib/backend-architecture.mjs +6 -0
  382. package/template/scripts/lib/backend-platform-provenance.mjs +67 -0
  383. package/template/scripts/lib/backend-platform-verification.mjs +210 -0
  384. package/template/scripts/lib/backend-platform.mjs +175 -0
  385. package/template/scripts/lib/backend-scaffold-prerequisites.mjs +1 -1
  386. package/template/scripts/lib/decision-continuation.mjs +79 -0
  387. package/template/scripts/lib/delivery-preflight.mjs +6 -5
  388. package/template/scripts/lib/digital-human-roles.mjs +10 -0
  389. package/template/scripts/lib/frontend-delivery-boundary.mjs +3 -0
  390. package/template/scripts/lib/implementation-contract-compiler.mjs +42 -9
  391. package/template/scripts/lib/lifecycle-controls.mjs +2 -2
  392. package/template/scripts/lib/lifecycle-transition.mjs +3 -1
  393. package/template/scripts/lib/plan-spec-entry.mjs +3 -3
  394. package/template/scripts/lib/scaffold-local-database.mjs +1 -0
  395. package/template/scripts/lib/slice-applicability.mjs +10 -0
  396. package/template/scripts/lib/slice-contract-preparation.mjs +257 -0
  397. package/template/scripts/lib/slice-contract-views.mjs +52 -0
  398. package/template/scripts/lib/slice-contract.mjs +211 -0
  399. package/template/scripts/lib/slice-repositories.mjs +49 -0
  400. package/template/scripts/lib/slice-task-package.mjs +66 -0
  401. package/template/scripts/lib/strategic-handoff-io.mjs +7 -0
  402. package/template/scripts/lib/strategic-handoff.mjs +33 -8
  403. package/template/scripts/lib/task-package.mjs +6 -2
  404. package/template/scripts/lib/technical-design-boundary.mjs +1 -0
  405. package/template/scripts/lib/user-decision-reuse.mjs +1 -0
  406. package/template/scripts/lib/user-decision.mjs +17 -3
  407. package/template/scripts/preflight-delivery +2 -2
  408. package/template/scripts/slice-contract +30 -0
  409. package/template/scripts/verify-backend-platform-matrix +69 -0
  410. package/template/scripts/verify-scaffold-architecture-decisions +5 -0
  411. package/template/scripts/verify-user-decision +7 -2
  412. package/template/skills-lock.json +62 -57
  413. package/template.snapshot.json +3 -3
@@ -0,0 +1,211 @@
1
+ import {validateExistingUiBaseline} from './existing-ui-baseline.mjs';
2
+ import {sliceRepositories} from './slice-repositories.mjs';
3
+ import { sliceCheckApplicability } from './slice-applicability.mjs';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { parseDocument } from '../vendor/yaml.mjs';
7
+ import { safe, hash, digest, schema } from './strategic-handoff-io.mjs';
8
+
9
+ const originals = new WeakMap();
10
+ const sourceSnapshots = new WeakMap();
11
+ const nonempty = value => typeof value === 'string' && value.trim();
12
+ const unique = values => [...new Set(values)];
13
+ const fail = message => { throw new TypeError(`slice-contract-invalid: ${message}`); };
14
+ const requireThat = (ok, message) => { if (!ok) fail(message); };
15
+ export const sourceSliceContract = value => originals.get(value) || value?.slice_contract || value;
16
+ export function parseSliceYaml(bytes) {
17
+ const doc = parseDocument(String(bytes), { uniqueKeys: true, intAsBigInt: true });
18
+ requireThat(!doc.errors.length, `YAML 无效: ${doc.errors[0]?.message}`);
19
+ const value = doc.toJS({ maxAliasCount: 0 });
20
+ const convert = item => {
21
+ if (typeof item === 'bigint') {
22
+ requireThat(item <= BigInt(Number.MAX_SAFE_INTEGER) && item >= BigInt(Number.MIN_SAFE_INTEGER), 'YAML 整数超出精确范围,请使用字符串');
23
+ return Number(item);
24
+ }
25
+ if (Array.isArray(item)) return item.map(convert);
26
+ if (item && typeof item === 'object') return Object.fromEntries(Object.entries(item).map(([k,v]) => [k,convert(v)]));
27
+ requireThat(typeof item !== 'number' || Number.isFinite(item), 'YAML 非有限数值');
28
+ return item;
29
+ };
30
+ return convert(value);
31
+ }
32
+ export function withinSlicePath(candidate, parent) {
33
+ if (!nonempty(candidate) || !nonempty(parent)) return false;
34
+ const rel = path.relative(path.resolve(parent), path.resolve(candidate));
35
+ return rel === '' || (!path.isAbsolute(rel) && rel !== '..' && !rel.startsWith(`..${path.sep}`));
36
+ }
37
+ function safeWritePath(value) {
38
+ requireThat(nonempty(value) && !path.isAbsolute(value) && !value.split(/[\\/]/).includes('..') && !/[\x00-\x1f*?{}\[\]]/.test(value), `写范围必须为明确的仓库相对路径: ${value}`);
39
+ }
40
+ export function resolveSliceBasis(contract, key, stack = []) {
41
+ requireThat(!stack.includes(key), `依据别名循环: ${[...stack,key].join(' -> ')}`);
42
+ const binding = contract.basis?.[key];
43
+ requireThat(binding !== undefined, `缺少上游依据 ${key}`);
44
+ return typeof binding === 'string' ? resolveSliceBasis(contract,binding,[...stack,key]) : binding;
45
+ }
46
+ export function readSliceSources(contract, { root = process.cwd() } = {}) {
47
+ const result = {}, bytesByPath=new Map();
48
+ for (const key of Object.keys(contract.basis)) {
49
+ const binding = resolveSliceBasis(contract,key);
50
+ const file=safe(root,binding.ref);
51
+ if(!bytesByPath.has(file))bytesByPath.set(file,fs.readFileSync(file));
52
+ const bytes=bytesByPath.get(file);
53
+ requireThat(hash(bytes) === binding.digest, `stale: 上游依据 ${key} 原始字节变化`);
54
+ result[key] = { ...binding, text: bytes.toString('utf8') };
55
+ }
56
+ return result;
57
+ }
58
+ export function sliceArchitectureEvidence(contract,sources) {
59
+ const identity=contract.resolution.architecture_identity;
60
+ if(!identity)return undefined;
61
+ const keys=['engineering_baseline','repository_registration','manifest'];
62
+ if(identity.schema_version!==2)return Object.fromEntries(keys.map(key=>[key,parseSliceYaml(sources[key].text)]));
63
+ const registration=parseSliceYaml(sources.repository_registration.text);
64
+ const evidence={repository_registration:resolveSliceBasis(contract,'repository_registration')};
65
+ for(const key of ['engineering_baseline','manifest']) {
66
+ const original=registration.architecture_evidence?.[key],bound=resolveSliceBasis(contract,key);
67
+ requireThat(original?.ref===bound.ref&&original?.digest===bound.digest,`登记与 ${key} 绑定冲突`);
68
+ evidence[key]=original;
69
+ }
70
+ return evidence;
71
+ }
72
+ function requireKeys(value, names, label) {
73
+ for (const name of names) requireThat(value[name] !== undefined, `${label} 缺少 ${name}`);
74
+ }
75
+ function locate(text, locator) {
76
+ if(locator.startsWith('pointer:')) {
77
+ const value=locator.slice(8).split('/').slice(1).reduce((current,key)=>current?.[key.replaceAll('~1','/').replaceAll('~0','~')],parseSliceYaml(text));
78
+ requireThat(value!==undefined,`定位缺失: ${locator}`);return JSON.stringify(value);
79
+ }
80
+ const lines = text.split('\n');
81
+ const range = /^lines:(\d+)-(\d+)$/.exec(locator);
82
+ if (range) {
83
+ const start=Number(range[1]),end=Number(range[2]);
84
+ requireThat(start>=1&&end>=start&&end<=lines.length,`定位范围无效: ${locator}`);
85
+ return lines.slice(start-1,end).join('\n');
86
+ }
87
+ const body=text.replace(/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/,'');
88
+ const matches=body.split('\n').filter(line=>line.includes(locator));
89
+ requireThat(matches.length===1, `定位缺失或不唯一: ${locator}`);
90
+ return matches[0];
91
+ }
92
+ export function sliceAcceptanceText(contract, sources) {
93
+ return Object.fromEntries(Object.entries(contract.acceptance).map(([id,item])=>{
94
+ requireThat(sources[item.source],`验收 ${id} 来源缺失`);
95
+ return [id,locate(sources[item.source].text,item.locator)];
96
+ }));
97
+ }
98
+ /** Validate the authoritative v3 document, then expand inherited facts ONLY in memory. */
99
+ export function normalizeSliceContract(document, options = {}) {
100
+ const raw = sourceSliceContract(document);
101
+ requireThat(raw && [2,3].includes(raw.schema_version), 'Slice Implementation Contract schema v1 已停止支持;需要 schema v2 或 v3');
102
+ if (raw.schema_version === 2) return structuredClone(raw);
103
+ schema(raw,'docs/process/schemas/slice-implementation-contract-v3.schema.json');
104
+ const sources=readSliceSources(raw,options), refs=Object.fromEntries(Object.entries(sources).map(([key,item])=>[key,item.ref]));
105
+ requireKeys(refs,['spec','ticket','engineering_baseline','implementation_repository','build_architecture_checklist'],'依据');
106
+ if(!raw.applicability.checks)requireKeys(refs,['architecture_review'],'依据');
107
+ else {
108
+ requireKeys(refs,['lifecycle_registry','process_tailoring'],'适用性依据');
109
+ const registry=parseSliceYaml(sources.lifecycle_registry.text),expected=sliceCheckApplicability(raw.scope,registry);
110
+ requireThat(digest(raw.applicability.checks)===digest(expected),'材料适用性与生命周期规则冲突');
111
+ if(expected['check.architecture-reviewed'].status==='required')requireKeys(refs,['architecture_review'],'命中检查');
112
+ }
113
+ if(raw.ticket_policy)requireThat(nonempty(sources.ticket.version),'冻结 Ticket 缺少需求版本');
114
+ const extension=raw.extensions || {}, scope=raw.scope, resolution=structuredClone(raw.resolution);
115
+ if(raw.ticket_policy&&scope.project_roots.length>1)requireThat(extension.cross_repo?.repository_bindings,'新跨仓草案缺少逐仓登记绑定');
116
+ const repositories=sliceRepositories(raw,sources,options);
117
+ for (const key of ['frontend','backend','api','cross_repo']) {
118
+ const item=raw.applicability[key];
119
+ if (item.status === 'required') requireThat(extension[key],`命中 ${key} 影响但缺少子合同`);
120
+ else {
121
+ requireThat(nonempty(item.reason),`${key} 不适用缺少理由`);
122
+ requireThat(!extension[key],`${key} 不适用时不得保存空子合同`);
123
+ }
124
+ }
125
+ for(const [impact,section]of [['frontend','frontend'],['ui','frontend'],['backend','backend'],['api','api'],['cross-repo','cross_repo']])if(scope.impacted_areas.includes(impact))requireThat(raw.applicability[section].status==='required',`影响面 ${impact} 与适用性冲突`);
126
+ if(scope.impacted_areas.some(x=>['data','persistence'].includes(x)))requireKeys(refs,['data_architecture'],'数据依据');
127
+ if (extension.frontend && raw.applicability.frontend.baseline_kind==='existing-ui-baseline') {
128
+ requireThat(raw.applicability.frontend.ui_change==='none'&&!scope.impacted_areas.includes('ui'),'既有 UI 基线不能承接 UI 变化');
129
+ requireKeys(refs,['existing_ui_baseline','frontend_delivery'],'既有 UI 依据');
130
+ const observed=parseSliceYaml(sources.existing_ui_baseline.text);
131
+ const validation=validateExistingUiBaseline(observed,{bundleRoot:path.dirname(safe(options.root||process.cwd(),sources.existing_ui_baseline.ref))});
132
+ requireThat(validation.errors.length===0,`既有 UI 基线不可消费: ${validation.errors.join('; ')}`);
133
+ requireThat(extension.frontend.visual_baseline_case_ids.every(id=>observed.cases.some(c=>c.case_id===id)),'既有 UI 用例未被基线覆盖');
134
+ } else if (extension.frontend) requireKeys(refs,['requirement_freeze','low_fidelity_review','prototype_review','prototype_profile_decision','prototype_deliverable','prototype_deliverable_verification','prototype_confirmation','visual_baseline','state_matrix'],'前端依据');
135
+ if (extension.backend) {
136
+ requireKeys(refs,['technical_design','repository_registration','manifest','backend_repository','maven_wrapper'],'后端依据');
137
+ requireThat(resolution.architecture_identity||repositories&&Object.values(repositories).some(r=>r.resolution.architecture_identity),'后端缺少架构身份');
138
+ requireThat(nonempty(sources.technical_design.version),'技术设计缺少版本');
139
+ for (const selector of extension.backend.design_refs) locate(sources.technical_design.text,selector);
140
+ }
141
+ requireKeys(refs,[extension.api?'openapi_freeze':'no_api_impact_record'],'API 依据');
142
+ requireThat(!refs[extension.api?'no_api_impact_record':'openapi_freeze'],'API 影响结论冲突');
143
+ for (const p of scope.allowed_write_paths) safeWritePath(p);
144
+ requireThat(!scope.project_roots.some(p=>/^app\/(backend|frontend)(\/|$)/.test(p)), '禁止 app/backend 或 app/frontend');
145
+ if (scope.implementation_path_policy !== 'external-repository-native') for(const p of scope.project_roots) requireThat(/^apps\/(backend|frontend)\/[^/]+/.test(p),'Harness 工程必须落入具体 project 目录');
146
+ sliceAcceptanceText(raw,sources);
147
+ const unitIds=new Set(), usedChecks=new Set(), covered=new Set();
148
+ const expected=Object.keys(raw.acceptance);
149
+ for(const [id,check] of Object.entries(raw.verification)) {
150
+ requireThat(scope.project_roots.some(p=>withinSlicePath(check.cwd,p)),`验证 ${id} 的 cwd 未登记`);
151
+ if(check.dependency_roots)requireThat(repositories&&check.dependency_roots.every(p=>repositories[p]),`验证 ${id} 依赖仓库未登记`);
152
+ requireThat(check.acceptance_refs.length && check.acceptance_refs.every(ref=>expected.includes(ref)),`验证 ${id} 验收引用无效`);
153
+ }
154
+ const work_units=raw.work_units.map(unit=>{
155
+ requireThat(!unitIds.has(unit.id),`工作单元重复: ${unit.id}`);unitIds.add(unit.id);
156
+ const allowed=unit.allowed_write_paths || scope.allowed_write_paths;
157
+ for(const p of allowed) { safeWritePath(p);requireThat(scope.allowed_write_paths.some(parent=>withinSlicePath(p,parent)),`任务 ${unit.id} 写范围越界: ${p}`); }
158
+ const root=unit.project_root || (scope.project_roots.length===1?scope.project_roots[0]:null);
159
+ requireThat(scope.project_roots.includes(root),`任务 ${unit.id} 必须选择登记的 project_root`);
160
+ const checks=unique([...Object.keys(raw.verification).filter(id=>raw.verification[id].required_for_all),...unit.verification_refs]);
161
+ requireThat(checks.every(id=>raw.verification[id]),`任务 ${unit.id} 引用未知验证`);
162
+ requireThat(checks.every(id=>withinSlicePath(raw.verification[id].cwd,root)),`任务 ${unit.id} 验证执行仓库冲突`);
163
+ const skills=[unit.primary_skill,...(unit.supporting_skills || [])];
164
+ requireThat(skills.every(id=>resolution.required_skills.includes(id)),`任务 ${unit.id} Skill 不在冻结闭包内`);
165
+ requireThat(unit.acceptance_refs.every(id=>expected.includes(id)&&checks.some(k=>raw.verification[k].acceptance_refs.includes(id))),`任务 ${unit.id} 验收没有验证覆盖`);
166
+ for(const id of unit.acceptance_refs)covered.add(id);
167
+ for(const id of checks)usedChecks.add(id);
168
+ if(unit.tdd_mode==='controlled-generation') {
169
+ requireThat(unit.controlled_generation,'controlled-generation 缺少受控例外');
170
+ requireKeys(unit.controlled_generation,['exception_reason','generator','generator_inputs','expected_files','verification_commands','behavior_tests_after_generation'],'受控生成');
171
+ } else requireThat(!unit.controlled_generation,'行为测试不得携带受控生成例外');
172
+ const work_unit={...unit,allowed_write_paths:allowed,project_root:root,supporting_skills:unit.supporting_skills||[],verification:checks.map(id=>({id,...raw.verification[id]})),verification_commands:checks.map(id=>raw.verification[id].command),expected_evidence:unique(checks.flatMap(id=>raw.verification[id].expected_evidence)),forbidden_patterns:unique([...(scope.forbidden_patterns||[]),...(unit.forbidden_patterns||[])])};
173
+ return {...work_unit,contract_id:raw.contract_id,contract_version:raw.contract_version,work_unit};
174
+ });
175
+ requireThat(expected.every(id=>covered.has(id)), '存在未被工作单元覆盖的验收');
176
+ requireThat(Object.keys(raw.verification).every(id=>usedChecks.has(id)),'存在未分配的验证要求');
177
+ if(repositories)for(const id of extension.cross_repo.integration_verification)requireThat(raw.verification[id]?.dependency_roots?.length,'联合验证必须引用有依赖仓库和明确 cwd 的 verification');
178
+ const allChecks=Object.values(raw.verification);
179
+ resolution.freshness='current'; // Only after every bound source was read and verified above.
180
+ if(resolution.architecture_identity) {
181
+ resolution.architecture_identity_digest=digest(resolution.architecture_identity).slice(7);
182
+ resolution.architecture_evidence=sliceArchitectureEvidence(raw,sources);
183
+ }
184
+ if(refs.technical_design)resolution.technical_design=resolveSliceBasis(raw,'technical_design');
185
+ if(refs.frontend_delivery)resolution.frontend_delivery={acceptance_ref:refs.frontend_delivery,digest:sources.frontend_delivery.digest};
186
+ const common={...scope,required_capabilities:resolution.required_capabilities,required_skills:resolution.required_skills,verification_commands:allChecks.map(c=>c.command),expected_evidence_files:unique(allChecks.flatMap(c=>c.expected_evidence)),quality_baseline_ref:refs.engineering_baseline,forbidden_patterns:scope.forbidden_patterns||[],full_reroute_triggers:scope.full_reroute_triggers||[]};
187
+ const normalized={...structuredClone(raw),...(repositories?{repositories}:{}),common,resolution,lifecycle_refs:{...refs,openapi_freeze_or_no_impact:refs.openapi_freeze||refs.no_api_impact_record},readiness:{blockers:[],stale_inputs:[],not_applicable:Object.entries(raw.applicability).filter(([,a])=>a.status==='not-applicable').map(([item,a])=>({item,reason:a.reason}))},work_units,
188
+ frontend:extension.frontend?{status:'required',...extension.frontend,approved_prototype_ref:refs.prototype_confirmation,state_matrix_ref:refs.state_matrix,visual_baseline_ref:refs.visual_baseline,...(resolution.frontend_delivery?{delivery:resolution.frontend_delivery}:{})}:{status:'not-applicable'},
189
+ backend:extension.backend?{status:'required',...extension.backend}:{status:'not-applicable'},
190
+ contract:{api_impact:!!extension.api,...(extension.api?{freeze_ref:refs.openapi_freeze,...extension.api}:{no_api_impact_ref:refs.no_api_impact_record})},
191
+ cross_repo:extension.cross_repo?{repositories:scope.project_roots,...extension.cross_repo}:{}
192
+ };
193
+ originals.set(normalized,raw);
194
+ sourceSnapshots.set(normalized,sources);
195
+ return normalized;
196
+ }
197
+ export function readSliceContract(ref,{root=process.cwd(),diagnostic=false}={}) {
198
+ const bytes=fs.readFileSync(safe(root,ref)),raw=sourceSliceContract(parseSliceYaml(bytes));
199
+ const contract=diagnostic&&raw.status==='blocked'?null:normalizeSliceContract(raw,{root});
200
+ return {contract,raw,sources:structuredClone(sourceSnapshots.get(contract)||{}),binding:{ref,id:raw.contract_id,version:raw.contract_version,digest:hash(bytes)}};
201
+ }
202
+
203
+ /** Select only after full normalization; original raw identity is retained for approval comparison. */
204
+ export function selectSliceWorkUnit(contract,workUnitId) {
205
+ if(!contract.repositories)return contract;
206
+ const unit=contract.work_units.find(u=>u.id===workUnitId);
207
+ requireThat(unit,'跨仓执行必须选择唯一 work_unit_id');
208
+ const repo=contract.repositories[unit.project_root];
209
+ const selected={...contract,backend:repo.project.delivery_role==='backend'?contract.backend:{status:'not-applicable'},frontend:repo.project.delivery_role==='frontend'?{...contract.frontend,...(repo.resolution.frontend_delivery?{delivery:repo.resolution.frontend_delivery}:{})}:{status:'not-applicable'},resolution:{...repo.resolution,freshness:contract.resolution.freshness},common:{...contract.common,project_roots:[unit.project_root],allowed_write_paths:unit.allowed_write_paths},lifecycle_refs:{...contract.lifecycle_refs,...Object.fromEntries(Object.entries(repo.basis).map(([k,v])=>[k,v.ref]))}};
210
+ originals.set(selected,sourceSliceContract(contract));return selected;
211
+ }
@@ -0,0 +1,49 @@
1
+ import fs from 'node:fs';
2
+ import * as lifecycle from './lifecycle-transition.mjs';
3
+ import path from 'node:path';
4
+ import {digest,schema} from './strategic-handoff-io.mjs';
5
+ import {parseSliceYaml,resolveSliceBasis,withinSlicePath,sliceArchitectureEvidence} from './slice-contract.mjs';
6
+ const check=(ok,message)=>{if(!ok)throw new TypeError(`slice-repository-invalid: ${message}`);};
7
+ /** All file facts stay in basis. Repository entries only select those facts. */
8
+ export function sliceRepositories(contract,sources,{root=process.cwd()}={}) {
9
+ const bindings=contract.extensions?.cross_repo?.repository_bindings;if(!bindings)return null;
10
+ check(lifecycle.SLICE_REPOSITORY_PREPARATION_PROTOCOL===1&&typeof lifecycle.validateImplementationRepositoriesReady==='function','接收端不支持当前来源的多项目准备协议,不能套用本地默认规则');
11
+ check(sources.repository_preparation,'缺少多项目准备结果');
12
+ const preparation=parseSliceYaml(sources.repository_preparation.text);
13
+ schema(preparation,'docs/process/schemas/implementation-repository-preparation-result.schema.json');
14
+ const ready=lifecycle.validateImplementationRepositoriesReady({implementation_repository_preparation:preparation,delivery_impacts:Object.fromEntries(['backend','frontend'].map(role=>[role,preparation.projects.some(p=>p.delivery_role===role&&p.status!=='not-applicable')]))},{root,exists:ref=>fs.existsSync(path.resolve(root,ref)),read:ref=>fs.readFileSync(path.resolve(root,ref),'utf8')});
15
+ check(ready.result!=='blocked',`多项目准备未就绪: ${ready.missing_requirements.join('; ')}`);
16
+ check(new Set(Object.keys(bindings).map(p=>path.resolve(p))).size===Object.keys(bindings).length,'工程根存在路径别名,不能重复登记');
17
+ const result={},identities=new Set();
18
+ for(const [projectRoot,keys]of Object.entries(bindings)) {
19
+ const references=Object.entries(keys).filter(([name])=>!['recipe_refs','capability_refs'].includes(name));
20
+ const selected=Object.fromEntries(references.map(([name,key])=>{check(sources[key],`缺少 basis.${key}`);return[name,sources[key]];}));
21
+ const registration=parseSliceYaml(selected.implementation_repository.text),baseline=parseSliceYaml(selected.engineering_baseline.text);
22
+ const actual=path.resolve(registration.local_worktree,registration.project_root||'.');
23
+ check(path.resolve(projectRoot)===actual,'工程根与逐仓登记冲突');
24
+ const project=preparation.projects.filter(p=>p.project_id===registration.project_id&&p.repository_ref===selected.implementation_repository.ref);
25
+ check(project.length===1&&project[0].status!=='not-applicable'&&path.resolve(project[0].project_root)===actual,'准备结果没有唯一当前工程');
26
+ const identityKey=JSON.stringify([registration.repository_id,registration.project_id]);check(!identities.has(identityKey),'同一仓库工程不能重复绑定');identities.add(identityKey);
27
+ check(registration.status==='current'&&baseline.status==='current','逐仓登记或基线非 current');
28
+ check(registration.repository_id===baseline.repository_id&&registration.project_id===baseline.project_id,'逐仓基线身份冲突');
29
+ check(Array.isArray(registration.allowed_write_paths)&&registration.allowed_write_paths.length,'登记缺少写边界');
30
+ if(project[0].delivery_role==='backend')check(selected.technical_design&&project[0].design_prerequisites.technical_design.digest===selected.technical_design.digest&&project[0].design_prerequisites.technical_design.ref===selected.technical_design.ref,'多项目准备与切片技术设计绑定冲突');
31
+ const identity=baseline.architecture_identity||registration.architecture_identity;
32
+ if(baseline.architecture_identity&&registration.architecture_identity)check(digest(baseline.architecture_identity)===digest(registration.architecture_identity),'逐仓架构冲突');
33
+ const basis=Object.fromEntries(references.map(([name,key])=>[name,resolveSliceBasis(contract,key)]));
34
+ basis.repository_registration??=basis.implementation_repository;
35
+ selected.repository_registration??=selected.implementation_repository;
36
+ const resolution={...contract.resolution};delete resolution.architecture_identity;
37
+ if(identity){resolution.architecture_identity=identity;resolution.architecture_identity_digest=digest(identity).slice(7);resolution.architecture_evidence=sliceArchitectureEvidence({basis,resolution},selected);}
38
+ if(basis.technical_design)resolution.technical_design=basis.technical_design;
39
+ if(basis.frontend_delivery)resolution.frontend_delivery={acceptance_ref:basis.frontend_delivery.ref,digest:basis.frontend_delivery.digest};
40
+ result[projectRoot]={registration,project:project[0],basis,resolution,recipe_refs:keys.recipe_refs,capability_refs:keys.capability_refs};
41
+ }
42
+ check(Object.keys(result).length===contract.scope.project_roots.length&&contract.scope.project_roots.every(p=>result[p]),'多仓绑定必须完整覆盖工程根');
43
+ for(const key of ['delivery_order','rollback_order'])check(contract.extensions.cross_repo[key].length===Object.keys(result).length&&contract.extensions.cross_repo[key].every(p=>result[p]),`${key} 必须完整且唯一列出工程根`);
44
+ for(const unit of contract.work_units) {
45
+ const repo=result[unit.project_root];check(repo,`工作单元 ${unit.id} 未选择唯一工程`);
46
+ check((unit.allowed_write_paths||contract.scope.allowed_write_paths).every(p=>repo.registration.allowed_write_paths.some(parent=>withinSlicePath(p,parent))),`工作单元 ${unit.id} 超出逐仓登记`);
47
+ }
48
+ return result;
49
+ }
@@ -0,0 +1,66 @@
1
+ import {enforceHarnessTaskScope} from './harness-execution-scope.mjs';
2
+ import { readFileSync } from 'node:fs';
3
+ import { ROOT, hash, safe, digest } from './strategic-handoff-io.mjs';
4
+ import { normalizeSliceContract, withinSlicePath, parseSliceYaml } from './slice-contract.mjs';
5
+ import { createApprovedExecutionContext, assertApprovedExecutionContext } from './approved-execution-context.mjs';
6
+ import { assertImplementationDecision } from './user-decision.mjs';
7
+ import { taskPackageDefaults, loadDigitalHumanRoles } from './digital-human-roles.mjs';
8
+ import { validateTaskPackageSchema } from './task-package-schema.mjs';
9
+ const fail=message=>{throw new TypeError(message);};
10
+ const equalArrays=(a,b)=>Array.isArray(a)&&a.length===b.length&&a.every((x,i)=>x===b[i]);
11
+ function generateTaskPackageDefaults(roleId,overrides,{rolesDoc}={}) {
12
+ const defaults=taskPackageDefaults(roleId,rolesDoc||loadDigitalHumanRoles());
13
+ return {schema_version:1,role_id:roleId,skill_source:{registry_ref:'docs/agents/digital-human-roles.yaml',defaults_ref:`taskPackageDefaults(${roleId})`,core_skills:defaults.core_skills,forbidden_skills:defaults.forbidden_skills},...overrides};
14
+ }
15
+
16
+ /** Compile dispatch from the approved YAML. Only runtime identity and task ID come from the caller. */
17
+ export function compileSliceTaskPackage(binding,{root=ROOT,work_unit_id,task_id,actor_id,runtime_id,execution_state='Worker',rolesDoc,user_decisions}={}) {
18
+ const actualRoles=parseSliceYaml(readFileSync(safe(root,'docs/agents/digital-human-roles.yaml')));
19
+ if(rolesDoc&&digest(rolesDoc)!==digest(actualRoles))fail('调用方不能替换接收端角色能力');
20
+ rolesDoc=actualRoles;
21
+ if(!actualRoles.runtimes.some(runtime=>runtime.id===runtime_id))fail('接收端不支持该 runtime_id');
22
+ const execution=createApprovedExecutionContext(binding,{root,work_unit_id});
23
+ const {contract}=assertApprovedExecutionContext(execution,{root});
24
+ if(contract.schema_version!==3)fail('v3 派发编译入口只接受 v3;v2 保留原派发路径');
25
+ const unit=contract.work_units.find(item=>item.id===work_unit_id);
26
+ if(!unit)fail('未找到指定 Slice 工作单元');
27
+ const checkpoint=readSliceDispatchApproval(root,binding.approval_ref);
28
+ const decisions=user_decisions||checkpoint.human_review?.user_decisions;
29
+ const output=generateTaskPackageDefaults(unit.role_id,{
30
+ task_id,work_unit_id,actor_id,runtime_id,execution_state,workflow_status:'not-started',stage_id:'stage.vertical-slice-implementation',
31
+ contract:{kind:'slice-implementation',contract_id:contract.contract_id,contract_version:contract.contract_version,status:'issued',contract_ref:binding.ref,slice_contract_ref:binding.ref,gate_refs:[binding.approval_ref]},
32
+ inputs:[binding.ref,...new Set(Object.values(contract.lifecycle_refs))],
33
+ objective:`${unit.behavior}(执行目录:${unit.project_root};完整约束读取 ${binding.ref})`,
34
+ allowed_write_paths:unit.allowed_write_paths,forbidden_actions:[...unit.work_unit.forbidden_patterns,'来源过期、越界、缺证据、验证失败或新增影响时停止并回交'],
35
+ expected_outputs:[unit.behavior],expected_evidence_files:unit.work_unit.expected_evidence,verification_commands:unit.work_unit.verification_commands,verification_results:[],
36
+ downstream_consumers:unit.downstream_consumers||['role.lifecycle-orchestrator'],convergence:{parent_work_unit:'work-unit.slice-implementation',convergence_ref:unit.convergence_ref||binding.approval_ref,conflict_escalation:'返回生命周期主控'},user_decisions:decisions
37
+ },{rolesDoc});
38
+ enforceHarnessTaskScope(output,{root});
39
+ validateTaskPackageSchema(output);
40
+ assertSliceV3TaskPackage(output,contract,{root});
41
+ return output;
42
+ }
43
+ function readSliceDispatchApproval(root,ref) {return parseSliceYaml(readFileSync(safe(root,ref)));}
44
+ export function assertSliceV3TaskPackage(value,slice,{root=ROOT}={}) {
45
+ enforceHarnessTaskScope(value,{root});
46
+ const contract=value.contract;
47
+ const current=normalizeSliceContract(slice,{root});
48
+ const roles=parseSliceYaml(readFileSync(safe(root,'docs/agents/digital-human-roles.yaml'))),defaults=taskPackageDefaults(value.role_id,roles);
49
+ if(!roles.runtimes.some(runtime=>runtime.id===value.runtime_id)||!defaults.stages.includes(value.stage_id))fail('接收端角色或运行时不支持当前任务');
50
+ if(!equalArrays(value.skill_source.core_skills,defaults.core_skills)||!equalArrays(value.skill_source.forbidden_skills,defaults.forbidden_skills))fail('任务角色能力与接收端不一致');
51
+ const unit=current.work_units.find(item=>item.id===value.work_unit_id);
52
+ if(unit&&[unit.primary_skill,...(unit.supporting_skills||[])].some(skill=>defaults.forbidden_skills.includes(skill)))fail('工作单元使用接收角色禁用 Skill');
53
+ if(!unit||unit.role_id!==value.role_id||current.contract_id!==contract.contract_id||current.contract_version!==contract.contract_version)fail('任务身份与 Slice v3 不一致');
54
+ if(!Array.isArray(contract.gate_refs)||contract.gate_refs.length!==1)fail('Slice v3 派发需要唯一批准 checkpoint 引用');
55
+ const bytes=readFileSync(safe(root,contract.slice_contract_ref));
56
+ const execution=createApprovedExecutionContext({ref:contract.slice_contract_ref,digest:hash(bytes),id:current.contract_id,version:current.contract_version,approval_ref:contract.gate_refs[0]},{root,work_unit_id:value.work_unit_id});
57
+ assertApprovedExecutionContext(execution,{root,contract:current});
58
+ for(const allowed of value.allowed_write_paths)if(!unit.allowed_write_paths.some(parent=>withinSlicePath(allowed,parent)))fail('任务写范围超出 Slice v3');
59
+ for(const key of ['verification_commands','expected_evidence_files']) {
60
+ const required=key==='verification_commands'?unit.work_unit.verification_commands:unit.work_unit.expected_evidence;
61
+ if(!equalArrays(value[key],required))fail(`任务包遗漏或替换 Slice v3 ${key}`);
62
+ }
63
+ for(const item of unit.work_unit.forbidden_patterns)if(!value.forbidden_actions.includes(item))fail('任务包遗漏全局约束');
64
+ if(value.execution_state==='Worker')assertImplementationDecision({slice_contract_ref:contract.slice_contract_ref,vertical_slice_ticket_ref:current.lifecycle_refs.ticket,user_decisions:value.user_decisions},{root});
65
+ return value;
66
+ }
@@ -78,6 +78,13 @@ export function sourceApprovalPolicy(source) {
78
78
  roles.user_decision_policy ||= {gates:[]};
79
79
  ensure(!(roles.user_decision_policy.required_capabilities || []).some(id => id !== 'strategic-decision-reuse-v1'), '接收工具不支持源用户决定策略,请升级工具后验包');
80
80
  const policy=roles.gate_policy;
81
+ // Dedicated receivers may predate check_reviews. Mirror source check-review
82
+ // rules into their existing digital review lookup without changing source bytes.
83
+ for(const rule of policy.check_reviews || []) {
84
+ if(!(policy.digital_human_review||[]).some(x=>x.gate===rule.gate) && !(policy.dual_digital_human||[]).some(x=>x.gate===rule.gate)) {
85
+ policy.digital_human_review ||= [];policy.digital_human_review.push({gate:rule.gate,drafter:rule.drafter,countersigners:[...rule.countersigners]});
86
+ }
87
+ }
81
88
  for(const gate of policy.product_digital_human_with_biological_veto || []) {
82
89
  if(!(policy.biological_human||[]).includes(gate) && !(policy.digital_human_review||[]).some(x=>x.gate===gate) && !(policy.dual_digital_human||[]).some(x=>x.gate===gate)) {
83
90
  policy.digital_human_review ||= [];policy.digital_human_review.push({gate,countersigners:['role.product-manager']});
@@ -20,6 +20,19 @@ const SOURCE_SCHEMAS = new Map([
20
20
  ]);
21
21
  const CAPABILITIES=['backend-technical-design','frontend-engineering-design','delivery-coordination'];
22
22
 
23
+ function sourceApprovalRecord(document, gateId) {
24
+ if(document?.kind!=='review-bundle')return document;
25
+ for(const field of ['bundle_id','task_id','work_unit_id','review_session_id','role_id','runtime_id','principal_ref'])ensure(nonempty(document[field]),`组合审查缺少 ${field}`);
26
+ ensure(Array.isArray(document.reviews)&&document.reviews.length,'组合审查不能为空');
27
+ ensure(new Set(document.reviews.map(row=>row?.gate_id)).size===document.reviews.length,'组合审查 gate_id 重复');
28
+ const rows=document.reviews.filter(row=>row.gate_id===gateId);
29
+ ensure(rows.length===1,`组合审查缺少当前结论: ${gateId}`);
30
+ const row=rows[0];
31
+ ensure(row.role_id===document.role_id&&row.runtime_id===document.runtime_id&&row.principal_ref===document.principal_ref,'组合审查必须来自同一复核角色、运行时和实例');
32
+ ensure(!row.review_session_id||row.review_session_id===document.review_session_id,'组合审查 review_session_id 不一致');
33
+ return {...row,review_bundle_id:document.bundle_id,review_task_id:document.task_id,review_work_unit_id:document.work_unit_id,review_session_id:document.review_session_id};
34
+ }
35
+
23
36
  function deliveryReadme(handoff) {
24
37
  const sources=Object.entries(handoff.source).sort(([a],[b])=>a.localeCompare(b)).map(([key,value])=>`- \`${key}\`: \`${value.persisted_ref}\` (${value.version}, ${value.digest})`);
25
38
  const routes=handoff.consumer_routes.map(route=>`- \`${route.capability}\`: \`${route.activation}\` (${route.route_id})`);
@@ -75,6 +88,17 @@ export async function sourceApproval(record, roles, root) {
75
88
  const { assertApprovalUserDecision } = await import('./user-decision-reuse.mjs');
76
89
  assertApprovalUserDecision(record, roles, options);
77
90
  }
91
+ // Older dedicated receivers retain their own lifecycle policy. Normalize only
92
+ // this already-verified source approval, without granting local capabilities.
93
+ if (record.continuation_ref) {
94
+ ensure(roles.user_decision_policy.gates.includes(record.gate_id), '未登记的源延续批准边界');
95
+ const reviewers = roles.gate_policy.continuation_reviews?.[record.gate_id];
96
+ ensure(reviewers?.includes(record.role_id) && record.drafter_principal_ref && record.drafter_principal_ref !== record.principal_ref, '源授权延续缺少独立审查身份');
97
+ options.rolesDoc = structuredClone(roles);
98
+ const policy = options.rolesDoc.gate_policy;
99
+ policy.dual_digital_human = (policy.dual_digital_human || []).filter(x => x.gate !== record.gate_id);
100
+ policy.digital_human_review = [...(policy.digital_human_review || []).filter(x => x.gate !== record.gate_id), { gate: record.gate_id, countersigners: reviewers }];
101
+ }
78
102
  validateApprovalRecord(record,options);
79
103
  }
80
104
 
@@ -160,13 +184,14 @@ export async function inspectSource(root, handoffRef) {
160
184
  const indexes=extractTraceability(strategy);
161
185
  const sourceRoles=read(safe(root,'docs/agents/digital-human-roles.yaml'));
162
186
  const roles=sourceApprovalPolicy(sourceRoles);
163
- for (const [artifact, version] of [[strategy,strategy.domain_version],[stage,stage.package_version]]) {
164
- if(artifact.approval) { const record=read(safe(root,artifact.approval.approval_ref));await sourceApproval(record,roles,root);ensure(artifact.approval.current_version===version,'资产内置批准版本过期'); }
187
+ for (const [artifact, version, gateId] of [[strategy,strategy.domain_version,'check.domain-strategy-approved'],[stage,stage.package_version,'check.stage-decision-package-approved']]) {
188
+ if(artifact.approval) { const record=sourceApprovalRecord(read(safe(root,artifact.approval.approval_ref)),gateId);await sourceApproval(record,roles,root);ensure(artifact.approval.current_version===version,'资产内置批准版本过期'); }
165
189
  }
166
190
  // Source packages retain their published approval vocabulary. Never promote old approvals into current checkpoint gates.
167
191
  const currentPlan = (roles.gate_policy.dual_digital_human || []).some(rule => rule.gate === 'gate.plan-approved');
168
- const terminalGate=currentPlan?'gate.plan-approved':countersignRuleForGate(roles.gate_policy,'gate.strategic-design-handoff-approved')?'gate.strategic-design-handoff-approved':'gate.stage-decision-package-approved';
169
- const expectedGates={domain_strategy_ref:currentPlan?'gate.plan-approved':'gate.domain-strategy-approved',stage_decision_package_ref:currentPlan?'gate.plan-approved':'gate.stage-decision-package-approved',spec_ref:'gate.spec-baseline-approved',prototype_ref:currentPlan?'gate.product-design-approved':'gate.user-confirmation',visual_baseline_ref:currentPlan?'gate.product-design-approved':'gate.user-confirmation',business_ticket_set_ref:terminalGate,handoff:terminalGate};
192
+ const explicitlyReviewed=(gate)=>(roles.gate_policy.digital_human_review||[]).some(rule=>rule.gate===gate)||(roles.gate_policy.dual_digital_human||[]).some(rule=>rule.gate===gate)||(roles.gate_policy.biological_human||[]).includes(gate);
193
+ const terminalGate=currentPlan||explicitlyReviewed('gate.strategic-design-handoff-approved')?'gate.strategic-design-handoff-approved':'gate.stage-decision-package-approved';
194
+ const expectedGates={domain_strategy_ref:currentPlan?'gate.plan-approved':'gate.domain-strategy-approved',stage_decision_package_ref:currentPlan?'gate.plan-approved':'gate.stage-decision-package-approved',spec_ref:'gate.spec-baseline-approved',prototype_ref:currentPlan?'gate.product-design-approved':'gate.user-confirmation',visual_baseline_ref:currentPlan?'gate.product-design-approved':'gate.user-confirmation',business_ticket_set_ref:currentPlan?'gate.plan-approved':terminalGate,handoff:terminalGate};
170
195
  expectedGates.existing_ui_baseline_ref=expectedGates.prototype_ref;
171
196
  const bindings={...handoff.source,handoff:{id:handoff.handoff_id,version:handoff.handoff_version,persisted_ref:handoffRef,status:'approved'}};
172
197
  for(const [key,ref] of Object.entries(bindings)) {
@@ -183,14 +208,14 @@ export async function inspectSource(root, handoffRef) {
183
208
  }
184
209
  } else actual=bytesDigest(readFileSync(safe(root,ref.persisted_ref)),approval.digest_kind);
185
210
  if(key!=='handoff')ensure(ref.digest===actual,`源资产摘要过期: ${key}`);
186
- const record=read(safe(root,approval.record_ref));
211
+ const record=sourceApprovalRecord(read(safe(root,approval.record_ref)),approval.gate_id);
187
212
  if(key==='existing_ui_baseline_ref')ensure(record.subject_ref===`${ref.persisted_ref}/${ref.manifest_ref}`,'既有 UI 用户决定必须以当前 manifest 为批准主体');
188
213
  await sourceApproval(record,roles,root);
189
214
  ensure(record.gate_id===approval.gate_id,`批准门禁不匹配: ${key}`);
190
215
  ensure((record.artifact_bindings || []).some(x=>x.id===(ref.id||ref.baseline_id) && x.version===ref.version && x.digest===actual),`批准记录未绑定当前资产: ${key}`);
191
216
  }
192
217
  if (roles.user_decision_policy.required_capabilities?.includes('strategic-decision-reuse-v1')) {
193
- const record=read(safe(root,config.approvals.handoff.record_ref));
218
+ const record=sourceApprovalRecord(read(safe(root,config.approvals.handoff.record_ref)),config.approvals.handoff.gate_id);
194
219
  const scope=read(safe(root,record.subject_ref));
195
220
  ensure(scope.kind==='strategic-delivery-scope' && scope.schema_version===1, '交接必须绑定独立的交付范围清单');
196
221
  const {package_export,status,...delivery}=handoff;
@@ -198,7 +223,7 @@ export async function inspectSource(root, handoffRef) {
198
223
  ensure(scope.assets?.some(asset=>asset.ref===scope.delivery_ref && asset.digest===hash(readFileSync(safe(root,scope.delivery_ref)))), '交接内容快照缺少批准覆盖');
199
224
  for (const [key,ref] of Object.entries(handoff.source)) {
200
225
  const file=['visual_baseline_ref','existing_ui_baseline_ref'].includes(key)?`${ref.persisted_ref}/${ref.manifest_ref}`:ref.persisted_ref;
201
- const decisionBoundaries=key==='business_ticket_set_ref'?['gate.spec-baseline-approved',terminalGate]:[expectedGates[key]];
226
+ const decisionBoundaries=[expectedGates[key]];
202
227
  ensure(scope.assets?.some(asset=>asset.ref===file && asset.version===ref.version && decisionBoundaries.includes(asset.boundary) && asset.digest===hash(readFileSync(safe(root,file)))), `交付范围清单遗漏当前资产: ${key}`);
203
228
  }
204
229
  }
@@ -217,7 +242,7 @@ function collect(root, handoffRef, handoff, config) {
217
242
  const enqueue=ref=> { if(symbolic[ref])queue.push(symbolic[ref]); else if(/^https?:\/\//i.test(ref))return; else if(ref.startsWith('evidence.'))throw new TypeError(`未解析 evidence ID: ${ref}`); else if(ref.includes('/') || /\.(?:md|yaml|json|html|png|txt|log)$/.test(ref))queue.push(ref); };
218
243
  function refs(value,key='') {
219
244
  if(Array.isArray(value)) { if(key==='evidence_refs') value.forEach(enqueue); else value.forEach(v=>refs(v,key)); }
220
- else if(value && typeof value==='object') for(const [k,v]of Object.entries(value)) { if(['approval_ref','persisted_ref','user_decision_ref','decision_reuse_ref','scope_ref','subject_ref','delivery_ref'].includes(k)&&typeof v==='string')enqueue(v); else if(k==='ref'&&typeof v==='string'&&!/^[a-z]+:\/\//i.test(v))enqueue(v); else refs(v,k); }
245
+ else if(value && typeof value==='object') for(const [k,v]of Object.entries(value)) { if(['approval_ref','persisted_ref','user_decision_ref','decision_reuse_ref','continuation_ref','plan_continuation_ref','scope_ref','subject_ref','delivery_ref'].includes(k)&&typeof v==='string')enqueue(v); else if(k==='ref'&&typeof v==='string'&&!/^[a-z]+:\/\//i.test(v))enqueue(v); else refs(v,k); }
221
246
  }
222
247
  let totalBytes = 0;
223
248
  while(queue.length) {
@@ -1,3 +1,6 @@
1
+ import { normalizeSliceContract } from './slice-contract.mjs';
2
+ import { assertSliceV3TaskPackage } from './slice-task-package.mjs';
3
+ export { compileSliceTaskPackage, assertSliceV3TaskPackage } from './slice-task-package.mjs';
1
4
  import { existsSync, readFileSync } from "node:fs";
2
5
  import path from "node:path";
3
6
  import { parseDocument } from "../vendor/yaml.mjs";
@@ -178,11 +181,12 @@ function validateContract(value, registry, lifecycle) {
178
181
  const contractPath = assertSafeRelativePath(contract.slice_contract_ref, "contract.slice_contract_ref");
179
182
  if (!existsSync(contractPath)) fail(`Slice Implementation Contract 不存在: ${contract.slice_contract_ref}`);
180
183
  const document = parseYaml(readFileSync(contractPath, "utf8"), "Slice Implementation Contract");
181
- const slice = document.slice_contract || document;
182
- if (slice.schema_version !== 2 || typeof slice.slice_id !== "string" || !slice.lifecycle_refs || !slice.readiness || !Array.isArray(slice.work_units)) fail("Slice Implementation Contract 需要 schema v2 及 slice_id/lifecycle_refs/readiness/work_units");
184
+ const slice = normalizeSliceContract(document,{root:ROOT});
185
+ if (![2,3].includes(slice.schema_version) || typeof slice.slice_id !== "string" || !slice.lifecycle_refs || !slice.readiness || !Array.isArray(slice.work_units)) fail("Slice Implementation Contract 需要 schema v2 及 slice_id/lifecycle_refs/readiness/work_units");
183
186
  if (slice.contract_id !== contract.contract_id || slice.contract_version !== contract.contract_version || slice.status !== "approved") fail("Slice Contract 必须是当前 approved 版本");
184
187
  const sliceUnit = slice.work_units.find((item) => item && item.id === value.work_unit_id);
185
188
  if (!sliceUnit) fail(`Slice Implementation Contract 缺少 work_unit_id: ${value.work_unit_id}`);
189
+ if(slice.schema_version===3)return assertSliceV3TaskPackage(value,slice,{root:ROOT});
186
190
  for (const field of ["role_id", "runtime_id", "task_package_ref", "contract_id", "contract_version", "allowed_write_paths"]) if (sliceUnit[field] === undefined) fail(`Slice Contract work_unit 缺少 ${field}`);
187
191
  if (sliceUnit.role_id !== value.role_id || sliceUnit.runtime_id !== value.runtime_id || sliceUnit.contract_id !== contract.contract_id || sliceUnit.contract_version !== contract.contract_version) fail("任务包与 Slice Contract work_unit 不一致");
188
192
  for (const allowed of value.allowed_write_paths) if (!sliceUnit.allowed_write_paths.includes(allowed)) fail(`allowed_write_paths 未获 Slice Contract 授权: ${allowed}`);
@@ -24,6 +24,7 @@ export function enforceTechnicalDesign(state = {}, { root = ROOT, execution, rea
24
24
  if(execution){
25
25
  assertApprovedExecutionContext(execution,{root,technicalDesign:data,architectureIdentity:state.architecture_identity,sliceId:state.slice_id});
26
26
  const approved=approvedExecutionBinding(execution);
27
+ if(approved.work_unit_id)args.push('--work-unit',approved.work_unit_id);
27
28
  args.push('--approved-slice',approved.ref,'--approved-slice-digest',approved.digest,'--approved-slice-approval',approved.approval_ref);
28
29
  }
29
30
  const verified = spawnSync(process.execPath, args, { cwd: root, encoding: 'utf8', timeout: 60000, maxBuffer: 2 * 1024 * 1024 });
@@ -8,6 +8,7 @@ const sameSet = (a,b) => Array.isArray(a) && Array.isArray(b) && a.length === ne
8
8
  export function assertApprovalUserDecision(record, roles, options = {}) {
9
9
  const policy = roles.user_decision_policy;
10
10
  const io = decisionIO(options);
11
+ if (record.continuation_ref) return assertUserDecisionRequirement({boundary:record.gate_id,subject_ref:record.subject_ref,scope:record.approval_scope,continuation_ref:record.continuation_ref}, {...options,rolesDoc:roles});
11
12
  if (policy.required_capabilities?.some(id => id !== DECISION_REUSE_CAPABILITY)) fail('接收工具不支持源用户决定策略,请升级');
12
13
  if (!record.decision_reuse_ref) return assertUserDecisionRequirement({boundary:record.gate_id,subject_ref:record.subject_ref,scope:record.approval_scope,user_decision_ref:record.user_decision_ref}, {...options,rolesDoc:roles});
13
14
  if (record.gate_id !== 'gate.strategic-design-handoff-approved' || !policy.required_capabilities?.includes(DECISION_REUSE_CAPABILITY)) fail('未登记的复用边界或能力');
@@ -1,3 +1,4 @@
1
+ import { normalizeSliceContract } from './slice-contract.mjs';
1
2
  import { createHash } from "node:crypto";
2
3
  import { readFileSync } from "node:fs";
3
4
  import path from "node:path";
@@ -5,6 +6,8 @@ import { parseDocument } from "../vendor/yaml.mjs";
5
6
  import { ROOT } from "./lifecycle-registry.mjs";
6
7
  import { loadDigitalHumanRoles } from "./digital-human-roles.mjs";
7
8
  import { validateJsonSchema } from "./json-schema.mjs";
9
+ import { assertDecisionContinuation } from './decision-continuation.mjs';
10
+ import { platformProfile } from './backend-platform.mjs';
8
11
 
9
12
  export function decisionError(code, detail) {
10
13
  const error = new TypeError(`${code}: ${detail}`);
@@ -161,6 +164,7 @@ export function verifyUserDecisionFile(ref, options = {}) {
161
164
 
162
165
  export function assertUserDecisionRequirement(requirement, options = {}) {
163
166
  if (!requirement) decisionError("user-decision-response-required", "缺少当前决定及其范围");
167
+ if (requirement.continuation_ref) return assertDecisionContinuation(requirement, options.rolesDoc || loadDigitalHumanRoles(), options);
164
168
  return verifyUserDecisionFile(requirement.user_decision_ref, { ...options, expected: [requirement] });
165
169
  }
166
170
 
@@ -191,7 +195,7 @@ export function assertImplementationDecision(state, options = {}) {
191
195
  if (state.slice_contract_ref !== slice.contract?.ref) decisionError("user-decision-subject-mismatch", "当前合同不在批准清单中");
192
196
  checkAsset(slice.contract, io);
193
197
  const content = io.document(slice.contract.ref);
194
- const contract = content.slice_contract || content;
198
+ const contract = content.slice_contract?.schema_version === 3 || content.schema_version === 3 ? normalizeSliceContract(content, { root: options.root || ROOT }) : content.slice_contract || content;
195
199
  if (contract.lifecycle_refs?.ticket !== ticketRef) decisionError("user-decision-subject-mismatch", "持久化合同的切片引用不匹配");
196
200
  for (const [manifestKey, contractKey] of [["repositories", "project_roots"], ["allowed_write_paths", "allowed_write_paths"]]) {
197
201
  if (!Array.isArray(slice[manifestKey]) || slice[manifestKey].length === 0 || JSON.stringify([...slice[manifestKey]].sort()) !== JSON.stringify([...(contract.common?.[contractKey] || [])].sort())) decisionError("user-decision-scope-mismatch", manifestKey);
@@ -202,11 +206,21 @@ export function assertImplementationDecision(state, options = {}) {
202
206
 
203
207
  export function scaffoldDecisionSnapshot(decision) {
204
208
  const { user_confirmation, status, decision_inputs_digest, ...inputs } = decision;
205
- return inputs;
209
+ const profile = platformProfile(decision.platform_profile, undefined, decision.platform_configuration?.spring_boot_version);
210
+ return {
211
+ ...inputs,
212
+ platform_selection: {
213
+ profile_id: profile.id,
214
+ spring_boot_version: profile.spring_boot_version,
215
+ java_version: profile.java_version,
216
+ },
217
+ };
206
218
  }
207
219
  export function assertScaffoldUserDecision(decision, options = {}) {
208
220
  const confirmation = decision.user_confirmation || {};
209
- const requirement = { boundary: "scaffold-choice", subject_ref: confirmation.decision_subject_ref, scope: [decision.project_id, decision.confirmed_architecture, decision.decision_inputs_digest], user_decision_ref: confirmation.user_decision_ref };
221
+ const profile = platformProfile(decision.platform_profile, undefined, decision.platform_configuration?.spring_boot_version);
222
+ const platformScope = `${profile.id}@${profile.spring_boot_version}/java${profile.java_version}`;
223
+ const requirement = { boundary: "gate.backend-architecture-platform-approved", subject_ref: confirmation.decision_subject_ref, scope: [decision.project_id, decision.confirmed_architecture, platformScope, decision.decision_inputs_digest], user_decision_ref: confirmation.user_decision_ref };
210
224
  assertUserDecisionRequirement(requirement, options);
211
225
  const io = decisionIO(options);
212
226
  if (decisionDigest(io.document(requirement.subject_ref)) !== decisionDigest(scaffoldDecisionSnapshot(decision))) decisionError("user-decision-stale", "脚手架输入与用户所见快照不一致");
@@ -6,9 +6,9 @@ import { preflightDelivery, invalidPreflightInput } from './lib/delivery-preflig
6
6
 
7
7
  let result;
8
8
  try {
9
- const {values}=parseArgs({options:{input:{type:'string'},stage:{type:'string'},json:{type:'boolean'}},strict:true});
9
+ const {values}=parseArgs({options:{input:{type:'string'},stage:{type:'string'},'work-unit':{type:'string'},json:{type:'boolean'}},strict:true});
10
10
  if(!values.input||!values.stage) throw new TypeError('必须提供 --input <file> 和 --stage prepare|build|export|accept');
11
- result=await preflightDelivery(read(path.resolve(values.input)),{stage:values.stage,root:process.cwd()});
11
+ result=await preflightDelivery(read(path.resolve(values.input)),{stage:values.stage,root:process.cwd(),work_unit_id:values['work-unit']});
12
12
  } catch(error) { result=invalidPreflightInput(error.message); }
13
13
  process.stdout.write(`${JSON.stringify(result,null,2)}\n`);
14
14
  process.exitCode=result.exit_code;
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { prepareSliceImplementationContract, migrateSliceContractV2, persistSliceDraft } from './lib/slice-contract-preparation.mjs';
5
+ import { renderSliceContractView, diffSliceContracts } from './lib/slice-contract-views.mjs';
6
+ import { parseSliceYaml, readSliceContract } from './lib/slice-contract.mjs';
7
+
8
+ try {
9
+ const args=process.argv.slice(2),mode=args.shift(),options={},positional=[];
10
+ for(let i=0;i<args.length;i++) {
11
+ if(args[i]==='--json'){options.json=true;continue;}
12
+ if(args[i].startsWith('--')) {
13
+ const key=args[i].slice(2);if(!['root','input','output','unit','before-root'].includes(key)||!args[i+1])throw new Error(`未知或缺值参数 ${args[i]}`);
14
+ options[key]=args[++i];
15
+ }else positional.push(args[i]);
16
+ }
17
+ const root=path.resolve(options.root||process.cwd());
18
+ let result;
19
+ if(mode==='prepare'||mode==='migrate') {
20
+ const input=options.input?parseSliceYaml(fs.readFileSync(path.resolve(root,options.input))):{};
21
+ if(mode==='prepare')result=prepareSliceImplementationContract({...input,root,ticket_ref:positional[0]});
22
+ else result=migrateSliceContractV2(readSliceContract(positional[0],{root}).raw,{...input,root});
23
+ if(options.output)persistSliceDraft(result,options.output,{root});
24
+ if(result.report.blockers.length)process.exitCode=1;
25
+ }else if(mode==='view')result=renderSliceContractView(positional[0],{root,unit_id:options.unit});
26
+ else if(mode==='diff')result=diffSliceContracts(positional[0],positional[1],{root,beforeRoot:options['before-root']?path.resolve(options['before-root']):root});
27
+ else if(mode==='verify')result={read_only:true,approval_validity:'not-checked',...readSliceContract(positional[0],{root}).binding};
28
+ else throw new Error('用法: scripts/slice-contract prepare <ticket> --input <补充.yaml> --output <新合同.yaml> | migrate <v2.yaml> --input <补充.yaml> --output <新合同.yaml> | view <合同.yaml> [--unit <id>] | diff <旧合同> <新合同> | verify <合同> [--root <项目根>]');
29
+ process.stdout.write(options.json||!result.markdown?`${JSON.stringify(result,null,2)}\n`:`${result.markdown}\n`);
30
+ }catch(error){process.stderr.write(`${error.message}\n`);process.exitCode=1;}