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
@@ -1,3 +1,6 @@
1
+ import { resolveBackendPlatform } from "./backend-platform.mjs";
2
+ import { safe } from './strategic-handoff-io.mjs';
3
+ import { selectSliceWorkUnit, normalizeSliceContract, withinSlicePath } from './slice-contract.mjs';
1
4
  import { createApprovedExecutionContext, createApprovedRecompilationContext, assertApprovedExecutionContext } from './approved-execution-context.mjs';
2
5
  import { enforceTechnicalDesign } from './technical-design-boundary.mjs';
3
6
  import { enforceHarnessSkillScope } from "./harness-execution-scope.mjs";
@@ -67,13 +70,15 @@ export function compileImplementationContract({
67
70
  architecture_identity,
68
71
  architecture_evidence,
69
72
  approved_slice,
73
+ work_unit_id,
70
74
  root = ROOT,
71
75
  slice_id,
72
76
  frontend_delivery,
73
- technical_design
77
+ technical_design,
78
+ readOnly = false
74
79
  }) {
75
80
  assertV2(registry, compilerContract);
76
- const recompilationExecution=approved_slice?createApprovedRecompilationContext(approved_slice,{root}):undefined;
81
+ const recompilationExecution=approved_slice?createApprovedRecompilationContext(approved_slice,{root,work_unit_id}):undefined;
77
82
  const deliveryInput = enforceFrontendDelivery({ slice_id, frontend_delivery }, { root });
78
83
  if (!Array.isArray(recipeIds) || !Array.isArray(requiredCapabilities) || !Array.isArray(conditions)) {
79
84
  fail("recipeIds、requiredCapabilities 与 conditions 必须是数组");
@@ -96,7 +101,8 @@ export function compileImplementationContract({
96
101
  for (const recipe of orderedRecipes) if (recipe.architecture_family && recipe.architecture_family !== architecture_identity.architecture_family) fail(`Recipe ${recipe.id} 与架构族不匹配`);
97
102
  }
98
103
 
99
- enforceTechnicalDesign({ technical_design, conditions, architecture_identity, slice_id }, { root, execution:recompilationExecution });
104
+ if (architecture_identity?.platform_configuration) resolveBackendPlatform(architecture_identity.platform_configuration);
105
+ enforceTechnicalDesign({ technical_design, conditions, architecture_identity, slice_id }, { root, execution:recompilationExecution, readOnly });
100
106
 
101
107
  const capabilitySources = new Map();
102
108
  const orderedCapabilities = [];
@@ -206,14 +212,17 @@ export function compileDefaultImplementationContract(input = {}) {
206
212
  });
207
213
  }
208
214
 
209
- export function evaluateContractFreshness(contract, { registry, compilerContract, root = ROOT, approved_slice, readOnly = false }, execution) {
215
+ export function evaluateContractFreshness(contract, { registry, compilerContract, root = ROOT, approved_slice, readOnly = false, work_unit_id }, execution) {
210
216
  assertV2(registry, compilerContract);
211
- if (contract?.schema_version !== 2) fail("Slice Implementation Contract schema v1 已停止支持;必须重新编译 v2 合同");
217
+ try { contract=normalizeSliceContract(contract,{root}); } catch(error) { return {freshness:'stale',reasons:[error.message]}; }
218
+ if (![2,3].includes(contract?.schema_version)) fail("Slice Implementation Contract schema v1 已停止支持;必须重新编译 v2 合同");
219
+ const all=contract;
220
+ try {contract=selectSliceWorkUnit(contract,work_unit_id);} catch(error){return {freshness:'stale',reasons:[error.message]};}
212
221
  const resolution = contract.resolution ?? contract;
213
222
  const reasons = [];
214
223
  let trustedExecution;
215
224
  try {
216
- trustedExecution=approved_slice?createApprovedExecutionContext(approved_slice,{root,contract}):execution;
225
+ trustedExecution=approved_slice?createApprovedExecutionContext(approved_slice,{root,contract:all,work_unit_id}):execution;
217
226
  if(trustedExecution)assertApprovedExecutionContext(trustedExecution,{root,contract});
218
227
  } catch(error) { reasons.push(error.code||'EXECUTION_APPROVAL_INVALID');trustedExecution=undefined; }
219
228
  try { enforceTechnicalDesign({ ...resolution, slice_id: contract.slice_id ?? resolution.slice_id }, { root,execution:trustedExecution,readOnly }); }
@@ -236,11 +245,13 @@ export function evaluateContractFreshness(contract, { registry, compilerContract
236
245
 
237
246
  export function validateExecutionResult(result, contract, current) {
238
247
  if (result?.schema_version !== 2) fail("YSS Skill Execution Result schema v1 已停止支持;请迁移到 v2");
239
- if (contract?.schema_version !== 2) fail("Slice Implementation Contract schema v1 已停止支持;必须重新编译 v2 合同");
248
+ contract=normalizeSliceContract(contract,{root:current?.root || ROOT});
249
+ if (![2,3].includes(contract?.schema_version)) fail("Slice Implementation Contract schema v1 已停止支持;必须重新编译 v2 合同");
240
250
  if (!EXECUTION_STATUSES.has(result.status)) fail(`未知 execution result status: ${result.status}`);
241
- if(contract.resolution?.architecture_identity?.schema_version===2&&!current?.approved_slice)return {status:'stale',blockers:['EXECUTION_APPROVAL_REQUIRED']};
242
- const freshness = evaluateContractFreshness(contract, current);
251
+ if((contract.schema_version===3||contract.resolution?.architecture_identity?.schema_version===2)&&!current?.approved_slice)return {status:'stale',blockers:['EXECUTION_APPROVAL_REQUIRED']};
252
+ const freshness = evaluateContractFreshness(contract, {...current,work_unit_id:result.work_unit_id});
243
253
  if (freshness.freshness === "stale") return { status: "stale", blockers: freshness.reasons };
254
+ contract=selectSliceWorkUnit(contract,result.work_unit_id);
244
255
  const consumed = result.consumed_contract ?? {};
245
256
  const resolution = contract.resolution ?? contract;
246
257
  const blockers = [];
@@ -253,6 +264,28 @@ export function validateExecutionResult(result, contract, current) {
253
264
  if (!item?.command || item.exit_code === undefined || !item.executed_at) blockers.push("verification-result-incomplete");
254
265
  else if (item.exit_code !== 0) blockers.push("verification-failed");
255
266
  }
267
+ if(contract.schema_version===3) {
268
+ const unit=contract.work_units.find(item=>item.id===result.work_unit_id);
269
+ if(!unit)blockers.push('work-unit-mismatch');
270
+ else {
271
+ const checks=unit.work_unit.verification;
272
+ for(const check of checks)if(!result.verification_results?.some(item=>item.command===check.command&&item.exit_code===0&&item.cwd===check.cwd&&(!check.dependency_roots||JSON.stringify(item.dependency_roots)===JSON.stringify(check.dependency_roots))))blockers.push('verification-coverage-or-cwd-missing');
273
+ if(!Array.isArray(result.changed_files))blockers.push('changed-files-missing');
274
+ else for(const item of result.changed_files) {
275
+ const changed=typeof item==='string'?item:item.path;
276
+ if(contract.repositories&&(typeof item==='string'||item.project_root!==unit.project_root))blockers.push('changed-file-repository-mismatch');
277
+ if(!unit.allowed_write_paths.some(parent=>withinSlicePath(changed,parent)))blockers.push('write-scope-violation');
278
+ }
279
+ const evidence=result.evidence_files||[];
280
+ for(const ref of unit.work_unit.expected_evidence) {
281
+ if(!evidence.some(item=>(typeof item==='string'?item:item.path)===ref&&(!contract.repositories||item.project_root===unit.project_root)))blockers.push('expected-evidence-missing');
282
+ else {try {readFileSync(safe(contract.repositories?unit.project_root:(current.root||ROOT),ref));}catch {blockers.push('expected-evidence-unreadable');}}
283
+ }
284
+ }
285
+ if(['drift','violation'].includes(result.status))blockers.push(result.status);
286
+ if(result.status==='not-applicable'&&!result.not_applicable_reason?.trim())blockers.push('not-applicable-reason-missing');
287
+ if(result.status==='seam-deferred'&&(!result.seam_deferred?.length||result.seam_deferred.some(item=>['risk','owner','follow_up_ticket','verification_plan','target_version_or_release_date'].some(key=>!item[key]))))blockers.push('seam-deferred-incomplete');
288
+ }
256
289
  if (Array.isArray(result.new_impacts) && result.new_impacts.length) blockers.push("new-impacts");
257
290
  return { status: blockers.length ? "blocked" : "accepted", blockers: [...new Set(blockers)] };
258
291
  }
@@ -46,7 +46,7 @@ export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRe
46
46
  const rule = countersignRuleForGate(rolesDoc.gate_policy, id);
47
47
  if (rule) {
48
48
  if (!refs.has(item.approval_ref) || !refs.has(item.subject_ref)) fail(`${id} 未绑定审查与资产`);
49
- const record = loadApprovalRecord(path.resolve(root, item.approval_ref));
49
+ const record = loadApprovalRecord(path.resolve(root, item.approval_ref), id);
50
50
  if (record.gate_id !== id || record.subject_ref !== item.subject_ref) fail(`${id} 审查对象不匹配`);
51
51
  if (!item.approval_scope?.length || JSON.stringify([...item.approval_scope].sort()) !== JSON.stringify([...(record.approval_scope || [])].sort())) fail(`${id} 审查范围不匹配`);
52
52
  const subjectDigest = createHash('sha256').update(readFileSync(path.resolve(root, item.subject_ref))).digest('hex');
@@ -65,7 +65,7 @@ export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRe
65
65
  const approvalRequired = countersignRuleForGate(rolesDoc.gate_policy, gateId);
66
66
  if (approvalRequired) {
67
67
  if (!refs.has(item.approval_ref) || !refs.has(item.subject_ref)) fail(`${gateId} 缺少已绑定批准记录和审阅包`);
68
- const record = loadApprovalRecord(path.resolve(root, item.approval_ref));
68
+ const record = loadApprovalRecord(path.resolve(root, item.approval_ref), gateId);
69
69
  if (!record.drafter_principal_ref || record.drafter_principal_ref === record.principal_ref) fail(`${gateId} 缺少独立审查身份或起草者自签`);
70
70
  const bytes = readFileSync(path.resolve(root, item.subject_ref));
71
71
  if (record.subject_ref !== item.subject_ref || record.subject_digest !== createHash('sha256').update(bytes).digest('hex')) fail(`${gateId} 批准依据过期`);
@@ -1,3 +1,5 @@
1
+ // Wire capability marker: profile-local readiness rules are not interchangeable.
2
+ export const SLICE_REPOSITORY_PREPARATION_PROTOCOL = 1;
1
3
  import { createHash } from "node:crypto";
2
4
  import { existsSync, readFileSync } from "node:fs";
3
5
  import { parseDocument } from "../vendor/yaml.mjs";
@@ -168,7 +170,7 @@ function backendDesignPrerequisitesReady(prerequisites, exists, root, projectId)
168
170
  const approvalFile = path.isAbsolute(prerequisites.engineering_contract_approval_ref)
169
171
  ? prerequisites.engineering_contract_approval_ref
170
172
  : path.resolve(root, prerequisites.engineering_contract_approval_ref);
171
- const approval = loadApprovalRecord(approvalFile);
173
+ const approval = loadApprovalRecord(approvalFile, 'gate.engineering-contract-approved');
172
174
  validateApprovalRecord(approval, { requireApproved: true, root });
173
175
  if (approval.gate_id !== "gate.engineering-contract-approved" || !approval.approval_scope?.includes(projectId)) return false;
174
176
  if (!approvalHasBinding(approval, technical.expected) || !approvalHasBinding(approval, data.expected)) return false;
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { verifyContextReconciliation } from './context-reconciliation.mjs';
3
3
  import { decisionIO, decisionDigest, assertUserDecisionRequirement } from './user-decision.mjs';
4
- import { validateApprovalRecord } from './approval-record.mjs';
4
+ import { validateApprovalRecord, selectApprovalRecord } from './approval-record.mjs';
5
5
 
6
6
  const fail = message => { throw new TypeError(`plan-spec-entry-blocked: ${message}`); };
7
7
  const text = value => typeof value === 'string' && value.trim().length > 0;
@@ -56,7 +56,7 @@ export function assertPlanSpecEntry(state, options = {}) {
56
56
  evidence(gate?.evidence_refs);
57
57
  if (review.impacts[impact]) {
58
58
  if (gate.status !== 'approved' || !basis.has(gate.approval_ref) || !basis.has(gate.subject_ref)) fail(`命中门禁未批准或未绑定依据: ${gateId}`);
59
- const record = io.document(gate.approval_ref);
59
+ const record = selectApprovalRecord(io.document(gate.approval_ref), gateId);
60
60
  if (record.gate_id !== gateId || record.subject_ref !== gate.subject_ref || !gate.approval_scope?.includes(state.feature_id) || JSON.stringify([...(gate.approval_scope || [])].sort()) !== JSON.stringify([...(record.approval_scope || [])].sort())) fail(`会签资产或范围不匹配: ${gateId}`);
61
61
  validateApprovalRecord(record, { ...options, requireApproved: true });
62
62
  } else if (gate.status !== 'not-applicable' || !text(gate.reason)) fail(`未命中门禁须有原因和依据: ${gateId}`);
@@ -72,7 +72,7 @@ export function assertPlanSpecEntry(state, options = {}) {
72
72
  if (reconciliation.status !== 'reconciled' || reconciliation.repository_mode !== 'project-instance') fail('Context 未调和');
73
73
  try { verifyContextReconciliation(path.resolve(io.root, review.context_reconciliation_ref), { root: io.root }); }
74
74
  catch (error) { fail(`Context reconciliation 验证失败: ${error.message}\n`); }
75
- assertUserDecisionRequirement({ boundary: 'gate.plan-approved', subject_ref: state.plan_review_ref, scope: [state.feature_id], user_decision_ref: state.plan_user_decision_ref }, options);
75
+ assertUserDecisionRequirement({ boundary: 'gate.plan-approved', subject_ref: state.plan_review_ref, scope: [state.feature_id], user_decision_ref: state.plan_user_decision_ref, continuation_ref: state.plan_continuation_ref }, options);
76
76
  return { result: 'allowed', blocking_signals: [], missing_requirements: [], evidence_refs: [state.plan_review_ref, ...basis.keys()], next_work_unit: null };
77
77
  }
78
78
 
@@ -14,6 +14,7 @@ export function localDatabaseConfiguration(name) {
14
14
 
15
15
  export function scaffoldArchitectureIdentity(contract, contractDigest) {
16
16
  return {
17
+ ...(contract.platform_configuration ? { platform_configuration: contract.platform_configuration } : {}),
17
18
  architecture_family: contract.architecture_family,
18
19
  architecture_profile: contract.architecture_profile,
19
20
  generator_skill: contract.generator_skill,
@@ -0,0 +1,10 @@
1
+ // Interpret the published lifecycle check, without creating a second gate registry.
2
+ export function sliceCheckApplicability(scope,registry) {
3
+ if(!['low','medium','high'].includes(scope.risk_level))throw new TypeError('缺少明确风险等级,不能裁剪材料');
4
+ if(scope.impacted_areas.some(impact=>!['ui','frontend','backend','api','data','persistence','domain','architecture','cross-repo','cross-boundary','high-risk'].includes(impact)))throw new TypeError('未知影响不能裁剪材料,先补影响分析');
5
+ const check=registry.checks?.find(check=>check.id==='check.architecture-reviewed');
6
+ // Unknown source rule revisions need an adapter update, never a local default.
7
+ if(check?.trigger!=='高风险或跨边界变化。')throw new TypeError('不支持当前生命周期架构审查规则');
8
+ const required=scope.risk_level==='high'||scope.impacted_areas.includes('high-risk')||scope.impacted_areas.some(impact=>['architecture','cross-repo','cross-boundary'].includes(impact))||scope.project_roots.length>1;
9
+ return {[check.id]:{status:required?'required':'not-applicable',reason:`${check.trigger} 本切片风险 ${scope.risk_level},影响 ${scope.impacted_areas.join(', ')||'无'},工程数 ${scope.project_roots.length}。`}};
10
+ }
@@ -0,0 +1,257 @@
1
+ import {sliceRepositories} from './slice-repositories.mjs';
2
+ import { sliceCheckApplicability } from './slice-applicability.mjs';
3
+ import path from 'node:path';
4
+ import fs from 'node:fs';
5
+ import { stringify } from '../vendor/yaml.mjs';
6
+ import { safe, hash, digest, write } from './strategic-handoff-io.mjs';
7
+ import { compileDefaultImplementationContract, loadCompilerContract } from './implementation-contract-compiler.mjs';
8
+ import { normalizeSliceContract, parseSliceYaml, readSliceSources, resolveSliceBasis, sourceSliceContract, sliceArchitectureEvidence } from './slice-contract.mjs';
9
+
10
+ const object=value=>value && typeof value==='object' && !Array.isArray(value);
11
+ const same=(a,b)=>digest(a)===digest(b);
12
+ function metadata(text) {
13
+ const front=/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(text);
14
+ if(front)return parseSliceYaml(front[1]);
15
+ return (/^\s*[{[]/.test(text)||/^[A-Za-z_][\w-]*:\s/m.test(text)&&!/^#/m.test(text))?parseSliceYaml(text):{};
16
+ }
17
+ function mergeFacts(left,right,path,report) {
18
+ if(left===undefined)return structuredClone(right);
19
+ if(right===undefined)return structuredClone(left);
20
+ if(object(left)&&object(right))return Object.fromEntries([...new Set([...Object.keys(left),...Object.keys(right)])].map(key=>[key,mergeFacts(left[key],right[key],`${path}.${key}`,report)]));
21
+ if(!same(left,right))report.blockers.push({field:path,reason:'conflict',before:left,after:right,recovery:'回到来源确认当前事实,不使用最后覆盖'});
22
+ return structuredClone(left);
23
+ }
24
+ function markdownAcceptance(text) {
25
+ const rows=text.split('\n'),result={};let active=false;
26
+ rows.forEach((line,index)=>{
27
+ if(/^##\s/.test(line))active=/验收/.test(line);
28
+ if(active&&/^\s*-\s+(?:\[[ xX]\]\s*)?\S/.test(line)) {
29
+ const id=/(?:AC|SC|验收)[-_][\w-]+/.exec(line)?.[0] || `acceptance-${Object.keys(result).length+1}`;
30
+ if(result[id])throw new TypeError(`验收 ID 重复: ${id}`);
31
+ result[id]={source:'ticket',locator:`lines:${index+1}-${index+1}`};
32
+ }
33
+ });return result;
34
+ }
35
+ function lifecycleSources(checkpoint,report) {
36
+ const result={};
37
+ for(const [artifact,key]of Object.entries({'artifact.spec':'spec','artifact.engineering-baseline':'engineering_baseline','artifact.architecture-review':'architecture_review','artifact.technical-design':'technical_design','artifact.data-architecture':'data_architecture','artifact.state-matrix':'state_matrix','artifact.prototype-deliverable':'prototype_deliverable','artifact.prototype-review':'prototype_review','artifact.prototype-confirmation':'prototype_confirmation','artifact.openapi-freeze-record':'openapi_freeze'})) {
38
+ const value=checkpoint.artifacts?.[artifact];if(value===undefined)continue;
39
+ if(typeof value==='string')result[key]={ref:value};
40
+ else if(object(value)&&typeof value.ref==='string')result[key]=Object.fromEntries(['ref','version','digest','approval_ref'].filter(k=>value[k]!==undefined).map(k=>[k,value[k]]));
41
+ else report.blockers.push({field:`artifacts.${artifact}`,reason:'上游引用不明确,需选择当前绑定'});
42
+ }
43
+ return result;
44
+ }
45
+ /** sources select existing assets; refinements contain ONLY new slice facts, never an approved contract. */
46
+ export function prepareSliceImplementationContract({root=process.cwd(),ticket_ref,checkpoint_ref,sources={},refinements={},approved_slice}={}) {
47
+ const started=performance.now();
48
+ const report={read_only:true,blockers:[],sources:{},provenance:[],reason_chains:{},checks:[]};
49
+ const snapshots=new Map();
50
+ const read=ref=>{if(!snapshots.has(ref))snapshots.set(ref,fs.readFileSync(safe(root,ref)));return snapshots.get(ref);};
51
+ let contract={schema_version:3,status:'blocked'};
52
+ try {
53
+ let ticketText='',ticket={},saved={};
54
+ try {ticketText=read(ticket_ref).toString('utf8');ticket=metadata(ticketText);}catch(error){report.blockers.push({code:'SLICE_SOURCE_UNREADABLE',field:'basis.ticket',source_ref:ticket_ref,reason:error.message});}
55
+ if(checkpoint_ref)try {saved=parseSliceYaml(read(checkpoint_ref));}catch(error){report.blockers.push({code:'SLICE_SOURCE_UNREADABLE',field:'checkpoint',source_ref:checkpoint_ref,reason:error.message});}
56
+ const fromTicket=ticket.slice_implementation || {};
57
+ const facts=mergeFacts(saved.slice_implementation || {},fromTicket,'slice',report);
58
+ const input=mergeFacts(facts,refinements,'slice',report);
59
+ for(const field of ['status','resolution','schema_version','readiness'])if(Object.hasOwn(input,field))report.blockers.push({field,reason:'由编译器生成,不接受调用方指定'});
60
+ const inputKeys=['contract_id','contract_version','slice_id','sources','scope','applicability','recipe_ids','required_capabilities','conditions','acceptance','verification','work_units','extensions'];
61
+ for(const field of Object.keys(input))if(!inputKeys.includes(field))report.blockers.push({field,reason:'未知输入字段,禁止静默丢弃'});
62
+ contract={schema_version:3,contract_id:input.contract_id,contract_version:input.contract_version,slice_id:input.slice_id,status:'blocked'};
63
+ for(const field of ['contract_id','contract_version','slice_id','scope','applicability','verification','work_units'])if(input[field]===undefined)report.blockers.push({code:'SLICE_INPUT_MISSING',field:`slice.${field}`,reason:'缺少切片必要输入',recovery:'优先从 Ticket / checkpoint 整理;只补缺失的切片细化'});
64
+ for(const field of ['impacted_areas','allowed_write_paths'])if(input.scope?.[field]===undefined)report.blockers.push({code:'SLICE_INPUT_MISSING',field:`scope.${field}`,reason:'影响与授权范围未确定',responsibility:field==='allowed_write_paths'?'user-decision':'professional-review',recovery:'先确认影响与既有授权范围;不能从目录猜测'});
65
+
66
+ const selected=mergeFacts(lifecycleSources(saved,report),mergeFacts(input.sources || {},sources,'sources',report),'sources',report);
67
+ if(selected.ticket && (typeof selected.ticket==='string'?selected.ticket:selected.ticket.ref)!==ticket_ref)throw new TypeError('Ticket 来源冲突');
68
+ selected.ticket=selected.ticket || {ref:ticket_ref};
69
+ if(input.scope?.risk_level){selected.lifecycle_registry??={ref:'docs/process/lifecycle-registry.yaml'};selected.process_tailoring??={ref:'docs/process/harness-process-tailoring.md'};}
70
+ if(!selected.context&&fs.existsSync(safe(root,'CONTEXT.md',{missing:true})))selected.context={ref:'CONTEXT.md'};
71
+ const basis={},seen=new Map();
72
+ for(const [key,value] of Object.entries(selected)) {
73
+ try {
74
+ if(typeof value==='string' && Object.hasOwn(selected,value)) {basis[key]=value;continue;}
75
+ const binding=typeof value==='string'?{ref:value}:value;
76
+ const bytes=read(binding.ref),rawDigest=hash(bytes);
77
+ if(binding.digest&&binding.digest!==rawDigest)throw new TypeError(`stale: 来源 ${key}`);
78
+ const data=metadata(bytes.toString('utf8'));
79
+ const sourceVersion=data.requirement_version??data.version??data.contract_version;
80
+ if(binding.version!==undefined&&sourceVersion!==undefined&&String(binding.version)!==String(sourceVersion))throw new TypeError(`来源版本冲突: ${key}`);
81
+ const version=binding.version||data.requirement_version||data.version||data.contract_version;
82
+ basis[key]={ref:binding.ref,digest:rawDigest,...(version?{version:String(version)}:{}),...(binding.approval_ref?{approval_ref:binding.approval_ref}:{})};
83
+ if(seen.has(binding.ref)) {
84
+ const previous=seen.get(binding.ref);
85
+ if(!same(basis[key],basis[previous]))throw new TypeError(`来源绑定冲突: ${key}/${previous}`);
86
+ basis[key]=previous;
87
+ }else seen.set(binding.ref,key);
88
+ report.provenance.push({target:`basis.${key}`,source_ref:binding.ref,digest:rawDigest,rule:'original-bytes'});
89
+ }catch(error){report.blockers.push({code:(error.code==='ENOENT'||/文件不可读/.test(error.message))?'SLICE_SOURCE_UNREADABLE':/冲突/.test(error.message)?'SLICE_SOURCE_CONFLICT':'SLICE_SOURCE_INVALID',field:`basis.${key}`,source_ref:typeof value==='string'?value:value?.ref,reason:error.message,responsibility:'agent',recovery:'补齐当前来源或纠正绑定后重新准备'});}
90
+ }
91
+ const extraRequired=[...(input.applicability?.backend?.status==='required'?['technical_design','repository_registration','manifest','backend_repository','maven_wrapper']:[]),...(input.applicability?.frontend?.status==='required'?(input.applicability.frontend.baseline_kind==='existing-ui-baseline'?['existing_ui_baseline','frontend_delivery']:['requirement_freeze','low_fidelity_review','prototype_review','prototype_profile_decision','prototype_deliverable','prototype_deliverable_verification','prototype_confirmation','visual_baseline','state_matrix']):[]),...(input.applicability?.api?[input.applicability.api.status==='required'?'openapi_freeze':'no_api_impact_record']:[])];
92
+ for(const key of ['spec','ticket','engineering_baseline','implementation_repository','build_architecture_checklist',...extraRequired,...(!input.scope?.risk_level?['architecture_review']:[])])if(!selected[key])report.blockers.push({code:'SLICE_SOURCE_MISSING',field:`basis.${key}`,reason:'缺少必要来源',responsibility:'agent',recovery:'绑定已有当前资产;不能用空文档替代'});
93
+ contract.basis=basis;
94
+ if(report.blockers.length){report.checks.push({check:'dependent-compilation',result:'not-executed',reason:'来源或输入存在独立阻断'});throw Object.assign(new Error('依赖未就绪'),{code:'SLICE_DEPENDENCIES_UNAVAILABLE'});}
95
+ const sourceDoc=key=>basis[key]?metadata(read(resolveSliceBasis({basis},key).ref).toString('utf8')):{};
96
+ const registration=sourceDoc('implementation_repository'),baseline=sourceDoc('engineering_baseline');
97
+ const registeredRoot=registration.local_worktree?(registration.project_root&&registration.project_root!=='.'?path.resolve(registration.local_worktree,registration.project_root):registration.local_worktree):undefined;
98
+ const scope={...(registeredRoot?{project_roots:[registeredRoot]}:{}),...input.scope};
99
+ // Registration is an upper bound. Never use its allowed_write_paths as slice authorization.
100
+ if(!input.extensions?.cross_repo?.repository_bindings&&registeredRoot&&scope.project_roots?.some(p=>p!==registeredRoot))throw new TypeError('实施仓库与登记冲突');
101
+ if(!input.extensions?.cross_repo?.repository_bindings&&registration.allowed_write_paths && scope.allowed_write_paths) {
102
+ const {withinSlicePath}=helpers;
103
+ if(scope.allowed_write_paths.some(p=>!registration.allowed_write_paths.some(parent=>withinSlicePath(p,parent))))throw new TypeError('Slice 写范围超出登记');
104
+ }
105
+ const applicability=structuredClone(input.applicability);
106
+ if(scope.risk_level){const calculated=sliceCheckApplicability(scope,sourceDoc('lifecycle_registry'));if(applicability.checks&&!same(applicability.checks,calculated))throw new TypeError('材料适用性与生命周期规则冲突');applicability.checks=calculated;}
107
+ const architecture_identity=baseline.architecture_identity || registration.architecture_identity;
108
+ if(baseline.architecture_identity&&registration.architecture_identity&&!same(baseline.architecture_identity,registration.architecture_identity))throw new TypeError('工程基线与登记架构冲突');
109
+ const bound=key=>basis[key]?resolveSliceBasis({basis},key):undefined;
110
+ const architecture_evidence=architecture_identity?sliceArchitectureEvidence({basis,resolution:{architecture_identity}},readSliceSources({basis},{root})):undefined;
111
+ const compilerRules=loadCompilerContract();
112
+ scope.full_reroute_triggers=[...new Set([...(compilerRules.full_reroute_triggers||[]),...(scope.full_reroute_triggers||[])])];
113
+ for(const impact of input.extensions?.backend?.component_impacts||[])if(!compilerRules.impact_to_capabilities[impact])throw new TypeError(`未知组件影响: ${impact}`);
114
+ const componentCapabilities=(input.extensions?.backend?.component_impacts||[]).flatMap(impact=>compilerRules.impact_to_capabilities[impact]||[]);
115
+ const compileBase={root,slice_id:input.slice_id,conditions:input.conditions||[]};
116
+ let compiled;
117
+ if(input.extensions?.cross_repo?.repository_bindings) {
118
+ const repositories=sliceRepositories({basis,scope,extensions:input.extensions,work_units:input.work_units,resolution:{}},readSliceSources({basis},{root}),{root});
119
+ const results=Object.entries(repositories).map(([projectRoot,repo])=>{
120
+ const recipeIds=repo.recipe_refs||(input.recipe_ids||[]).filter(id=>!id.startsWith('backend.')&&!id.startsWith('frontend.')||id.startsWith(`${repo.project.delivery_role}.`));
121
+ const requiredCapabilities=repo.capability_refs||input.required_capabilities||[];
122
+ if(recipeIds.some(id=>!(input.recipe_ids||[]).includes(id))||requiredCapabilities.some(id=>!(input.required_capabilities||[]).includes(id)))throw new TypeError('逐仓编译引用不属于切片新增输入');
123
+ return compileDefaultImplementationContract({...compileBase,recipeIds,requiredCapabilities:[...requiredCapabilities,...(repo.project.delivery_role==='backend'?componentCapabilities:[])],architecture_identity:repo.resolution.architecture_identity,architecture_evidence:repo.resolution.architecture_evidence,technical_design:repo.resolution.technical_design,...(repo.resolution.frontend_delivery?{frontend_delivery:repo.resolution.frontend_delivery}:{}),...(approved_slice?{approved_slice,work_unit_id:input.work_units.find(u=>u.project_root===projectRoot)?.id}:{})});
124
+ });
125
+ if(results.some(r=>r.registry_digest!==results[0].registry_digest||r.compiler_contract_digest!==results[0].compiler_contract_digest))throw new TypeError('逐仓编译依据冲突:准备期间来源发生变化');
126
+ compiled={...results[0],required_capabilities:[...new Set(results.flatMap(r=>r.required_capabilities))],required_skills:[...new Set(results.flatMap(r=>r.required_skills))],recipe_ids:[...new Set(results.flatMap(r=>r.recipe_ids))],readiness_blockers:results.flatMap(r=>r.readiness_blockers||[]),reason_chains:Object.fromEntries(Object.keys(repositories).map((p,i)=>[p,results[i].reason_chains]))};
127
+ delete compiled.architecture_identity;
128
+ } else compiled=compileDefaultImplementationContract({...compileBase,recipeIds:input.recipe_ids||[],requiredCapabilities:[...new Set([...(input.required_capabilities||[]),...componentCapabilities])],architecture_identity,architecture_evidence,technical_design:bound('technical_design'),...(bound('frontend_delivery')?{frontend_delivery:{acceptance_ref:bound('frontend_delivery').ref,digest:bound('frontend_delivery').digest}}:{}),...(approved_slice?{approved_slice}:{})});
129
+ if(compiled.compiler_contract_digest!==digest(compilerRules).slice(7))throw new TypeError('编译规则来源冲突:准备期间发生变化');
130
+ const resolution=Object.fromEntries(['required_capabilities','required_skills','recipe_ids','conditions','registry_digest','compiler_contract_digest','architecture_identity'].filter(key=>compiled[key]!==undefined).map(key=>[key,compiled[key]]));
131
+ contract={schema_version:3,ticket_policy:{mode:'frozen-requirements',state_owner:'tracker-or-task-package'},contract_id:input.contract_id,contract_version:input.contract_version,slice_id:input.slice_id,status:'draft',basis,scope,applicability,resolution,acceptance:input.acceptance||markdownAcceptance(ticketText),verification:input.verification,work_units:input.work_units,...(input.extensions?{extensions:input.extensions}:{})};
132
+ report.reason_chains=compiled.reason_chains;
133
+ for(const reason of compiled.readiness_blockers||[])report.blockers.push({reason});
134
+ normalizeSliceContract(contract,{root});
135
+ report.checks.push({check:'structure-sources-scope-acceptance',result:'pass'});
136
+ report.provenance.push({target:'resolution',source_ref:'docs/agents/yss-skill-registry.yaml',digest:compiled.registry_digest,rule:'existing-capability-compiler'});
137
+ for(const field of ['scope','acceptance','verification','work_units','applicability','extensions'])if(contract[field]) {
138
+ const origins=[];
139
+ if(saved.slice_implementation?.[field]!==undefined)origins.push({kind:'checkpoint',ref:checkpoint_ref});
140
+ if(fromTicket[field]!==undefined)origins.push({kind:'ticket-metadata',ref:ticket_ref});
141
+ if(refinements[field]!==undefined)origins.push({kind:'agent-refinement'});
142
+ if(field==='scope'&&registeredRoot&&!input.scope?.project_roots)origins.push({kind:'repository-registration',ref:resolveSliceBasis({basis},'implementation_repository').ref});
143
+ if(field==='scope'&&input.extensions?.cross_repo?.repository_bindings)for(const keys of Object.values(input.extensions.cross_repo.repository_bindings))origins.push({kind:'repository-registration',ref:resolveSliceBasis({basis},keys.implementation_repository).ref});
144
+ if(field==='acceptance'&&!input.acceptance)origins.push({kind:'ticket-acceptance',ref:ticket_ref});
145
+ if(field==='applicability'&&scope.risk_level)origins.push({kind:'lifecycle-rule',ref:resolveSliceBasis({basis},'lifecycle_registry').ref});
146
+ report.provenance.push({target:field,origins,requires_professional_review:true});
147
+ }
148
+ }catch(error){if(error.code!=='SLICE_DEPENDENCIES_UNAVAILABLE')report.blockers.push({reason:error.message,recovery:'补齐已确认输入后重新准备;草案不授予执行权限'});report.checks.push({check:'assembly',result:'not-executed',reason:'前置检查未通过'});}
149
+ for(const [ref,bytes] of snapshots) {
150
+ try {if(hash(fs.readFileSync(safe(root,ref)))!==hash(bytes))report.blockers.push({field:ref,reason:'生成期间来源变化'});}catch(error){report.blockers.push({field:ref,reason:error.message});}
151
+ report.sources[ref]=hash(bytes);
152
+ }
153
+ report.blockers=report.blockers.map(b=>({code:b.code||(/conflict|冲突/.test(b.reason)?'SLICE_INPUT_CONFLICT':'SLICE_INPUT_INVALID'),field:b.field||'slice',source_ref:b.source_ref||null,responsibility:b.responsibility||(/user.decision|用户决定|实施授权/.test(b.reason)?'user-decision':/conflict|冲突|技术设计|架构/.test(b.reason)?'professional-review':'agent'),recovery:b.recovery||'核对所列来源并补齐细化后重新准备',...b}));
154
+ report.blockers=report.blockers.filter((b,i,all)=>all.findIndex(x=>x.code===b.code&&x.field===b.field&&x.source_ref===b.source_ref)===i);
155
+ contract.status=report.blockers.length?'blocked':'ready-for-lifecycle-review';
156
+ report.metrics={elapsed_ms:Math.round(performance.now()-started),preparation_round:null,additional_human_confirmations:null,reapproval_reasons:[],measurement:'observed-preparation-only; interaction counts not recorded',unique_source_files:snapshots.size,refinement_fields:Object.keys(refinements).length,contract_bytes:Buffer.byteLength(stringify({slice_contract:contract}))};
157
+ return {slice_contract:contract,report};
158
+ }
159
+ import * as helpers from './slice-contract.mjs';
160
+
161
+ export function persistSliceDraft(result,ref,{root=process.cwd()}={}) {
162
+ if(!['draft','blocked','ready-for-lifecycle-review'].includes(result.slice_contract?.status))throw new TypeError('只能保存编译器草案');
163
+ for(const [source,expected]of Object.entries(result.report?.sources||{}))if(hash(fs.readFileSync(safe(root,source)))!==expected)throw new TypeError(`stale: 保存前来源变化 ${source}`);
164
+ if(result.slice_contract.status!=='blocked')normalizeSliceContract(result.slice_contract,{root});
165
+ const bytes=stringify({slice_contract:result.slice_contract});
166
+ const reportRef=`${ref}.preparation.json`;
167
+ if(fs.existsSync(safe(root,reportRef,{missing:true})))throw Object.assign(new TypeError('EEXIST: 准备报告目标已存在'),{code:'EEXIST'});
168
+ write(root,ref,bytes); // wx: never overwrite a draft or approval.
169
+ write(root,reportRef,JSON.stringify({binding:{ref,digest:hash(bytes)},...result.report},null,2)+'\n');
170
+ return ref;
171
+ }
172
+
173
+ /** Explicit, non-destructive migration; no new authorization is inferred. */
174
+ export function migrateSliceContractV2(document,{root=process.cwd(),ticket_ref,sources={},refinements={},...rest}={}) {
175
+ const old=sourceSliceContract(document);
176
+ if(old?.schema_version!==2)throw new TypeError('显式迁移只接受 Slice v2');
177
+ const conflicts=[];
178
+ const meaningful=value=>value!==undefined&&value!==null&&value!==''&&(!Array.isArray(value)||value.length>0);
179
+ const compare=(a,b,label)=>{if(meaningful(a)&&meaningful(b)&&!same(a,b))conflicts.push({field:label,reason:'conflict',before:a,after:b});};
180
+ for(const key of ['required_skills','required_capabilities'])compare(old.common?.[key],old.resolution?.[key],key);
181
+ compare(old.frontend?.delivery,old.resolution?.frontend_delivery,'frontend_delivery');
182
+ const constraintKeys=['application_boundary','transaction_boundary','persistence_strategy','aggregate_refs','invariant_refs','state_behavior_refs','gateway_boundary_ref','domain_test_seams','application_test_seams'];
183
+ for(const key of constraintKeys)compare(old.backend?.[key],old.backend?.tactical_ddd?.[key],`backend.${key}`);
184
+ if(refinements.contract_version===undefined||refinements.contract_version===String(old.contract_version))conflicts.push({field:'contract_version',reason:'迁移必须指定新版本'});
185
+ if(old.readiness?.blockers?.length||old.readiness?.stale_inputs?.length)conflicts.push({field:'readiness',reason:'旧合同仍有阻断或过期输入'});
186
+ const sourceMap=Object.fromEntries(Object.entries(old.lifecycle_refs||{}).filter(([,v])=>typeof v==='string'&&v).map(([k,v])=>[k,{ref:v}]));
187
+ for(const [key,binding]of Object.entries({...old.resolution?.architecture_evidence,...(old.resolution?.technical_design?{technical_design:old.resolution.technical_design}:{})})) {
188
+ if(!binding?.ref)continue;
189
+ if(sourceMap[key]&&sourceMap[key].ref!==binding.ref)conflicts.push({field:`basis.${key}`,reason:'阅读引用与冻结绑定冲突'});
190
+ sourceMap[key]=binding;
191
+ }
192
+ if(sourceMap.openapi_freeze_or_no_impact){sourceMap[old.contract?.api_impact?'openapi_freeze':'no_api_impact_record']=sourceMap.openapi_freeze_or_no_impact;delete sourceMap.openapi_freeze_or_no_impact;}
193
+ const frontendBinding=old.frontend?.delivery||old.resolution?.frontend_delivery;
194
+ if(frontendBinding)sourceMap.frontend_delivery={ref:frontendBinding.acceptance_ref,digest:frontendBinding.digest};
195
+ if(sourceMap.tactical_design&&!sourceMap.technical_design)sourceMap.technical_design=sourceMap.tactical_design;
196
+ const applicability=Object.fromEntries(['frontend','backend','api','cross_repo'].map(key=>{
197
+ const required=key==='api'?old.contract?.api_impact:key==='cross_repo'?old.cross_repo?.repositories?.length>1:old[key]?.status==='required';
198
+ const reason=old.readiness?.not_applicable?.find(x=>x.item===key)?.reason;
199
+ return [key,required?{status:'required'}:{status:'not-applicable',reason:reason||refinements.applicability?.[key]?.reason}];
200
+ }));
201
+ const scopeKeys=['impacted_areas','implementation_path_policy','project_roots','allowed_write_paths','forbidden_patterns','context_plan','doubt_driven_review','human_review_points','full_reroute_triggers','optional_skills','unavailable_skills'];
202
+ const scope=Object.fromEntries(scopeKeys.filter(k=>old.common?.[k]!==undefined).map(k=>[k,old.common[k]]));
203
+ const checkUnknown=(value,known,prefix)=>{for(const [key,item]of Object.entries(value||{}))if(meaningful(item)&&!known.includes(key))conflicts.push({field:`${prefix}.${key}`,reason:'未映射约束,禁止静默丢弃'});};
204
+ checkUnknown(old,['schema_version','contract_id','contract_version','slice_id','status','suggested_owner_role_id','lifecycle_refs','readiness','resolution','common','frontend','backend','contract','cross_repo','work_units'],'root');
205
+ checkUnknown(old.common,[...scopeKeys,'required_capabilities','required_skills','verification_commands','expected_evidence_files','quality_baseline_ref'],'common');
206
+ checkUnknown(old.resolution,['schema_version','status','slice_id','architecture_identity','architecture_identity_digest','architecture_evidence','technical_design','frontend_delivery','profile_maturity','readiness_blockers','skill_profiles','recipe_ids','conditions','required_capabilities','required_skills','reason_chains','non_expanding_dependencies','excluded_conditional_dependencies','registry_digest','compiler_contract_digest','compiled_at','freshness'],'resolution');
207
+ const ticketRef=ticket_ref||old.lifecycle_refs?.ticket;
208
+ let acceptance=refinements.acceptance;
209
+ if(!acceptance){try{acceptance=markdownAcceptance(fs.readFileSync(safe(root,ticketRef),'utf8'));}catch(error){conflicts.push({field:'acceptance',reason:error.message});acceptance={};}}
210
+ const verification={},work_units=[],extensions={};
211
+ for(const entry of old.work_units||[]) {
212
+ const unit=entry.work_unit||entry;
213
+ for(const key of ['allowed_write_paths','verification_commands','expected_evidence'])compare(entry[key],unit[key],`work_units.${entry.id}.${key}`);
214
+ const projectRoot=unit.project_root||entry.project_root||(scope.project_roots?.length===1?scope.project_roots[0]:undefined);
215
+ const acceptanceRefs=unit.acceptance_refs||(Object.keys(acceptance).length===1?Object.keys(acceptance):[]);
216
+ const seams=[...(old.frontend?.component_test_seams||[]),...(old.frontend?.e2e_paths||[]),...(old.backend?.domain_test_seams||old.backend?.tactical_ddd?.domain_test_seams||[]),...(old.backend?.application_test_seams||old.backend?.tactical_ddd?.application_test_seams||[])];
217
+ const evidence=[...new Set([...(old.common?.expected_evidence_files||[]),...(unit.expected_evidence||[])])];
218
+ const refs=[];
219
+ for(const command of new Set([...(old.common?.verification_commands||[]),...(unit.verification_commands||[])])) {
220
+ const check={command,cwd:projectRoot,expected_evidence:evidence,test_seams:seams,acceptance_refs:acceptanceRefs};
221
+ const existing=Object.entries(verification).find(([,v])=>same(v,check));
222
+ const id=existing?.[0]||`verify-${Object.keys(verification).length+1}`;verification[id]=check;refs.push(id);
223
+ }
224
+ const allowed=unit.allowed_write_paths||entry.allowed_write_paths;
225
+ const next={id:entry.id||unit.id,role_id:entry.role_id||unit.role_id,behavior:unit.behavior,primary_skill:unit.primary_skill,tdd_mode:unit.tdd_mode,verification_refs:refs,acceptance_refs:acceptanceRefs};
226
+ for(const key of ['supporting_skills','controlled_generation','downstream_consumers','convergence_ref','forbidden_patterns'])if(meaningful(unit[key]||entry[key]))next[key]=unit[key]||entry[key];
227
+ if(allowed&&!same(allowed,scope.allowed_write_paths))next.allowed_write_paths=allowed;
228
+ if(scope.project_roots?.length>1)next.project_root=projectRoot;
229
+ work_units.push(next);
230
+ checkUnknown(unit,['id','behavior','role_id','runtime_id','execution_state','workflow_status','task_package_ref','contract_id','contract_version','architecture_identity','project_root','primary_skill','supporting_skills','tdd_mode','allowed_write_paths','expected_evidence','verification_commands','controlled_generation','acceptance_refs','downstream_consumers','convergence_ref','forbidden_patterns'],'work_unit');
231
+ }
232
+ const subset=(value,keys)=>Object.fromEntries(keys.filter(k=>meaningful(value?.[k])).map(k=>[k,value[k]]));
233
+ if(applicability.frontend.status==='required')extensions.frontend=subset(old.frontend,['visual_baseline_case_ids','component_test_seams','e2e_paths','generated_api_client_ref','implementation_verification_ref']);
234
+ if(applicability.backend.status==='required') {
235
+ const constraints={...subset(old.backend,constraintKeys),...subset(old.backend?.tactical_ddd,constraintKeys)};
236
+ extensions.backend={...subset(old.backend,['affected_layers','component_impacts','seam_deferred']),design_refs:['pointer:/design'],...(Object.keys(constraints).length?{constraints}:{})};
237
+ }
238
+ if(applicability.api.status==='required')extensions.api=subset(old.contract,['generated_clients','contract_tests','regeneration_commands']);
239
+ if(applicability.cross_repo.status==='required')extensions.cross_repo=subset(old.cross_repo,['delivery_order','integration_verification','rollback_order']);
240
+ for(const [section,data]of Object.entries({frontend:old.frontend,backend:old.backend})) {
241
+ if(data?.status!=='required')continue;
242
+ for(const key of ['allowed_write_paths','forbidden_patterns','verification_commands','expected_evidence_files'])if(meaningful(data[key])&&!same(data[key],old.common?.[key]))conflicts.push({field:`${section}.${key}`,reason:'独有约束须显式映射至对应工作单元'});
243
+ }
244
+ const knownSub=['status','required_skills','allowed_write_paths','forbidden_patterns','verification_commands','expected_evidence_files'];
245
+ checkUnknown(old.frontend,[...knownSub,'approved_prototype_ref','state_matrix_ref','visual_baseline_ref','visual_baseline_case_ids','component_test_seams','e2e_paths','generated_api_client_ref','implementation_verification_ref','delivery'],'frontend');
246
+ checkUnknown(old.backend,[...knownSub,...constraintKeys,'affected_layers','component_impacts','tactical_design_ref','tactical_design_version','tactical_ddd','seam_deferred'],'backend');
247
+ checkUnknown(old.contract,['api_impact','freeze_ref','no_api_impact_ref','generated_clients','contract_tests','regeneration_commands'],'contract');
248
+ checkUnknown(old.cross_repo,['repositories','delivery_order','integration_verification','rollback_order'],'cross_repo');
249
+ const base={contract_id:old.contract_id,slice_id:old.slice_id,scope,applicability,recipe_ids:old.resolution?.recipe_ids,required_capabilities:old.resolution?.required_capabilities,conditions:old.resolution?.conditions,acceptance,verification,work_units,...(Object.keys(extensions).length?{extensions}:{})};
250
+ const migrated=mergeFacts(base,refinements,'migration', {blockers:conflicts});
251
+ migrated.contract_version=refinements.contract_version;
252
+ const result=prepareSliceImplementationContract({root,ticket_ref:ticketRef,sources:mergeFacts(sourceMap,sources,'sources',{blockers:conflicts}),refinements:migrated,...rest});
253
+ result.report.blockers.push(...conflicts);
254
+ result.report.migration={from_schema:2,to_schema:3,approval_inherited:false};
255
+ if(result.report.blockers.length)result.slice_contract.status='blocked';
256
+ return result;
257
+ }
@@ -0,0 +1,52 @@
1
+ import fs from 'node:fs';
2
+ import { safe, hash, digest } from './strategic-handoff-io.mjs';
3
+ import { selectSliceWorkUnit, readSliceContract, readSliceSources, sliceAcceptanceText, parseSliceYaml, sourceSliceContract } from './slice-contract.mjs';
4
+
5
+ function sections(text) {
6
+ const result={};let name='正文';
7
+ for(const line of text.split('\n')) {
8
+ const heading=/^#{1,3}\s+(.+)/.exec(line);
9
+ if(heading)name=heading[1];
10
+ else (result[name]??=[]).push(line);
11
+ }
12
+ return Object.fromEntries(Object.entries(result).filter(([name])=>!/验收/.test(name)).map(([name,lines])=>[name,lines.join('\n').trim()]));
13
+ }
14
+ export function renderSliceContractView(ref,{root=process.cwd(),unit_id}={}) {
15
+ const {contract,raw,binding,sources}=readSliceContract(ref,{root,diagnostic:true});
16
+ if(raw.status==='blocked') {
17
+ let report;try{report=JSON.parse(fs.readFileSync(safe(root,`${ref}.preparation.json`),'utf8'));if(report.binding.digest!==binding.digest)report=undefined;}catch{}
18
+ const blockers=report?.blockers||[{code:'SLICE_DIAGNOSTICS_UNAVAILABLE',reason:'未找到绑定当前字节的准备报告,需重新准备'}];
19
+ return {read_only:true,diagnostic_only:true,binding,status:'blocked',approval_validity:'阻断草案不可批准或执行',blockers,markdown:`# Slice 诊断\n\n${ref} · ${binding.digest}\n\n阻断草案不可批准或执行。\n\n`+blockers.map(b=>`- ${b.code} · ${b.field||'slice'}:${b.reason};${b.recovery||'重新准备'}`).join('\n')};
20
+ }
21
+
22
+ const displayed=unit_id?selectSliceWorkUnit(contract,unit_id):contract;
23
+ const task=unit_id?contract.work_units?.filter(u=>u.id===unit_id):null;
24
+ if(task&&task.length!==1)throw new TypeError(`工作单元缺失或不唯一: ${unit_id}`);
25
+ const view={ticket_state:raw.ticket_policy?{owner:raw.ticket_policy.state_owner,frozen_status:/^---\r?\n([\s\S]*?)\r?\n---/.test(sources.ticket.text)?parseSliceYaml(/^---\r?\n([\s\S]*?)\r?\n---/.exec(sources.ticket.text)[1]).status||'未记录':'未记录',current_status:'请读取主 tracker 或当前任务包',requirement_version:sources.ticket.version}:{owner:'legacy-ticket'},read_only:true,view_kind:unit_id?'work-unit':'review',binding,status:raw.status,approval_validity:'未核验;本视图不授予执行权限',sources:Object.fromEntries(Object.entries(sources).map(([k,{text,...b}])=>[k,b])),acceptance:raw.schema_version===3?sliceAcceptanceText(raw,sources):{},summary:sources.ticket?sections(sources.ticket.text.replace(/^---\n[\s\S]*?\n---\n/,'')):{说明:'v2 原合同未提供统一摘要来源'},constraints:displayed.common,extensions:{frontend:displayed.frontend,backend:displayed.backend,api:displayed.contract,cross_repo:displayed.cross_repo},...(task?{task:task[0].work_unit||task[0]}:{})};
26
+ const lines=[`# Slice ${raw.slice_id}`,`权威合同:${ref} · ${raw.contract_version} · ${binding.digest}`,`状态:${raw.status};${view.approval_validity}`];
27
+ for(const [name,pattern]of [['交付目标',/目标|构建/],['关键取舍',/取舍/],['风险',/风险/],['待决定事项',/待|决定/]]) { const rows=Object.entries(view.summary).filter(([key])=>pattern.test(key)&&!/^非目标/.test(key));lines.push(`## ${name}`,rows.map(([,text])=>text).filter(Boolean).join('\n')||'未提供说明,需在审查时核实。'); }
28
+ lines.push('## 实施范围',Object.entries(view.summary).filter(([name])=>/范围|非目标/.test(name)).map(([name,text])=>`${name}:${text}`).join('\n')||'未提供业务范围说明,需核对目标、工作单元与写边界。',`工程:${displayed.common?.project_roots?.join(', ') || '见原合同'}`,`允许写入:${displayed.common?.allowed_write_paths?.join(', ') || '见原合同'}`);
29
+ lines.push('## 验收',...Object.entries(view.acceptance).map(([id,text])=>`- ${id}: ${text}`));
30
+ if(raw.ticket_policy)lines.push('## 状态来源',`需求版本:${view.ticket_state.requirement_version};冻结时状态:${view.ticket_state.frozen_status}。当前执行状态:${view.ticket_state.current_status}。`);
31
+ if(view.task)lines.push('## 当前任务',`行为:${view.task.behavior}`,`写范围:${view.task.allowed_write_paths.join(', ')}`,`验证:${view.task.verification_commands.join('; ')}`);
32
+ lines.push('## 执行停止条件','来源或批准过期、越界、缺少证据、验证失败、drift / violation / new_impacts 时停止并回交。','<details><summary>完整工程约束与来源</summary>','', '```json',JSON.stringify({constraints:view.constraints,extensions:view.extensions,task:view.task,sources:view.sources},null,2),'```','</details>');
33
+ view.markdown=lines.join('\n\n');
34
+ return view;
35
+ }
36
+ export function diffSliceContracts(beforeRef,afterRef,{root=process.cwd(),beforeRoot=root}={}) {
37
+ const read=(base,ref)=>{const bytes=fs.readFileSync(safe(base,ref));return{raw:sourceSliceContract(parseSliceYaml(bytes)),binding:{ref,digest:hash(bytes)}};};
38
+ const before=read(beforeRoot,beforeRef),after=read(root,afterRef),changes=[];
39
+ function walk(a,b,p) {
40
+ if(digest(a??null)===digest(b??null)&&((a===undefined)===(b===undefined)))return;
41
+ if(a&&b&&typeof a==='object'&&typeof b==='object'&&!Array.isArray(a)&&!Array.isArray(b)) {
42
+ for(const key of new Set([...Object.keys(a),...Object.keys(b)]))walk(a[key],b[key],p?`${p}.${key}`:key);
43
+ }else changes.push({path:p,before:a??null,after:b??null,category:/^(scope\.(allowed_write_paths|project_roots)|work_units)/.test(p)?'scope':/^acceptance/.test(p)?'acceptance':/^(ticket_policy|basis\.ticket|contract_version|status)/.test(p)?'authorization':'engineering-detail',evidence:{before:before.binding,after:after.binding},decision_impact:'待独立专业审查判定'});
44
+ }
45
+ walk(before.raw,after.raw,'');
46
+ const sourceChecks=[];
47
+ for(const [label,entry,base]of [['before',before,beforeRoot],['after',after,root]]) {
48
+ try {if(entry.raw.schema_version!==3)throw new Error('v2 未冻结统一来源快照');readSliceSources(entry.raw,{root:base});sourceChecks.push({side:label,result:'current'});}
49
+ catch(error){sourceChecks.push({side:label,result:'unknown-or-stale',reason:error.message});}
50
+ }
51
+ return {read_only:true,before:before.binding,after:after.binding,bytes_changed:before.binding.digest!==after.binding.digest,category:changes.length?'requires-review':sourceChecks.some(x=>x.result!=='current')?'unknown-or-stale':before.binding.digest===after.binding.digest?'unchanged':'presentation-only',changes,source_checks:sourceChecks,approval_reusable:false,explanation:'字节变化后须重新绑定;用户确认是否延续由现有协议和独立专业审查裁决。'};
52
+ }