create-yss-spec 3.5.5 → 3.5.8

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 (554) hide show
  1. package/README.md +2 -0
  2. package/bin/create-yss-spec.js +3 -1
  3. package/cli-core.lock.json +11 -7
  4. package/package.json +4 -1
  5. package/src/api/_sync-service.js +3 -1
  6. package/src/command-runner.mjs +44 -9
  7. package/src/content-identity.js +111 -0
  8. package/src/runtime-store.mjs +650 -0
  9. package/src/template/asset-runtime.js +7 -2
  10. package/src/template/instance-runtime.js +27 -9
  11. package/src/validation/metadata.js +8 -0
  12. package/template/.agents/skills/.strategic-design-skills-manifest.json +1 -1
  13. package/template/.agents/skills/alibaba-java-code-style/SKILL.md +30 -36
  14. package/template/.agents/skills/archify/SKILL.md +2 -2
  15. package/template/.agents/skills/archify/scripts/yss-safe-deliver.mjs +10 -6
  16. package/template/.agents/skills/archify/test/yss-safe-deliver.test.mjs +9 -2
  17. package/template/.agents/skills/code-review/SKILL.md +19 -11
  18. package/template/.agents/skills/code-review/references/candidate-capture.md +1 -1
  19. package/template/.agents/skills/code-review/references/legacy-convergence.md +3 -1
  20. package/template/.agents/skills/code-review/references/review-axis-checklists.md +2 -0
  21. package/template/.agents/skills/code-review/references/yss-review-standards.md +4 -2
  22. package/template/.agents/skills/competitive-intelligence/SKILL.md +32 -74
  23. package/template/.agents/skills/file-export-download/SKILL.md +4 -73
  24. package/template/.agents/skills/file-export-download/references/binary-contract-example.md +26 -0
  25. package/template/.agents/skills/file-export-download/references/download-call-example.md +45 -0
  26. package/template/.agents/skills/formily-foundation/SKILL.md +6 -105
  27. package/template/.agents/skills/formily-foundation/references/async-save-example.md +57 -0
  28. package/template/.agents/skills/formily-foundation/references/query-layout.md +50 -0
  29. package/template/.agents/skills/formily-linkage-effects/SKILL.md +3 -116
  30. package/template/.agents/skills/formily-linkage-effects/references/linkage-example.md +116 -0
  31. package/template/.agents/skills/formily-mode-slot-detail/SKILL.md +3 -81
  32. package/template/.agents/skills/formily-mode-slot-detail/references/mode-slot-example.md +81 -0
  33. package/template/.agents/skills/formily-step-flow/SKILL.md +3 -143
  34. package/template/.agents/skills/formily-step-flow/references/step-flow-example.md +143 -0
  35. package/template/.agents/skills/handoff/SKILL.md +3 -1
  36. package/template/.agents/skills/i-have-adhd/SKILL.md +2 -2
  37. package/template/.agents/skills/i-have-adhd/references/yss-adaptation.md +2 -2
  38. package/template/.agents/skills/i-have-adhd/tests/verify-integration.mjs +7 -2
  39. package/template/.agents/skills/implement/SKILL.md +2 -2
  40. package/template/.agents/skills/llm-wiki/references/transactions.md +2 -2
  41. package/template/.agents/skills/llm-wiki/scripts/core.mjs +40 -2
  42. package/template/.agents/skills/llm-wiki/scripts/transaction.mjs +30 -27
  43. package/template/.agents/skills/llm-wiki/scripts/v2.test.mjs +38 -2
  44. package/template/.agents/skills/lombok/SKILL.md +2 -0
  45. package/template/.agents/skills/mapstruct/SKILL.md +2 -0
  46. package/template/.agents/skills/tdd/SKILL.md +2 -2
  47. package/template/.agents/skills/theme-token-usage/SKILL.md +6 -5
  48. package/template/.agents/skills/wayfinder/references/chart-map.md +2 -2
  49. package/template/.agents/skills/wayfinder/references/ticket-types.md +1 -1
  50. package/template/.agents/skills/yss-api-integration/SKILL.md +13 -50
  51. package/template/.agents/skills/yss-api-integration/references/orval-list-example.md +38 -0
  52. package/template/.agents/skills/yss-application/SKILL.md +11 -5
  53. package/template/.agents/skills/yss-audit-log/SKILL.md +8 -6
  54. package/template/.agents/skills/yss-audit-log/references/README.md +5 -5
  55. package/template/.agents/skills/yss-cache/SKILL.md +4 -4
  56. package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +7 -8
  57. package/template/.agents/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +13 -6
  58. package/template/.agents/skills/yss-ddd-scaffold-generator/references/command-examples.md +2 -0
  59. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +28 -1
  60. package/template/.agents/skills/yss-design-system/SKILL.md +2 -2
  61. package/template/.agents/skills/yss-distributed-id/SKILL.md +4 -4
  62. package/template/.agents/skills/yss-dto/SKILL.md +9 -9
  63. package/template/.agents/skills/yss-dto/references/README.md +4 -4
  64. package/template/.agents/skills/yss-dto/references/wire-validation-checklist.md +4 -4
  65. package/template/.agents/skills/yss-excel-mvc/SKILL.md +4 -4
  66. package/template/.agents/skills/yss-exception/SKILL.md +42 -48
  67. package/template/.agents/skills/yss-formily-schema-generator/SKILL.md +26 -170
  68. package/template/.agents/skills/yss-formily-schema-generator/references/workflow.md +49 -193
  69. package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +14 -10
  70. package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +2 -6
  71. package/template/.agents/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +15 -1
  72. package/template/.agents/skills/yss-layered-mvc-scaffold-generator/SKILL.md +1 -1
  73. package/template/.agents/skills/yss-mybatis/SKILL.md +4 -4
  74. package/template/.agents/skills/yss-openapi-draft-review/SKILL.md +6 -4
  75. package/template/.agents/skills/yss-openapi-draft-review/references/review-output.md +2 -0
  76. package/template/.agents/skills/yss-openapi-draft-review/references/semantic-review.md +3 -3
  77. package/template/.agents/skills/yss-openapi-governance/SKILL.md +5 -7
  78. package/template/.agents/skills/yss-openapi-governance/references/governance-output.md +2 -0
  79. package/template/.agents/skills/yss-openapi-governance/references/governance-workflow.md +3 -3
  80. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +23 -21
  81. package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  82. package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +25 -5
  83. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +100 -4
  84. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +35 -12
  85. package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +3 -1
  86. package/template/.agents/skills/yss-product-lifecycle/references/user-decisions.md +3 -3
  87. package/template/.agents/skills/yss-prototype-stage/SKILL.md +1 -5
  88. package/template/.agents/skills/yss-repository/SKILL.md +2 -2
  89. package/template/.agents/skills/yss-research/SKILL.md +39 -48
  90. package/template/.agents/skills/yss-research/assets/competitive-evidence-template.yaml +146 -0
  91. package/template/.agents/skills/yss-research/references/competitive-analysis.md +76 -0
  92. package/template/.agents/skills/yss-research/references/competitive-analysis.schema.json +324 -0
  93. package/template/.agents/skills/yss-research/references/evidence-contract.md +8 -0
  94. package/template/.agents/skills/yss-research/scripts/lib/competitive-analysis.mjs +185 -0
  95. package/template/.agents/skills/yss-research/scripts/render-competitive-outputs.mjs +16 -0
  96. package/template/.agents/skills/yss-research/scripts/validate-research-package.mjs +6 -2
  97. package/template/.agents/skills/yss-research/tests/competitive-scenarios.test.mjs +270 -0
  98. package/template/.agents/skills/yss-resilience4j/SKILL.md +25 -31
  99. package/template/.agents/skills/yss-security-algorithm/SKILL.md +37 -43
  100. package/template/.agents/skills/yss-skill-source-index-refresh/SKILL.md +29 -36
  101. package/template/.agents/skills/yss-skill-source-index-refresh/references/backend-component-platform-compatibility.md +1 -1
  102. package/template/.agents/skills/yss-stage-decision/SKILL.md +2 -5
  103. package/template/.agents/skills/yss-tactical-design/SKILL.md +1 -1
  104. package/template/.agents/skills/yss-tactical-design/references/output-template.md +3 -3
  105. package/template/.agents/skills/yss-tactical-design/references/tactical-design-contract.md +1 -1
  106. package/template/.agents/skills/yss-technical-design/SKILL.md +6 -5
  107. package/template/.agents/skills/yss-ui/SKILL.md +7 -1
  108. package/template/.agents/skills/yss-ui/assets/docs/guide/gitlab-ci-integration.md +2 -2
  109. package/template/.agents/skills/yss-ui/references/checklist.md +38 -96
  110. package/template/.agents/skills/yss-ui/references/component-routing.md +3 -1
  111. package/template/.agents/skills/yss-ui/references/quick-recipes.md +17 -272
  112. package/template/.agents/skills/yss-ui/references/specialized-components.md +3 -3
  113. package/template/.agents/skills/yss-ui-business-page-generation/SKILL.md +1 -1
  114. package/template/.agents/skills/yss-up-springboot3/SKILL.md +19 -21
  115. package/template/.agents/skills/yss-userinfo/SKILL.md +27 -33
  116. package/template/.agents/skills/yss-validation/SKILL.md +26 -32
  117. package/template/.agents/skills/yss-web-controller/SKILL.md +11 -44
  118. package/template/.agents/skills/yss-web-controller/references/crud-generation.md +38 -0
  119. package/template/.agents/skills/ytable-usage/SKILL.md +2 -2
  120. package/template/.agents/skills/ytree-usage/SKILL.md +2 -80
  121. package/template/.agents/skills/ytree-usage/references/tree-and-confirmation-example.md +81 -0
  122. package/template/.codex/skills/alibaba-java-code-style/SKILL.md +30 -36
  123. package/template/.codex/skills/archify/SKILL.md +2 -2
  124. package/template/.codex/skills/archify/scripts/yss-safe-deliver.mjs +10 -6
  125. package/template/.codex/skills/archify/test/yss-safe-deliver.test.mjs +9 -2
  126. package/template/.codex/skills/code-review/SKILL.md +19 -11
  127. package/template/.codex/skills/code-review/references/candidate-capture.md +1 -1
  128. package/template/.codex/skills/code-review/references/legacy-convergence.md +3 -1
  129. package/template/.codex/skills/code-review/references/review-axis-checklists.md +2 -0
  130. package/template/.codex/skills/code-review/references/yss-review-standards.md +4 -2
  131. package/template/.codex/skills/competitive-intelligence/SKILL.md +32 -74
  132. package/template/.codex/skills/file-export-download/SKILL.md +4 -73
  133. package/template/.codex/skills/file-export-download/references/binary-contract-example.md +26 -0
  134. package/template/.codex/skills/file-export-download/references/download-call-example.md +45 -0
  135. package/template/.codex/skills/formily-foundation/SKILL.md +6 -105
  136. package/template/.codex/skills/formily-foundation/references/async-save-example.md +57 -0
  137. package/template/.codex/skills/formily-foundation/references/query-layout.md +50 -0
  138. package/template/.codex/skills/formily-linkage-effects/SKILL.md +3 -116
  139. package/template/.codex/skills/formily-linkage-effects/references/linkage-example.md +116 -0
  140. package/template/.codex/skills/formily-mode-slot-detail/SKILL.md +3 -81
  141. package/template/.codex/skills/formily-mode-slot-detail/references/mode-slot-example.md +81 -0
  142. package/template/.codex/skills/formily-step-flow/SKILL.md +3 -143
  143. package/template/.codex/skills/formily-step-flow/references/step-flow-example.md +143 -0
  144. package/template/.codex/skills/handoff/SKILL.md +3 -1
  145. package/template/.codex/skills/i-have-adhd/SKILL.md +2 -2
  146. package/template/.codex/skills/i-have-adhd/references/yss-adaptation.md +2 -2
  147. package/template/.codex/skills/i-have-adhd/tests/verify-integration.mjs +7 -2
  148. package/template/.codex/skills/implement/SKILL.md +2 -2
  149. package/template/.codex/skills/llm-wiki/references/transactions.md +2 -2
  150. package/template/.codex/skills/llm-wiki/scripts/core.mjs +40 -2
  151. package/template/.codex/skills/llm-wiki/scripts/transaction.mjs +30 -27
  152. package/template/.codex/skills/llm-wiki/scripts/v2.test.mjs +38 -2
  153. package/template/.codex/skills/lombok/SKILL.md +2 -0
  154. package/template/.codex/skills/mapstruct/SKILL.md +2 -0
  155. package/template/.codex/skills/product-design/references/communication-protocol.md +3 -3
  156. package/template/.codex/skills/product-design/references/critical-overrides.md +4 -5
  157. package/template/.codex/skills/product-design/skills/audit/SKILL.md +2 -4
  158. package/template/.codex/skills/product-design/skills/get-context/SKILL.md +6 -8
  159. package/template/.codex/skills/product-design/skills/ideate/SKILL.md +3 -3
  160. package/template/.codex/skills/product-design/skills/image-to-code/SKILL.md +3 -5
  161. package/template/.codex/skills/product-design/skills/index/SKILL.md +1 -1
  162. package/template/.codex/skills/product-design/skills/prototype/SKILL.md +2 -4
  163. package/template/.codex/skills/product-design/skills/research/SKILL.md +4 -6
  164. package/template/.codex/skills/product-design/skills/research/assets/research-brief-template.md +3 -3
  165. package/template/.codex/skills/product-design/skills/share/SKILL.md +2 -4
  166. package/template/.codex/skills/product-design/skills/url-to-code/SKILL.md +2 -4
  167. package/template/.codex/skills/product-design/skills/user-context/SKILL.md +1 -1
  168. package/template/.codex/skills/tdd/SKILL.md +2 -2
  169. package/template/.codex/skills/theme-token-usage/SKILL.md +6 -5
  170. package/template/.codex/skills/wayfinder/references/chart-map.md +2 -2
  171. package/template/.codex/skills/wayfinder/references/ticket-types.md +1 -1
  172. package/template/.codex/skills/yss-api-integration/SKILL.md +13 -50
  173. package/template/.codex/skills/yss-api-integration/references/orval-list-example.md +38 -0
  174. package/template/.codex/skills/yss-application/SKILL.md +11 -5
  175. package/template/.codex/skills/yss-audit-log/SKILL.md +8 -6
  176. package/template/.codex/skills/yss-audit-log/references/README.md +5 -5
  177. package/template/.codex/skills/yss-cache/SKILL.md +4 -4
  178. package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +7 -8
  179. package/template/.codex/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +13 -6
  180. package/template/.codex/skills/yss-ddd-scaffold-generator/references/command-examples.md +2 -0
  181. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +28 -1
  182. package/template/.codex/skills/yss-design-system/SKILL.md +2 -2
  183. package/template/.codex/skills/yss-distributed-id/SKILL.md +4 -4
  184. package/template/.codex/skills/yss-dto/SKILL.md +9 -9
  185. package/template/.codex/skills/yss-dto/references/README.md +4 -4
  186. package/template/.codex/skills/yss-dto/references/wire-validation-checklist.md +4 -4
  187. package/template/.codex/skills/yss-excel-mvc/SKILL.md +4 -4
  188. package/template/.codex/skills/yss-exception/SKILL.md +42 -48
  189. package/template/.codex/skills/yss-formily-schema-generator/SKILL.md +26 -170
  190. package/template/.codex/skills/yss-formily-schema-generator/references/workflow.md +49 -193
  191. package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +14 -10
  192. package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +2 -6
  193. package/template/.codex/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +15 -1
  194. package/template/.codex/skills/yss-layered-mvc-scaffold-generator/SKILL.md +1 -1
  195. package/template/.codex/skills/yss-mybatis/SKILL.md +4 -4
  196. package/template/.codex/skills/yss-openapi-draft-review/SKILL.md +6 -4
  197. package/template/.codex/skills/yss-openapi-draft-review/references/review-output.md +2 -0
  198. package/template/.codex/skills/yss-openapi-draft-review/references/semantic-review.md +3 -3
  199. package/template/.codex/skills/yss-openapi-governance/SKILL.md +5 -7
  200. package/template/.codex/skills/yss-openapi-governance/references/governance-output.md +2 -0
  201. package/template/.codex/skills/yss-openapi-governance/references/governance-workflow.md +3 -3
  202. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +23 -21
  203. package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  204. package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +25 -5
  205. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +100 -4
  206. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +35 -12
  207. package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +3 -1
  208. package/template/.codex/skills/yss-product-lifecycle/references/user-decisions.md +3 -3
  209. package/template/.codex/skills/yss-prototype-stage/SKILL.md +1 -5
  210. package/template/.codex/skills/yss-repository/SKILL.md +2 -2
  211. package/template/.codex/skills/yss-research/SKILL.md +39 -48
  212. package/template/.codex/skills/yss-research/assets/competitive-evidence-template.yaml +146 -0
  213. package/template/.codex/skills/yss-research/references/competitive-analysis.md +76 -0
  214. package/template/.codex/skills/yss-research/references/competitive-analysis.schema.json +324 -0
  215. package/template/.codex/skills/yss-research/references/evidence-contract.md +8 -0
  216. package/template/.codex/skills/yss-research/scripts/lib/competitive-analysis.mjs +185 -0
  217. package/template/.codex/skills/yss-research/scripts/render-competitive-outputs.mjs +16 -0
  218. package/template/.codex/skills/yss-research/scripts/validate-research-package.mjs +6 -2
  219. package/template/.codex/skills/yss-research/tests/competitive-scenarios.test.mjs +270 -0
  220. package/template/.codex/skills/yss-resilience4j/SKILL.md +25 -31
  221. package/template/.codex/skills/yss-security-algorithm/SKILL.md +37 -43
  222. package/template/.codex/skills/yss-skill-source-index-refresh/SKILL.md +29 -36
  223. package/template/.codex/skills/yss-skill-source-index-refresh/references/backend-component-platform-compatibility.md +1 -1
  224. package/template/.codex/skills/yss-stage-decision/SKILL.md +2 -5
  225. package/template/.codex/skills/yss-tactical-design/SKILL.md +1 -1
  226. package/template/.codex/skills/yss-tactical-design/references/output-template.md +3 -3
  227. package/template/.codex/skills/yss-tactical-design/references/tactical-design-contract.md +1 -1
  228. package/template/.codex/skills/yss-technical-design/SKILL.md +6 -5
  229. package/template/.codex/skills/yss-ui/SKILL.md +7 -1
  230. package/template/.codex/skills/yss-ui/assets/docs/guide/gitlab-ci-integration.md +2 -2
  231. package/template/.codex/skills/yss-ui/references/checklist.md +38 -96
  232. package/template/.codex/skills/yss-ui/references/component-routing.md +3 -1
  233. package/template/.codex/skills/yss-ui/references/quick-recipes.md +17 -272
  234. package/template/.codex/skills/yss-ui/references/specialized-components.md +3 -3
  235. package/template/.codex/skills/yss-ui-business-page-generation/SKILL.md +1 -1
  236. package/template/.codex/skills/yss-up-springboot3/SKILL.md +19 -21
  237. package/template/.codex/skills/yss-userinfo/SKILL.md +27 -33
  238. package/template/.codex/skills/yss-validation/SKILL.md +26 -32
  239. package/template/.codex/skills/yss-web-controller/SKILL.md +11 -44
  240. package/template/.codex/skills/yss-web-controller/references/crud-generation.md +38 -0
  241. package/template/.codex/skills/ytable-usage/SKILL.md +2 -2
  242. package/template/.codex/skills/ytree-usage/SKILL.md +2 -80
  243. package/template/.codex/skills/ytree-usage/references/tree-and-confirmation-example.md +81 -0
  244. package/template/.cursor/skills/alibaba-java-code-style/SKILL.md +30 -36
  245. package/template/.cursor/skills/archify/SKILL.md +2 -2
  246. package/template/.cursor/skills/archify/scripts/yss-safe-deliver.mjs +10 -6
  247. package/template/.cursor/skills/archify/test/yss-safe-deliver.test.mjs +9 -2
  248. package/template/.cursor/skills/code-review/SKILL.md +19 -11
  249. package/template/.cursor/skills/code-review/references/candidate-capture.md +1 -1
  250. package/template/.cursor/skills/code-review/references/legacy-convergence.md +3 -1
  251. package/template/.cursor/skills/code-review/references/review-axis-checklists.md +2 -0
  252. package/template/.cursor/skills/code-review/references/yss-review-standards.md +4 -2
  253. package/template/.cursor/skills/competitive-intelligence/SKILL.md +32 -74
  254. package/template/.cursor/skills/file-export-download/SKILL.md +4 -73
  255. package/template/.cursor/skills/file-export-download/references/binary-contract-example.md +26 -0
  256. package/template/.cursor/skills/file-export-download/references/download-call-example.md +45 -0
  257. package/template/.cursor/skills/formily-foundation/SKILL.md +6 -105
  258. package/template/.cursor/skills/formily-foundation/references/async-save-example.md +57 -0
  259. package/template/.cursor/skills/formily-foundation/references/query-layout.md +50 -0
  260. package/template/.cursor/skills/formily-linkage-effects/SKILL.md +3 -116
  261. package/template/.cursor/skills/formily-linkage-effects/references/linkage-example.md +116 -0
  262. package/template/.cursor/skills/formily-mode-slot-detail/SKILL.md +3 -81
  263. package/template/.cursor/skills/formily-mode-slot-detail/references/mode-slot-example.md +81 -0
  264. package/template/.cursor/skills/formily-step-flow/SKILL.md +3 -143
  265. package/template/.cursor/skills/formily-step-flow/references/step-flow-example.md +143 -0
  266. package/template/.cursor/skills/handoff/SKILL.md +3 -1
  267. package/template/.cursor/skills/i-have-adhd/SKILL.md +2 -2
  268. package/template/.cursor/skills/i-have-adhd/references/yss-adaptation.md +2 -2
  269. package/template/.cursor/skills/i-have-adhd/tests/verify-integration.mjs +7 -2
  270. package/template/.cursor/skills/implement/SKILL.md +2 -2
  271. package/template/.cursor/skills/llm-wiki/references/transactions.md +2 -2
  272. package/template/.cursor/skills/llm-wiki/scripts/core.mjs +40 -2
  273. package/template/.cursor/skills/llm-wiki/scripts/transaction.mjs +30 -27
  274. package/template/.cursor/skills/llm-wiki/scripts/v2.test.mjs +38 -2
  275. package/template/.cursor/skills/lombok/SKILL.md +2 -0
  276. package/template/.cursor/skills/mapstruct/SKILL.md +2 -0
  277. package/template/.cursor/skills/tdd/SKILL.md +2 -2
  278. package/template/.cursor/skills/theme-token-usage/SKILL.md +6 -5
  279. package/template/.cursor/skills/wayfinder/references/chart-map.md +2 -2
  280. package/template/.cursor/skills/wayfinder/references/ticket-types.md +1 -1
  281. package/template/.cursor/skills/yss-api-integration/SKILL.md +13 -50
  282. package/template/.cursor/skills/yss-api-integration/references/orval-list-example.md +38 -0
  283. package/template/.cursor/skills/yss-application/SKILL.md +11 -5
  284. package/template/.cursor/skills/yss-audit-log/SKILL.md +8 -6
  285. package/template/.cursor/skills/yss-audit-log/references/README.md +5 -5
  286. package/template/.cursor/skills/yss-cache/SKILL.md +4 -4
  287. package/template/.cursor/skills/yss-ddd-scaffold-generator/SKILL.md +7 -8
  288. package/template/.cursor/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +13 -6
  289. package/template/.cursor/skills/yss-ddd-scaffold-generator/references/command-examples.md +2 -0
  290. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +28 -1
  291. package/template/.cursor/skills/yss-design-system/SKILL.md +2 -2
  292. package/template/.cursor/skills/yss-distributed-id/SKILL.md +4 -4
  293. package/template/.cursor/skills/yss-dto/SKILL.md +9 -9
  294. package/template/.cursor/skills/yss-dto/references/README.md +4 -4
  295. package/template/.cursor/skills/yss-dto/references/wire-validation-checklist.md +4 -4
  296. package/template/.cursor/skills/yss-excel-mvc/SKILL.md +4 -4
  297. package/template/.cursor/skills/yss-exception/SKILL.md +42 -48
  298. package/template/.cursor/skills/yss-formily-schema-generator/SKILL.md +26 -170
  299. package/template/.cursor/skills/yss-formily-schema-generator/references/workflow.md +49 -193
  300. package/template/.cursor/skills/yss-frontend-scaffold-generator/SKILL.md +14 -10
  301. package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +2 -6
  302. package/template/.cursor/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +15 -1
  303. package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/SKILL.md +1 -1
  304. package/template/.cursor/skills/yss-mybatis/SKILL.md +4 -4
  305. package/template/.cursor/skills/yss-openapi-draft-review/SKILL.md +6 -4
  306. package/template/.cursor/skills/yss-openapi-draft-review/references/review-output.md +2 -0
  307. package/template/.cursor/skills/yss-openapi-draft-review/references/semantic-review.md +3 -3
  308. package/template/.cursor/skills/yss-openapi-governance/SKILL.md +5 -7
  309. package/template/.cursor/skills/yss-openapi-governance/references/governance-output.md +2 -0
  310. package/template/.cursor/skills/yss-openapi-governance/references/governance-workflow.md +3 -3
  311. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +23 -21
  312. package/template/.cursor/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  313. package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +25 -5
  314. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +100 -4
  315. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +35 -12
  316. package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +3 -1
  317. package/template/.cursor/skills/yss-product-lifecycle/references/user-decisions.md +3 -3
  318. package/template/.cursor/skills/yss-prototype-stage/SKILL.md +1 -5
  319. package/template/.cursor/skills/yss-repository/SKILL.md +2 -2
  320. package/template/.cursor/skills/yss-research/SKILL.md +39 -48
  321. package/template/.cursor/skills/yss-research/assets/competitive-evidence-template.yaml +146 -0
  322. package/template/.cursor/skills/yss-research/references/competitive-analysis.md +76 -0
  323. package/template/.cursor/skills/yss-research/references/competitive-analysis.schema.json +324 -0
  324. package/template/.cursor/skills/yss-research/references/evidence-contract.md +8 -0
  325. package/template/.cursor/skills/yss-research/scripts/lib/competitive-analysis.mjs +185 -0
  326. package/template/.cursor/skills/yss-research/scripts/render-competitive-outputs.mjs +16 -0
  327. package/template/.cursor/skills/yss-research/scripts/validate-research-package.mjs +6 -2
  328. package/template/.cursor/skills/yss-research/tests/competitive-scenarios.test.mjs +270 -0
  329. package/template/.cursor/skills/yss-resilience4j/SKILL.md +25 -31
  330. package/template/.cursor/skills/yss-security-algorithm/SKILL.md +37 -43
  331. package/template/.cursor/skills/yss-skill-source-index-refresh/SKILL.md +29 -36
  332. package/template/.cursor/skills/yss-skill-source-index-refresh/references/backend-component-platform-compatibility.md +1 -1
  333. package/template/.cursor/skills/yss-stage-decision/SKILL.md +2 -5
  334. package/template/.cursor/skills/yss-tactical-design/SKILL.md +1 -1
  335. package/template/.cursor/skills/yss-tactical-design/references/output-template.md +3 -3
  336. package/template/.cursor/skills/yss-tactical-design/references/tactical-design-contract.md +1 -1
  337. package/template/.cursor/skills/yss-technical-design/SKILL.md +6 -5
  338. package/template/.cursor/skills/yss-ui/SKILL.md +7 -1
  339. package/template/.cursor/skills/yss-ui/assets/docs/guide/gitlab-ci-integration.md +2 -2
  340. package/template/.cursor/skills/yss-ui/references/checklist.md +38 -96
  341. package/template/.cursor/skills/yss-ui/references/component-routing.md +3 -1
  342. package/template/.cursor/skills/yss-ui/references/quick-recipes.md +17 -272
  343. package/template/.cursor/skills/yss-ui/references/specialized-components.md +3 -3
  344. package/template/.cursor/skills/yss-ui-business-page-generation/SKILL.md +1 -1
  345. package/template/.cursor/skills/yss-up-springboot3/SKILL.md +19 -21
  346. package/template/.cursor/skills/yss-userinfo/SKILL.md +27 -33
  347. package/template/.cursor/skills/yss-validation/SKILL.md +26 -32
  348. package/template/.cursor/skills/yss-web-controller/SKILL.md +11 -44
  349. package/template/.cursor/skills/yss-web-controller/references/crud-generation.md +38 -0
  350. package/template/.cursor/skills/ytable-usage/SKILL.md +2 -2
  351. package/template/.cursor/skills/ytree-usage/SKILL.md +2 -80
  352. package/template/.cursor/skills/ytree-usage/references/tree-and-confirmation-example.md +81 -0
  353. package/template/.pi/skills/alibaba-java-code-style/SKILL.md +30 -36
  354. package/template/.pi/skills/archify/SKILL.md +2 -2
  355. package/template/.pi/skills/archify/scripts/yss-safe-deliver.mjs +10 -6
  356. package/template/.pi/skills/archify/test/yss-safe-deliver.test.mjs +9 -2
  357. package/template/.pi/skills/code-review/SKILL.md +19 -11
  358. package/template/.pi/skills/code-review/references/candidate-capture.md +1 -1
  359. package/template/.pi/skills/code-review/references/legacy-convergence.md +3 -1
  360. package/template/.pi/skills/code-review/references/review-axis-checklists.md +2 -0
  361. package/template/.pi/skills/code-review/references/yss-review-standards.md +4 -2
  362. package/template/.pi/skills/competitive-intelligence/SKILL.md +32 -74
  363. package/template/.pi/skills/file-export-download/SKILL.md +4 -73
  364. package/template/.pi/skills/file-export-download/references/binary-contract-example.md +26 -0
  365. package/template/.pi/skills/file-export-download/references/download-call-example.md +45 -0
  366. package/template/.pi/skills/formily-foundation/SKILL.md +6 -105
  367. package/template/.pi/skills/formily-foundation/references/async-save-example.md +57 -0
  368. package/template/.pi/skills/formily-foundation/references/query-layout.md +50 -0
  369. package/template/.pi/skills/formily-linkage-effects/SKILL.md +3 -116
  370. package/template/.pi/skills/formily-linkage-effects/references/linkage-example.md +116 -0
  371. package/template/.pi/skills/formily-mode-slot-detail/SKILL.md +3 -81
  372. package/template/.pi/skills/formily-mode-slot-detail/references/mode-slot-example.md +81 -0
  373. package/template/.pi/skills/formily-step-flow/SKILL.md +3 -143
  374. package/template/.pi/skills/formily-step-flow/references/step-flow-example.md +143 -0
  375. package/template/.pi/skills/handoff/SKILL.md +3 -1
  376. package/template/.pi/skills/i-have-adhd/SKILL.md +2 -2
  377. package/template/.pi/skills/i-have-adhd/references/yss-adaptation.md +2 -2
  378. package/template/.pi/skills/i-have-adhd/tests/verify-integration.mjs +7 -2
  379. package/template/.pi/skills/implement/SKILL.md +2 -2
  380. package/template/.pi/skills/llm-wiki/references/transactions.md +2 -2
  381. package/template/.pi/skills/llm-wiki/scripts/core.mjs +40 -2
  382. package/template/.pi/skills/llm-wiki/scripts/transaction.mjs +30 -27
  383. package/template/.pi/skills/llm-wiki/scripts/v2.test.mjs +38 -2
  384. package/template/.pi/skills/lombok/SKILL.md +2 -0
  385. package/template/.pi/skills/mapstruct/SKILL.md +2 -0
  386. package/template/.pi/skills/tdd/SKILL.md +2 -2
  387. package/template/.pi/skills/theme-token-usage/SKILL.md +6 -5
  388. package/template/.pi/skills/wayfinder/references/chart-map.md +2 -2
  389. package/template/.pi/skills/wayfinder/references/ticket-types.md +1 -1
  390. package/template/.pi/skills/yss-api-integration/SKILL.md +13 -50
  391. package/template/.pi/skills/yss-api-integration/references/orval-list-example.md +38 -0
  392. package/template/.pi/skills/yss-application/SKILL.md +11 -5
  393. package/template/.pi/skills/yss-audit-log/SKILL.md +8 -6
  394. package/template/.pi/skills/yss-audit-log/references/README.md +5 -5
  395. package/template/.pi/skills/yss-cache/SKILL.md +4 -4
  396. package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +7 -8
  397. package/template/.pi/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +13 -6
  398. package/template/.pi/skills/yss-ddd-scaffold-generator/references/command-examples.md +2 -0
  399. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +28 -1
  400. package/template/.pi/skills/yss-design-system/SKILL.md +2 -2
  401. package/template/.pi/skills/yss-distributed-id/SKILL.md +4 -4
  402. package/template/.pi/skills/yss-dto/SKILL.md +9 -9
  403. package/template/.pi/skills/yss-dto/references/README.md +4 -4
  404. package/template/.pi/skills/yss-dto/references/wire-validation-checklist.md +4 -4
  405. package/template/.pi/skills/yss-excel-mvc/SKILL.md +4 -4
  406. package/template/.pi/skills/yss-exception/SKILL.md +42 -48
  407. package/template/.pi/skills/yss-formily-schema-generator/SKILL.md +26 -170
  408. package/template/.pi/skills/yss-formily-schema-generator/references/workflow.md +49 -193
  409. package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +14 -10
  410. package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +2 -6
  411. package/template/.pi/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +15 -1
  412. package/template/.pi/skills/yss-layered-mvc-scaffold-generator/SKILL.md +1 -1
  413. package/template/.pi/skills/yss-mybatis/SKILL.md +4 -4
  414. package/template/.pi/skills/yss-openapi-draft-review/SKILL.md +6 -4
  415. package/template/.pi/skills/yss-openapi-draft-review/references/review-output.md +2 -0
  416. package/template/.pi/skills/yss-openapi-draft-review/references/semantic-review.md +3 -3
  417. package/template/.pi/skills/yss-openapi-governance/SKILL.md +5 -7
  418. package/template/.pi/skills/yss-openapi-governance/references/governance-output.md +2 -0
  419. package/template/.pi/skills/yss-openapi-governance/references/governance-workflow.md +3 -3
  420. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +23 -21
  421. package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  422. package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +25 -5
  423. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +100 -4
  424. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +35 -12
  425. package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +3 -1
  426. package/template/.pi/skills/yss-product-lifecycle/references/user-decisions.md +3 -3
  427. package/template/.pi/skills/yss-prototype-stage/SKILL.md +1 -5
  428. package/template/.pi/skills/yss-repository/SKILL.md +2 -2
  429. package/template/.pi/skills/yss-research/SKILL.md +39 -48
  430. package/template/.pi/skills/yss-research/assets/competitive-evidence-template.yaml +146 -0
  431. package/template/.pi/skills/yss-research/references/competitive-analysis.md +76 -0
  432. package/template/.pi/skills/yss-research/references/competitive-analysis.schema.json +324 -0
  433. package/template/.pi/skills/yss-research/references/evidence-contract.md +8 -0
  434. package/template/.pi/skills/yss-research/scripts/lib/competitive-analysis.mjs +185 -0
  435. package/template/.pi/skills/yss-research/scripts/render-competitive-outputs.mjs +16 -0
  436. package/template/.pi/skills/yss-research/scripts/validate-research-package.mjs +6 -2
  437. package/template/.pi/skills/yss-research/tests/competitive-scenarios.test.mjs +270 -0
  438. package/template/.pi/skills/yss-resilience4j/SKILL.md +25 -31
  439. package/template/.pi/skills/yss-security-algorithm/SKILL.md +37 -43
  440. package/template/.pi/skills/yss-skill-source-index-refresh/SKILL.md +29 -36
  441. package/template/.pi/skills/yss-skill-source-index-refresh/references/backend-component-platform-compatibility.md +1 -1
  442. package/template/.pi/skills/yss-stage-decision/SKILL.md +2 -5
  443. package/template/.pi/skills/yss-tactical-design/SKILL.md +1 -1
  444. package/template/.pi/skills/yss-tactical-design/references/output-template.md +3 -3
  445. package/template/.pi/skills/yss-tactical-design/references/tactical-design-contract.md +1 -1
  446. package/template/.pi/skills/yss-technical-design/SKILL.md +6 -5
  447. package/template/.pi/skills/yss-ui/SKILL.md +7 -1
  448. package/template/.pi/skills/yss-ui/assets/docs/guide/gitlab-ci-integration.md +2 -2
  449. package/template/.pi/skills/yss-ui/references/checklist.md +38 -96
  450. package/template/.pi/skills/yss-ui/references/component-routing.md +3 -1
  451. package/template/.pi/skills/yss-ui/references/quick-recipes.md +17 -272
  452. package/template/.pi/skills/yss-ui/references/specialized-components.md +3 -3
  453. package/template/.pi/skills/yss-ui-business-page-generation/SKILL.md +1 -1
  454. package/template/.pi/skills/yss-up-springboot3/SKILL.md +19 -21
  455. package/template/.pi/skills/yss-userinfo/SKILL.md +27 -33
  456. package/template/.pi/skills/yss-validation/SKILL.md +26 -32
  457. package/template/.pi/skills/yss-web-controller/SKILL.md +11 -44
  458. package/template/.pi/skills/yss-web-controller/references/crud-generation.md +38 -0
  459. package/template/.pi/skills/ytable-usage/SKILL.md +2 -2
  460. package/template/.pi/skills/ytree-usage/SKILL.md +2 -80
  461. package/template/.pi/skills/ytree-usage/references/tree-and-confirmation-example.md +81 -0
  462. package/template/.template-spec/agents/backend-architecture-profiles.md +1 -1
  463. package/template/.template-spec/agents/digital-human-roles.md +5 -1
  464. package/template/.template-spec/agents/digital-human-roles.yaml +49 -1
  465. package/template/.template-spec/engineering/backend-platforms.json +1 -1
  466. package/template/.template-spec/plan/templates/competitive-analysis-template.md +38 -36
  467. package/template/.template-spec/plan/templates/competitive-matrix-template.md +37 -17
  468. package/template/.template-spec/process/document-writing.md +22 -3
  469. package/template/.template-spec/process/harness-process-tailoring.md +5 -1
  470. package/template/.template-spec/process/implementation-repo-integration.md +26 -8
  471. package/template/.template-spec/process/research-completion.md +2 -0
  472. package/template/.template-spec/process/runtime-storage.md +78 -0
  473. package/template/.template-spec/process/schemas/approval-context.schema.json +67 -0
  474. package/template/.template-spec/process/schemas/approval-record.schema.json +179 -16
  475. package/template/.template-spec/process/schemas/backend-delivery.schema.json +16 -0
  476. package/template/.template-spec/process/schemas/delivery-preflight-input.schema.json +4 -0
  477. package/template/.template-spec/process/schemas/digital-human-task-package.schema.json +236 -1
  478. package/template/.template-spec/process/schemas/implementation-repository-preparation-result.schema.json +335 -52
  479. package/template/.template-spec/process/schemas/lifecycle-checkpoint.schema.json +11 -0
  480. package/template/.template-spec/process/schemas/project-scaffold-contract.schema.json +3 -0
  481. package/template/.template-spec/process/schemas/review-bundle.schema.json +347 -35
  482. package/template/.template-spec/process/schemas/strategic-design-handoff-v3.schema.json +504 -0
  483. package/template/.template-spec/process/schemas/strategic-design-handoff-v4.schema.json +544 -8
  484. package/template/.template-spec/process/schemas/strategic-design-handoff-v5.schema.json +616 -0
  485. package/template/.template-spec/process/schemas/strategic-design-handoff.schema.json +616 -0
  486. package/template/.template-spec/process/schemas/strategic-handoff-domain-strategy-v3.schema.json +712 -109
  487. package/template/.template-spec/process/schemas/strategic-handoff-domain-strategy.schema.json +595 -90
  488. package/template/.template-spec/process/schemas/strategic-handoff-export-v2.schema.json +448 -0
  489. package/template/.template-spec/process/schemas/strategic-handoff-export.schema.json +392 -0
  490. package/template/.template-spec/process/schemas/strategic-handoff-stage-decision-package-v3.schema.json +556 -83
  491. package/template/.template-spec/process/schemas/strategic-handoff-stage-decision-package.schema.json +418 -57
  492. package/template/.template-spec/process/subagent-collaboration.md +7 -1
  493. package/template/.template-spec/templates/approval-record-template.json +7 -3
  494. package/template/.template-spec/templates/approval-record-template.yaml +8 -2
  495. package/template/.template-spec/templates/examples/lifecycle-writing-examples.md +92 -2
  496. package/template/.template-spec/templates/retro-report-template.md +10 -3
  497. package/template/.template-spec/templates/review-bundle-template.yaml +19 -10
  498. package/template/AGENTS.md +4 -3
  499. package/template/CONTEXT.md +2 -2
  500. package/template/README.md +2 -2
  501. package/template/scripts/advance-maintenance-iteration +51 -0
  502. package/template/scripts/lib/approval-checkpoint-discovery.mjs +26 -0
  503. package/template/scripts/lib/approval-consumption.mjs +35 -0
  504. package/template/scripts/lib/approval-current.mjs +111 -0
  505. package/template/scripts/lib/approval-record-io.mjs +56 -0
  506. package/template/scripts/lib/approval-record.mjs +79 -184
  507. package/template/scripts/lib/approved-execution-context.mjs +8 -6
  508. package/template/scripts/lib/asset-transactions.mjs +5 -1
  509. package/template/scripts/lib/backend-delivery.mjs +1 -1
  510. package/template/scripts/lib/backend-review.mjs +2 -1
  511. package/template/scripts/lib/backend-scaffold-prerequisites.mjs +3 -2
  512. package/template/scripts/lib/business-ticket-lifecycle.mjs +2 -1
  513. package/template/scripts/lib/checkpoint-commit.mjs +50 -0
  514. package/template/scripts/lib/command-runner.mjs +44 -9
  515. package/template/scripts/lib/content-identity.mjs +273 -0
  516. package/template/scripts/lib/delivery-preflight.mjs +2 -1
  517. package/template/scripts/lib/digital-human-roles.mjs +12 -5
  518. package/template/scripts/lib/drift-report.mjs +110 -0
  519. package/template/scripts/lib/existing-backend-architecture.mjs +4 -1
  520. package/template/scripts/lib/lifecycle-context-query.mjs +172 -11
  521. package/template/scripts/lib/lifecycle-controls.mjs +9 -19
  522. package/template/scripts/lib/lifecycle-presentation.mjs +5 -0
  523. package/template/scripts/lib/lifecycle-status.mjs +63 -12
  524. package/template/scripts/lib/lifecycle-transition.mjs +2 -1
  525. package/template/scripts/lib/maintenance-candidate.mjs +24 -30
  526. package/template/scripts/lib/maintenance-research.mjs +52 -8
  527. package/template/scripts/lib/maintenance-storage.mjs +81 -0
  528. package/template/scripts/lib/plan-spec-entry.mjs +2 -1
  529. package/template/scripts/lib/project-governance.mjs +2 -1
  530. package/template/scripts/lib/read-only-intake.mjs +44 -9
  531. package/template/scripts/lib/review-capabilities.mjs +234 -0
  532. package/template/scripts/lib/review-package.mjs +100 -0
  533. package/template/scripts/lib/runtime-store.mjs +650 -0
  534. package/template/scripts/lib/skill-registry.mjs +4 -4
  535. package/template/scripts/lib/strategic-handoff.mjs +22 -9
  536. package/template/scripts/lib/task-package.mjs +47 -16
  537. package/template/scripts/lifecycle-status +26 -1
  538. package/template/scripts/maintenance-path +11 -0
  539. package/template/scripts/prepare-review-package +8 -0
  540. package/template/scripts/project-ci +13 -3
  541. package/template/scripts/query-lifecycle-context +8 -1
  542. package/template/scripts/run-read-only-intake +2 -2
  543. package/template/scripts/runtime-store +40 -0
  544. package/template/scripts/verify-approval-record +21 -13
  545. package/template/scripts/verify-lifecycle-checkpoint +7 -3
  546. package/template/scripts/verify-project-instance +21 -1
  547. package/template/skills-lock.json +62 -61
  548. package/template.snapshot.json +4 -4
  549. package/vendor/cli-core/cli.mjs +2 -0
  550. package/vendor/cli-core/command-runner.mjs +44 -9
  551. package/vendor/cli-core/package.json +1 -1
  552. package/vendor/cli-core/runtime-store.mjs +650 -0
  553. package/vendor/cli-core/scaffold.mjs +4 -2
  554. package/vendor/cli-core/tests/package-contract.mjs +14 -0
@@ -1,6 +1,8 @@
1
1
  import { loadExecutionScope, assertScopeWorkUnit, scopedNextRoutes } from './lifecycle-execution-scope.mjs';
2
2
  import { createHash } from "node:crypto";
3
- import { readFileSync, withValidationPhase, validationDependencies } from "./validation-phase.mjs";
3
+ import { readFileSync, existsSync, lstatSync, readdirSync, withValidationPhase, validationDependencies } from "./validation-phase.mjs";
4
+ import { realpathSync } from "node:fs";
5
+ import { OBSOLETE } from "./skill-supply-chain.mjs";
4
6
  import path from "node:path";
5
7
  import { parseDocument } from "../vendor/yaml.mjs";
6
8
  import { ROOT, loadRegistry, semanticDigest, validateRegistry } from "./lifecycle-registry.mjs";
@@ -10,6 +12,8 @@ import { loadLifecyclePresenter } from './lifecycle-presentation.mjs';
10
12
  const LIFECYCLE_REGISTRY_REF = ".template-spec/process/lifecycle-registry.yaml";
11
13
  const ORCHESTRATION_CONTRACT_REF = ".agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml";
12
14
  const SKILL_REGISTRY_REF = ".template-spec/agents/yss-skill-registry.yaml";
15
+ // Governed projections retain the specialist query's existing output contract.
16
+ const QUERY_PROFILE = 'lifecycle';
13
17
 
14
18
  function read(relativePath) {
15
19
  return readFileSync(path.join(ROOT, relativePath), "utf8");
@@ -68,7 +72,157 @@ export function queryLifecycleContext(options = {}) {
68
72
  return withValidationPhase({ root: ROOT, purpose: "lifecycle-context-query", readOnly: true }, () => querySnapshot(options));
69
73
  }
70
74
 
71
- function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
75
+ // Availability is an observation, not permission to install, invoke or approve.
76
+ export function inspectWorkUnitSkills({ root = ROOT, registry, route, agentRuntime, when = [] }) {
77
+ const issues = [], missing = [], required = new Set();
78
+ const report = (code, skill, ref, message) => issues.push({ code, skill: skill ?? null, ref, message });
79
+ const definitions = [...(registry.skills ?? []), ...(registry.external_skills ?? [])];
80
+ const externalIds = new Set((registry.external_skills ?? []).map(skill => skill.id));
81
+ const aliases = new Map(definitions.flatMap(skill => (skill.aliases ?? []).map(alias => [alias, skill.id])));
82
+ const roots = registry.agent_runtime_roots ?? registry.instance_distribution?.projection_roots ?? {};
83
+ const dependencies = registry.skill_dependencies ?? {};
84
+ function visit(requested) {
85
+ const id = aliases.get(requested) ?? requested;
86
+ if (required.has(id)) return;
87
+ required.add(id);
88
+ const definition = definitions.find(skill => skill.id === id);
89
+ if (OBSOLETE.has(id) || definition?.maturity === 'deprecated') {
90
+ report('skill-retired', id, '.template-spec/agents/skill-migrations.md',
91
+ definition?.replacement_skill ? '技能已停止新用法;请使用 ' + definition.replacement_skill : '技能已退役;按迁移说明重新路由');
92
+ return;
93
+ }
94
+ if (!definition || (!externalIds.has(id) && !/^[a-z][a-z0-9-]+$/.test(id))) {
95
+ report('skill-unknown', id, SKILL_REGISTRY_REF, '路由使用未登记的技能');
96
+ return;
97
+ }
98
+ if (externalIds.has(id)) {
99
+ report('external-skill-required', id, SKILL_REGISTRY_REF, '外部技能须核验实际运行时能力,不能通过共享技能补装代替');
100
+ return;
101
+ }
102
+ for (const dependency of dependencies[id] ?? []) {
103
+ if (dependency.type === 'context-required' ||
104
+ (dependency.type === 'context-conditional' && when.includes(dependency.when))) visit(dependency.skill);
105
+ }
106
+ }
107
+ [
108
+ route?.primary_skill,
109
+ route?.native?.invocation_mode === 'reference' ? null : route?.native?.skill,
110
+ ...(route?.supporting_skills ?? []), ...(route?.skills ?? []),
111
+ ].filter(Boolean).forEach(visit);
112
+ function readJson(ref) {
113
+ const file = path.join(root, ref);
114
+ if (!existsSync(file)) return null;
115
+ const value = JSON.parse(readFileSync(file, 'utf8'));
116
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new TypeError(ref + ' 必须是 JSON 对象');
117
+ return value;
118
+ }
119
+ const lock = readJson('skills-lock.json');
120
+ const metadata = readJson('.yss-template.json');
121
+ const selected = metadata?.distribution?.mode === 'selected' ? metadata.distribution : null;
122
+ const registeredRuntimes = selected?.runtimes ??
123
+ Object.keys(roots).filter(runtime => lock?.projectionRoots?.includes(roots[runtime]));
124
+ if (!agentRuntime && registeredRuntimes.length === 1) agentRuntime = registeredRuntimes[0];
125
+ if (agentRuntime && !Object.hasOwn(roots, agentRuntime)) throw new TypeError('未知 Agent 运行时: ' + agentRuntime);
126
+ if (!agentRuntime) report('runtime-required', null, '.yss-template.json', '请用 --agent-runtime 明确指定运行时;只在登记了唯一运行时时自动选择');
127
+ else if (!registeredRuntimes.includes(agentRuntime)) report('runtime-not-installed', null, '.yss-template.json', '所选运行时未登记;先核对运行时安装范围');
128
+ if (!lock?.skills?.shared || !Array.isArray(lock.projectionRoots)) report('skill-lock-invalid', null, 'skills-lock.json', '技能锁缺失或结构不支持;先恢复锁文件或规划迁移');
129
+ if (selected && (!Array.isArray(selected.installedSkills) || !Array.isArray(selected.runtimes) ||
130
+ JSON.stringify([...selected.runtimes.map(runtime => roots[runtime])].sort()) !== JSON.stringify([...(lock?.projectionRoots ?? [])].sort()))) {
131
+ report('distribution-lock-drift', null, '.yss-template.json', '实例元数据与技能锁的运行时或安装清单不一致');
132
+ }
133
+ const inside = (file, directory) => file === directory || file.startsWith(directory + path.sep);
134
+ const realRoot = realpathSync(root);
135
+ function stat(file) {
136
+ // existsSync observes absence; lstat also identifies occupied dangling links.
137
+ existsSync(file);
138
+ return lstatSync(file, { throwIfNoEntry: false });
139
+ }
140
+ function checkedTreeHash(directory, canonical, projection = false) {
141
+ const info = stat(directory);
142
+ if (!info) return null;
143
+ const resolved = realpathSync(directory);
144
+ if (!inside(resolved, realRoot) || (projection && info.isSymbolicLink() && resolved !== realpathSync(canonical)) ||
145
+ (!projection && info.isSymbolicLink()) || (!info.isDirectory() && !info.isSymbolicLink())) {
146
+ throw new TypeError('技能目录或投影链接无效: ' + directory);
147
+ }
148
+ const files = [];
149
+ function walk(current, prefix = '') {
150
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
151
+ if (entry.name === '.DS_Store' || entry.name === '__pycache__' || /\.(iml|pyc|pyo)$/.test(entry.name)) continue;
152
+ const file = path.join(current, entry.name), ref = prefix ? prefix + '/' + entry.name : entry.name;
153
+ const entryInfo = stat(file), real = realpathSync(file);
154
+ if (!inside(real, resolved)) throw new TypeError('技能文件链接越界: ' + ref);
155
+ if (entryInfo.isDirectory()) walk(file, ref);
156
+ else if (entryInfo.isFile() || entryInfo.isSymbolicLink()) files.push([ref, file]);
157
+ else throw new TypeError('技能包含不支持的文件类型: ' + ref);
158
+ }
159
+ }
160
+ walk(directory);
161
+ const digest = createHash('sha256');
162
+ for (const [ref, file] of files.sort(([left], [right]) => left.localeCompare(right))) {
163
+ const bytes = readFileSync(file);
164
+ const normalized = bytes.includes(0) ? bytes : Buffer.from(bytes.toString('utf8').replaceAll('\r\n', '\n'));
165
+ digest.update(ref).update('\0').update(normalized).update('\0');
166
+ }
167
+ return digest.digest('hex');
168
+ }
169
+ for (const id of [...required].sort()) {
170
+ if (issues.some(issue => issue.skill === id)) continue;
171
+ const canonicalRef = '.agents/skills/' + id;
172
+ const canonical = path.join(root, canonicalRef);
173
+ const record = lock?.skills?.shared?.[id];
174
+ const declared = selected?.installedSkills?.includes(id);
175
+ if (!stat(canonical)) {
176
+ const managed = Object.keys(metadata?.managedFiles ?? {}).some(ref => ref.startsWith(canonicalRef + '/'));
177
+ if (record || declared || managed) report('managed-skill-missing', id, canonicalRef, '已登记或受管技能文件丢失;先核对 sync 计划,不能当作未安装补装');
178
+ else {
179
+ const occupied = Object.entries(roots).find(([runtime, ref]) => registeredRuntimes.includes(runtime) && stat(path.join(root, ref, id)));
180
+ if (occupied) report('skill-path-conflict', id, occupied[1] + '/' + id, '同名投影路径已存在但未登记,拒绝覆盖');
181
+ else missing.push(id);
182
+ }
183
+ continue;
184
+ }
185
+ if (!record) {
186
+ report('skill-path-conflict', id, canonicalRef, '同名技能路径存在但未登记,拒绝覆盖');
187
+ continue;
188
+ }
189
+ if (selected && !declared) report('distribution-lock-drift', id, '.yss-template.json', '技能锁与实例安装清单不一致');
190
+ try {
191
+ const hash = checkedTreeHash(canonical, canonical);
192
+ if (!existsSync(path.join(canonical, 'SKILL.md'))) report('managed-skill-missing', id, canonicalRef + '/SKILL.md', '已登记技能缺少入口文件');
193
+ if (hash !== record.effectiveHash) report('skill-hash-drift', id, canonicalRef, 'canonical 技能内容与锁定有效哈希不一致');
194
+ const projectionRef = agentRuntime && roots[agentRuntime];
195
+ if (projectionRef) {
196
+ if (!lock.projectionRoots.includes(projectionRef) || !record.targets?.includes(projectionRef) || !record.targets?.includes('.agents/skills')) {
197
+ report('projection-lock-drift', id, 'skills-lock.json', '所选运行时投影目标与技能锁不一致');
198
+ }
199
+ const projection = path.join(root, projectionRef, id);
200
+ if (checkedTreeHash(projection, canonical, true) !== hash) report('projection-drift', id, projectionRef + '/' + id, '运行时投影缺失或与 canonical 内容不一致');
201
+ }
202
+ } catch (error) {
203
+ report('skill-path-invalid', id, canonicalRef, error.message);
204
+ }
205
+ }
206
+ const canEnsure = metadata?.metadataSchemaVersion === 3 && selected && metadata.templateName === 'create-yss-spec';
207
+ const commandArgs = ['create-yss-spec', 'skills', 'ensure', ...missing.sort(), ...when.flatMap(trigger => ['--when', trigger]), '--target-dir', root];
208
+ const quote = value => /^[a-zA-Z0-9_./:-]+$/.test(value) ? value : "'" + value.replaceAll("'", "'\\''") + "'";
209
+ const command = mode => [...commandArgs, mode].map(quote).join(' ');
210
+ return {
211
+ read_only: true, execution_allowed: false, agent_runtime: agentRuntime ?? null,
212
+ required_skills: [...required].sort(), missing_skills: missing,
213
+ status: issues.length ? 'blocked' : missing.length ? 'missing' : 'ready',
214
+ issues,
215
+ remediation: missing.length && !issues.length ? canEnsure
216
+ ? { plan_command: command('--plan'), apply_command: command('--apply'), authorization: 'existing-task-scope-required', recheck_required: true }
217
+ : { plan_command: null, apply_command: null, message: '此实例没有可用的 v3 按需补装元数据;按本家族 CLI 规划同步或迁移,保持现有分发模式' }
218
+ : null,
219
+ };
220
+ }
221
+
222
+ function querySnapshot({ mode, stageId, workUnitId, include = [], checkSkills = false, agentRuntime, when = [] } = {}) {
223
+ if (checkSkills && !workUnitId) throw new TypeError('--check-skills 必须指定 --work-unit');
224
+ if (!checkSkills && (agentRuntime !== undefined || when.length)) throw new TypeError('--agent-runtime 和 --when 必须与 --check-skills 一起使用');
225
+ if (!Array.isArray(when) || when.some(trigger => typeof trigger !== 'string' || !/^[a-z][a-z0-9-]+$/.test(trigger))) throw new TypeError('--when 必须是有效的条件触发项');
72
226
  if (!mode && !stageId && !workUnitId && include.length === 0) {
73
227
  throw new TypeError("至少提供 --mode、--stage、--work-unit 或 --include 之一");
74
228
  }
@@ -77,15 +231,15 @@ function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
77
231
  if (identity.schema_version !== 1 || !["template-source", "project-instance"].includes(identity.repository_mode)) {
78
232
  throw new TypeError("仓库身份或版本无效");
79
233
  }
80
- const scope = loadExecutionScope();
81
- if (workUnitId) assertScopeWorkUnit(workUnitId, { readOnly: true });
234
+ const scope = QUERY_PROFILE === 'lifecycle' ? loadExecutionScope() : null;
235
+ if (workUnitId && QUERY_PROFILE === 'lifecycle') assertScopeWorkUnit(workUnitId, { readOnly: true });
82
236
  const lifecycle = validateRegistry(loadRegistry());
83
237
  const orchestration = loadYaml(ORCHESTRATION_CONTRACT_REF, "生命周期编排合同");
84
238
  const skillRegistry = loadSkillRegistry();
85
239
  const planUnit = ['work-unit.plan-opportunity', 'work-unit.plan-requirements', 'work-unit.domain-strategy-design', 'work-unit.stage-decision', 'work-unit.spec-synthesis'].includes(workUnitId);
86
240
  const loadPlan = ['stage.plan', 'stage.spec-architecture'].includes(stageId) || planUnit;
87
241
  stageId ??= planUnit ? 'stage.plan' : undefined;
88
- include = [...include, 'gate_consolidation'];
242
+ if (QUERY_PROFILE === 'lifecycle') include = [...include, 'gate_consolidation'];
89
243
  if (loadPlan) include = [...include, 'planning', 'grill_exit'];
90
244
  const stage = selectById(lifecycle.stages, stageId, "阶段");
91
245
  const workUnit = selectById(lifecycle.work_units, workUnitId, "工作单元");
@@ -97,19 +251,19 @@ function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
97
251
  }
98
252
 
99
253
  const route = workUnitId ? orchestration.work_unit_routes?.[workUnitId] ?? null : null;
100
- if (workUnit?.scope === "project-instance" && workUnit.id !== "work-unit.entry-triage" && !route) {
254
+ if (QUERY_PROFILE === 'lifecycle' && workUnit?.scope === "project-instance" && workUnit.id !== "work-unit.entry-triage" && !route) {
101
255
  throw new TypeError(`项目工作单元缺少执行路由: ${workUnit.id}`);
102
256
  }
103
- if (workUnit?.scope === "project-instance" && workUnit.id !== "work-unit.entry-triage" && !Object.hasOwn(orchestration.transition_graph?.routes ?? {}, workUnit.id)) {
257
+ if (QUERY_PROFILE === 'lifecycle' && workUnit?.scope === "project-instance" && workUnit.id !== "work-unit.entry-triage" && !Object.hasOwn(orchestration.transition_graph?.routes ?? {}, workUnit.id)) {
104
258
  throw new TypeError(`项目工作单元缺少流转路由: ${workUnit.id}`);
105
259
  }
106
260
  const gates = lifecycle.gates.filter((gate) => gate.stage === stageId || (loadPlan && gate.stage === 'stage.plan'));
107
- const checks = lifecycle.checks.filter(check => check.stage === stageId || gates.some(gate => gate.requires_checks?.includes(check.id)));
261
+ const checks = QUERY_PROFILE === 'lifecycle' ? lifecycle.checks.filter(check => check.stage === stageId || gates.some(gate => gate.requires_checks?.includes(check.id))) : [];
108
262
  const artifacts = lifecycle.artifacts.filter((artifact) => artifact.stage === stageId || (loadPlan && artifact.stage === 'stage.plan'));
109
263
  const evidenceIds = new Set([...gates, ...checks].flatMap((gate) => gate.evidence ?? []));
110
264
  const selected = Object.fromEntries(normalizedIncludes.map((key) => [key, orchestration[key]]));
111
265
  const transition = workUnitId ? {
112
- next: scopedNextRoutes(workUnitId, orchestration.transition_graph?.routes?.[workUnitId] ?? []),
266
+ next: QUERY_PROFILE === 'lifecycle' ? scopedNextRoutes(workUnitId, orchestration.transition_graph?.routes?.[workUnitId] ?? []) : orchestration.transition_graph?.routes?.[workUnitId] ?? [],
113
267
  forbidden_shortcuts: (orchestration.transition_graph?.forbidden_shortcuts ?? [])
114
268
  .filter((edge) => edge.from === workUnitId || edge.to === workUnitId),
115
269
  } : null;
@@ -143,10 +297,10 @@ function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
143
297
  lifecycle: {
144
298
  artifacts,
145
299
  evidence: lifecycle.evidence.filter((item) => evidenceIds.has(item.id)).map(({ public_description, ...item }) => ({
146
- ...item, description: public_description ?? item.description
300
+ ...item, ...(QUERY_PROFILE === 'lifecycle' ? { description: public_description ?? item.description } : public_description ? { public_description } : {})
147
301
  })),
148
302
  gates,
149
- checks,
303
+ ...(QUERY_PROFILE === 'lifecycle' ? { checks } : {}),
150
304
  stage,
151
305
  work_unit: workUnit,
152
306
  },
@@ -160,12 +314,19 @@ function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
160
314
  },
161
315
  skills: selectedSkills(route, skillRegistry),
162
316
  };
317
+ if (checkSkills) {
318
+ result.query.check_skills = true;
319
+ result.query.when = [...new Set(when)].sort();
320
+ result.skill_readiness = inspectWorkUnitSkills({ registry: skillRegistry, route, agentRuntime, when: result.query.when });
321
+ }
322
+ if (QUERY_PROFILE === 'lifecycle') {
163
323
  const presenter = loadLifecyclePresenter(ROOT);
164
324
  result.presentation = { read_only: true, execution_allowed: false, approval_validity: 'not-checked',
165
325
  names: presenter.catalog(result.lifecycle), sources: presenter.sources, warnings: presenter.warnings };
166
326
  // Include role and transition references from the requested contract subtrees as well.
167
327
  Object.assign(result.presentation.names, presenter.catalog(result.execution));
168
328
  Object.assign(result.presentation.names, presenter.catalog(presenter.roleIds));
329
+ }
169
330
  result.references = [...collectPathReferences(result), LIFECYCLE_REGISTRY_REF, ORCHESTRATION_CONTRACT_REF, SKILL_REGISTRY_REF]
170
331
  .filter((value, index, all) => all.indexOf(value) === index)
171
332
  .sort();
@@ -1,15 +1,19 @@
1
- import { readFileSync } from './validation-phase.mjs';
1
+ import { readFileSync, withValidationPhase } from './validation-phase.mjs';
2
2
  import { createHash } from 'node:crypto';
3
3
  import path from 'node:path';
4
4
  import { parseDocument } from '../vendor/yaml.mjs';
5
5
  import { loadRegistry, ROOT } from './lifecycle-registry.mjs';
6
6
  import { loadDigitalHumanRoles, countersignRuleForGate } from './digital-human-roles.mjs';
7
- import { validateApprovalRecord, loadApprovalRecord } from './approval-record.mjs';
7
+ import {loadApprovalRecord} from './approval-record-io.mjs';
8
+ import {assertCurrentApproval, approvalExpectationFromState} from './approval-current.mjs';
8
9
 
9
10
  const fail = message => { throw new TypeError(`lifecycle-control-blocked: ${message}`); };
10
11
 
11
12
  // Checks retain their own evidence and independent review; only the aggregate requests a user decision.
12
- export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRegistry(), rolesDoc = loadDigitalHumanRoles() } = {}) {
13
+ export function assertGateChecks(gateId, state, options = {}) {
14
+ return withValidationPhase({root:options.root || ROOT,purpose:'current-gate-checks',readOnly:true},()=>validateGateChecks(gateId,state,options));
15
+ }
16
+ function validateGateChecks(gateId, state, { root = ROOT, registry = loadRegistry(), rolesDoc = loadDigitalHumanRoles() } = {}) {
13
17
  const gate = registry.gates.find(item => item.id === gateId);
14
18
  if (!gate) fail(`未知或已退役门禁: ${gateId}`);
15
19
  const controls = new Map(registry.checks.map(item => [item.id, item]));
@@ -47,12 +51,7 @@ export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRe
47
51
  if (rule) {
48
52
  if (!refs.has(item.approval_ref) || !refs.has(item.subject_ref)) fail(`${id} 未绑定审查与资产`);
49
53
  const record = loadApprovalRecord(path.resolve(root, item.approval_ref), id);
50
- if (record.gate_id !== id || record.subject_ref !== item.subject_ref) fail(`${id} 审查对象不匹配`);
51
- if (!item.approval_scope?.length || JSON.stringify([...item.approval_scope].sort()) !== JSON.stringify([...(record.approval_scope || [])].sort())) fail(`${id} 审查范围不匹配`);
52
- const subjectDigest = createHash('sha256').update(readFileSync(path.resolve(root, item.subject_ref))).digest('hex');
53
- if (record.subject_digest !== subjectDigest) fail(`${id} 审查资产摘要不匹配`);
54
- validateApprovalRecord(record, { rolesDoc, root, requireApproved: true });
55
- if (!record.drafter_principal_ref || record.drafter_principal_ref === record.principal_ref) fail(`${id} 缺少独立审查身份或起草者自签`);
54
+ assertCurrentApproval(record,approvalExpectationFromState(id,item,{root}),{rolesDoc,registry,root});
56
55
  }
57
56
  }
58
57
  for (const id of gate.requires_checks || []) check(id);
@@ -66,16 +65,7 @@ export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRe
66
65
  if (approvalRequired) {
67
66
  if (!refs.has(item.approval_ref) || !refs.has(item.subject_ref)) fail(`${gateId} 缺少已绑定批准记录和审阅包`);
68
67
  const record = loadApprovalRecord(path.resolve(root, item.approval_ref), gateId);
69
- if (!record.drafter_principal_ref || record.drafter_principal_ref === record.principal_ref) fail(`${gateId} 缺少独立审查身份或起草者自签`);
70
- const bytes = readFileSync(path.resolve(root, item.subject_ref));
71
- if (record.subject_ref !== item.subject_ref || record.subject_digest !== createHash('sha256').update(bytes).digest('hex')) fail(`${gateId} 批准依据过期`);
72
- const document = parseDocument(bytes.toString(), { uniqueKeys: true, maxAliasCount: 0 });
73
- if (document.errors.length) fail(`${gateId} 审阅包不可解析`);
74
- const review = document.toJS({ maxAliasCount: 0 });
75
- if (review?.gate_id !== gateId || !Array.isArray(review.basis)) fail(`${gateId} 审阅包身份或依据缺失`);
76
- for (const asset of item.basis.filter(asset => ![item.approval_ref, item.subject_ref].includes(asset.ref))) {
77
- if (!review.basis.some(bound => bound.ref === asset.ref && bound.digest === asset.digest)) fail(`${gateId} 批准范围未覆盖证据: ${asset.ref}`);
78
- }
68
+ assertCurrentApproval(record,approvalExpectationFromState(gateId,item,{root}),{rolesDoc,registry,root});
79
69
  }
80
70
  // Bind the aggregate approval to the exact check evidence it covers.
81
71
  for (const id of seen) for (const asset of state.checks[id].basis) {
@@ -64,13 +64,18 @@ export function loadLifecyclePresenter(root) {
64
64
  export function renderLifecycleStatus(result) {
65
65
  const view = result.presentation;
66
66
  if (!view) throw Error('缺少状态阅读信息');
67
+ const ownerNote = issue => ({'work-unit': '(工作单元负责人;问题责任方待确认)', 'checkpoint-pause': '(暂停记录责任方;问题责任方待确认)'}[issue.owner_scope] ?? '');
67
68
  return [
68
69
  `当前阶段:${view.stage}。登记状态:${view.checkpoint_status}。`,
70
+ `下一阶段(路由目标):${view.next_stage ?? '待核验'}。${view.next_stage_reason ?? '阶段归属未核验;不代表已批准或可进入'}。`,
69
71
  `当前阻塞:${view.blockers.length ? view.blockers.join(';') : '未登记阻塞;完整就绪与批准仍待核验'}。`,
72
+ ...(view.issues ?? []).map((issue, index) => `${index + 1}. ${issue.severity === 'error' ? '阻塞' : '待核验问题'}:${issue.message}\n 负责人:${issue.owner}${ownerNote(issue)};来源:${issue.source_ref ?? '未登记'}\n 处理:${issue.recovery}`),
70
73
  `负责人:${view.owner}。`,
71
74
  `下一项工作:${view.work_unit}。`,
72
75
  ...(view.expected_output ? [`预期产出:${view.expected_output}`] : []),
73
76
  `下一动作:${view.next_action}。`,
77
+ ...(view.pending_verification?.length ? [`待核验:${view.pending_verification.map(item => item.reason).join(';')}。`] : []),
78
+ ...(view.continue_conditions?.length ? [`继续条件:${view.continue_conditions.join(';')}。`] : []),
74
79
  ...view.warnings,
75
80
  '本次为只读查询,未核验完整批准或执行授权。',
76
81
  ].join('\n') + '\n';
@@ -15,50 +15,97 @@ function parse(bytes) {
15
15
  return document.toJS({ maxAliasCount: 0 });
16
16
  }
17
17
  function source(root, ref) {
18
- const bytes = readFileSync(safeTrackingPath(root, ref));
19
- return { value: parse(bytes), digest: sha(bytes) };
18
+ try {
19
+ const bytes = readFileSync(safeTrackingPath(root, ref));
20
+ return { value: parse(bytes), digest: sha(bytes) };
21
+ } catch (error) {
22
+ error.lifecycle_input_ref ??= ref;
23
+ throw error;
24
+ }
20
25
  }
21
26
 
22
27
  /** Read-only projection; checkpoint, registry and orchestration remain authoritative. */
23
28
  export function lifecycleStatus({ root, checkpointRef, taskPackageRef }) {
24
29
  if (!root || !checkpointRef) throw new TypeError('root and checkpoint are required');
25
30
  root = path.resolve(root);
26
- const identity = source(root, 'yss-project.yaml').value;
27
- if (identity.schema_version !== 1 || identity.repository_mode !== 'project-instance') throw new TypeError('生命周期状态仅适用于 project-instance');
31
+ let identity;
32
+ try {
33
+ identity = source(root, 'yss-project.yaml').value;
34
+ if (identity.schema_version !== 1 || identity.repository_mode !== 'project-instance') throw new TypeError('生命周期状态仅适用于 project-instance');
35
+ } catch (error) {
36
+ error.lifecycle_input_ref ??= 'yss-project.yaml';
37
+ error.lifecycle_input_kind = identity?.schema_version === 1 && identity?.repository_mode === 'template-source' ? 'template-source' : 'manifest';
38
+ throw error;
39
+ }
28
40
  const registryRef = '.template-spec/process/lifecycle-registry.yaml';
29
41
  const contractRef = orchestrationRef(root);
30
42
  const checkpoint = source(root, checkpointRef), registry = source(root, registryRef), contract = source(root, contractRef);
31
43
  const value = checkpoint.value;
44
+ const registeredText = value => typeof value === 'string' && value.trim() ? value : null;
32
45
  if (value.schema_version !== 1 || value.repository_mode !== 'project-instance') throw new TypeError('checkpoint 身份或版本无效');
33
46
  const items = value.stage_tracking?.items ?? [];
34
47
  if (!Array.isArray(items)) throw new TypeError('阶段追踪 items 必须为数组');
35
48
  const activeItems = items.filter(item => item.work_unit === value.next_work_unit && item.progress !== 'cancelled');
36
- const owner = value.pause?.owner_or_authority ?? activeItems.find(item => item.progress !== 'completed')?.owner ?? '未登记';
49
+ const pauseOwner = registeredText(value.pause?.owner_or_authority);
50
+ const workUnitOwner = registeredText(activeItems.find(item => item.progress !== 'completed')?.owner);
51
+ const owner = pauseOwner ?? workUnitOwner ?? '未登记';
52
+ const defaultOwnerScope = pauseOwner ? 'checkpoint-pause' : workUnitOwner ? 'work-unit' : 'not-recorded';
37
53
  const diagnostics = [], verification_scope = [];
38
54
  const check = (id, status, refs, reason) => verification_scope.push({ id, status, refs, reason });
39
- const issue = (code, message, source_ref, recovery, severity = 'error') => diagnostics.push({ code, message, source_ref, owner, recovery, severity });
55
+ const issue = (code, message, source_ref, recovery, severity = 'error', issueOwner = owner, ownerScope = defaultOwnerScope) => diagnostics.push({ code, message, source_ref, owner: issueOwner, owner_scope: issueOwner === '未登记' ? 'not-recorded' : ownerScope, recovery, severity });
40
56
  if (!Object.hasOwn(value, 'blockers')) {
41
57
  issue('registered-blockers-missing', 'checkpoint 缺少 blockers;不能据此判定无已登记阻塞', checkpointRef, '核对原始状态并补齐真实阻塞记录后重验');
42
58
  } else if (!Array.isArray(value.blockers)) {
43
59
  issue('registered-blockers-invalid', 'checkpoint.blockers 必须为数组;当前登记不可核验', checkpointRef, '修复阻塞记录类型,保留原有阻塞内容后重验');
44
60
  } else {
45
61
  for (const item of value.blockers) {
46
- issue('registered-blocker', typeof item === 'string' ? item : JSON.stringify(item), checkpointRef, '按原阻塞证据处理并复验');
62
+ const record = item && typeof item === 'object' && !Array.isArray(item) ? item : {};
63
+ issue('registered-blocker', registeredText(item) ?? registeredText(record.message) ?? registeredText(record.reason) ?? '已登记阻塞,具体问题尚未说明', registeredText(record.source_ref) ?? checkpointRef, registeredText(record.recovery) ?? '核对原阻塞记录、责任方和证据,明确处理动作后复验', 'error', registeredText(record.owner) ?? owner, registeredText(record.owner) ? 'issue' : defaultOwnerScope);
47
64
  }
48
65
  }
49
66
  check('registered-blockers', diagnostics.length ? 'failed' : 'passed', [checkpointRef], '仅读取已登记阻塞,不代表完整就绪');
50
67
  const stage = registry.value.stages?.find(item => item.id === value.stage);
51
68
  const workUnit = registry.value.work_units?.find(item => item.id === value.next_work_unit);
69
+ // Only explicit recorded associations identify a target stage. Stage order is not a route.
70
+ const stageAssociations = workUnit ? [
71
+ ...(registeredText(workUnit?.stage) ? [{stage: workUnit.stage, ref: registryRef}] : []),
72
+ ...activeItems.filter(item => registeredText(item.stage)).map(item => ({stage: item.stage, ref: checkpointRef})),
73
+ ] : [];
74
+ const stageIds = [...new Set(stageAssociations.map(item => item.stage))];
75
+ const nextStage = stageIds.length === 1 && registry.value.stages?.some(item => item.id === stageIds[0]) ? stageIds[0] : null;
76
+ const nextStageReason = !value.next_work_unit ? '未登记下一工作单元;需核验当前阶段验收与终点,不能据此判定完成'
77
+ : stageIds.length > 1 ? '下一工作单元的已登记阶段归属存在冲突;核对权威记录后重验'
78
+ : stageIds.length === 1 && !nextStage ? '下一工作单元的阶段归属未在注册表中识别;核对当前来源后重验'
79
+ : !nextStage ? '下一工作单元尚未登记阶段归属;核验当前路由与阶段追踪后确认'
80
+ : nextStage === value.stage ? '下一工作单元仍在当前阶段,先完成当前单元并验收,再核验后续流转;不代表已批准或可进入'
81
+ : '来自下一工作单元的已登记阶段归属,仅为路由目标,不代表已批准或可进入';
82
+ check('next-stage-association', nextStage ? 'passed' : 'not-checked', [...new Set(stageAssociations.map(item => item.ref))], nextStageReason);
83
+ if (stageIds.length > 1 || (stageIds.length === 1 && !nextStage)) issue('next-stage-unverifiable', nextStageReason, checkpointRef, '核对下一工作单元的已登记阶段归属并执行适用预检,不按阶段顺序猜目标', 'warning');
52
84
  if (!stage) issue('unknown-stage', `未知阶段: ${value.stage}`, registryRef, '按注册表核对当前阶段');
53
85
  if (value.next_work_unit && !workUnit) issue('unknown-work-unit', `未知下一工作单元: ${value.next_work_unit}`, registryRef, '按注册表核对下一工作单元');
54
86
  if (workUnit && workUnit.id !== 'work-unit.entry-triage' && !contract.value.work_unit_routes?.[workUnit.id]) issue('missing-route', `缺少执行路由: ${workUnit.id}`, contractRef, '修复当前合同路由后重验');
55
87
  check('stage-and-route', diagnostics.some(x => ['unknown-stage', 'unknown-work-unit', 'missing-route'].includes(x.code)) ? 'failed' : 'passed', [registryRef, contractRef], '仅检查身份与路由存在,不计算完整 frontier');
56
88
  if (value.context_reconciliation?.status === 'blocked') issue('context-blocked', '术语对账受阻', checkpointRef, '修复词汇对账并执行适用校验');
57
89
  check('context-reconciliation', value.context_reconciliation?.status === 'blocked' ? 'failed' : 'not-checked', [value.context_reconciliation?.ref].filter(Boolean), '读取登记状态;当前对账内容和摘要仍须由原验证器核验');
58
- for (const [id, gate] of Object.entries(value.gates ?? {})) {
59
- if (['blocked', 'stale'].includes(gate?.status)) issue('gate-blocked', `${id}: ${gate.status}`, checkpointRef, '核对受影响依据和当前批准');
90
+ const gateNames = {blocked: '受阻', stale: '依据已过期', pending: '等待处理', failed: '未通过', 'ready-for-human': '等待会签', 'not-evaluated': '尚未评估'};
91
+ const gates = value.gates && typeof value.gates === 'object' && !Array.isArray(value.gates) ? Object.entries(value.gates) : [];
92
+ if (!Object.hasOwn(value, 'gates') || !value.gates || typeof value.gates !== 'object' || Array.isArray(value.gates)) issue('gates-unverifiable', '门禁登记缺失或格式不可核验', checkpointRef, '核对原始门禁记录并执行正式预检', 'warning');
93
+ for (const [id, gate] of gates) {
94
+ const status = gateNames[gate?.status];
95
+ const hardBlocked = ['blocked', 'stale'].includes(gate?.status);
96
+ const failed = hardBlocked || (['pending', 'failed', 'ready-for-human', 'not-evaluated'].includes(gate?.status) && gate?.applicable === true);
97
+ if (status) {
98
+ const blocked = hardBlocked || (failed && gate?.applicable !== false);
99
+ const reason = registeredText(gate?.reason);
100
+ const applicability = hardBlocked && gate?.applicable === false ? ';登记状态与适用性标记冲突,需正式预检' : blocked ? '' : ';适用性与当前处理要求待核验';
101
+ const recovery = registeredText(gate?.recovery) ?? (['pending', 'ready-for-human'].includes(gate?.status) ? '核对适用范围、当前资产和已登记责任方;取得所需真实决定或有效延续后复验' : '核对适用范围、失败原因或过期依据,修复并重验受影响检查与批准');
102
+ issue(blocked ? 'gate-blocked' : 'gate-unverified', `${id}:${status}${reason ? `;${reason}` : ''}${applicability}`, checkpointRef, hardBlocked && gate?.applicable === false ? `${recovery};保留阻断状态,核对冲突登记并执行正式预检` : recovery, blocked ? 'error' : 'warning', registeredText(gate?.owner) ?? owner, registeredText(gate?.owner) ? 'issue' : defaultOwnerScope);
103
+ } else if (!['approved', 'not-applicable'].includes(gate?.status)) {
104
+ issue('gate-unverified', `${id}:登记状态未识别,适用性与处理要求待核验`, checkpointRef, '保留原记录,核对门禁状态与适用性后执行正式预检', 'warning', registeredText(gate?.owner) ?? owner, registeredText(gate?.owner) ? 'issue' : defaultOwnerScope);
105
+ }
60
106
  }
61
- check('registered-gates', diagnostics.some(x => x.code === 'gate-blocked') ? 'failed' : 'passed', [checkpointRef], '仅检查登记的 blocked/stale 标志');
107
+ const gateDiagnostics = diagnostics.filter(x => ['gate-blocked', 'gate-unverified', 'gates-unverifiable'].includes(x.code));
108
+ check('registered-gates', gateDiagnostics.some(x => x.severity === 'error') ? 'failed' : gateDiagnostics.length || !gates.length ? 'not-checked' : 'passed', [checkpointRef], '仅读取已登记状态;适用性未登记、待处理或记录缺失时不能判定门禁通过;不核验完整批准');
62
109
  const evidenceRefs = [value.context_reconciliation?.ref, ...Object.values(value.artifacts ?? {}).filter(item => item?.status === 'approved').map(item => item.ref)].filter(Boolean);
63
110
  for (const ref of evidenceRefs) {
64
111
  try { readFileSync(safeTrackingPath(root, ref)); }
@@ -149,17 +196,21 @@ export function lifecycleStatus({ root, checkpointRef, taskPackageRef }) {
149
196
  const presentation = {
150
197
  read_only: true, execution_allowed: false, approval_validity: 'not-checked',
151
198
  stage: value.stage ? presenter.label(value.stage, {trace: false}) : '未登记',
199
+ next_stage: nextStage ? presenter.label(nextStage, {trace: false}) : '待核验', next_stage_reason: readable(nextStageReason),
152
200
  checkpoint_status: Object.hasOwn(statusNames, value.status) ? statusNames[value.status] : `未识别状态(${value.status ?? '未登记'})`,
153
201
  work_unit: value.next_work_unit ? presenter.label(value.next_work_unit, {trace: false}) : '未登记',
154
202
  owner: presenter.text(owner, {trace: false}), blockers: blockers.map(readable),
203
+ issues: diagnostics.map(item => ({code: item.code, severity: item.severity, message: readable(item.message), source_ref: item.source_ref, owner: presenter.text(item.owner, {trace: false}), owner_scope: item.owner_scope, recovery: readable(item.recovery)})),
204
+ pending_verification: verification_scope.filter(item => !['passed', 'failed'].includes(item.status)).map(item => ({id: item.id, reason: readable(item.reason), refs: item.refs})),
205
+ continue_conditions: [...(registeredText(value.pause?.resume_condition) ? [readable(value.pause.resume_condition)] : []), ...next_step.prerequisites.map(readable), ...(blockers.length ? ['逐项处理当前阻塞,并由适用验证器确认恢复条件满足'] : []), '由主控验收当前证据并核验授权后决定继续或重新路由'],
155
206
  expected_output: workUnit ? readable(workUnit.public_output ?? workUnit.output ?? '产出说明未登记') : null,
156
207
  next_action: readable(next_action), sources: presenter.sources, warnings: presenter.warnings,
157
- names: presenter.catalog({stage: value.stage, work_unit: value.next_work_unit, owner, gates: value.gates, artifacts: value.artifacts}),
208
+ names: presenter.catalog({stage: value.stage, next_stage: nextStage, work_unit: value.next_work_unit, owner, gates: value.gates, artifacts: value.artifacts}),
158
209
  };
159
210
  return {
160
211
  presentation,
161
212
  decomposition: {business, implementation: {status:implementationArtifact?'recorded':'not-recorded',recorded_status:implementationArtifact?.status??null,ref:implementationArtifact?.ref??null,coverage:implementationCoverage}, readiness:{status:'not-evaluated',reason:'阶段工作完成不替代批准与实现就绪校验'}},
162
- schema_version: 1, read_only: true, stage: value.stage, checkpoint_status: value.status,
213
+ schema_version: 1, read_only: true, stage: value.stage, next_stage: nextStage, next_stage_reason: nextStageReason, next_stage_source_refs: [...new Set(stageAssociations.map(item => item.ref))], checkpoint_status: value.status,
163
214
  work_unit: value.next_work_unit ?? null, owner, blockers, next_action,
164
215
  execution_authorization: 'not-evaluated', verification_scope, diagnostics, next_step, recovery,
165
216
  reading_views: checkReadingViews(root,checkpointRef),
@@ -1,3 +1,4 @@
1
+ import {approvalExpectationForBoundAsset} from './approval-consumption.mjs';
1
2
  import { assertBusinessApprovalBasis } from './business-ticket-lifecycle.mjs';
2
3
  import { assertBusinessTicketTransition, assertImplementationTicket } from './business-tickets.mjs';
3
4
  import {assertReadingTransition} from './reading-view-bundle.mjs';
@@ -233,7 +234,7 @@ function backendDesignPrerequisitesReady(prerequisites, exists, root, projectId)
233
234
  ? prerequisites.engineering_contract_approval_ref
234
235
  : path.resolve(root, prerequisites.engineering_contract_approval_ref);
235
236
  const approval = loadApprovalRecord(approvalFile, 'gate.engineering-contract-approved');
236
- validateApprovalRecord(approval, { requireApproved: true, root });
237
+ validateApprovalRecord(approval, { requireApproved: true, root, expected: approvalExpectationForBoundAsset('gate.engineering-contract-approved',prerequisites.technical_design,{root}) });
237
238
  if (approval.gate_id !== "gate.engineering-contract-approved" || !approval.approval_scope?.includes(projectId)) return false;
238
239
  if (!approvalHasBinding(approval, technical.expected) || !approvalHasBinding(approval, data.expected)) return false;
239
240
  if (!approvalHasBinding(approval, { id: api.decision.decision_id, version: api.decision.decision_version, digest: prerequisites.api_contract_decision.digest })) return false;
@@ -2,11 +2,11 @@ import { spawnSync } from "node:child_process";
2
2
  import { createHash } from "node:crypto";
3
3
  import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import path from "node:path";
5
+ import { resolveMaintenanceOutput, resolveMaintenanceLocation, maintenanceReference, resolveMaintenanceReference, resolveMaintenanceBundleFile } from './maintenance-storage.mjs';
5
6
  import { parseDocument, stringify } from "../vendor/yaml.mjs";
6
7
 
7
8
  const MAGIC = Buffer.from("YSS-WORKTREE-CANDIDATE-V1\0", "ascii");
8
9
  const MAX_BUFFER = 512 * 1024 * 1024;
9
- const MAINTENANCE_EVIDENCE_ROOT = ".template-source/evidence/maintenance";
10
10
  const CANDIDATE_FILES = ["candidate-manifest.yaml", "candidate.bin", "tracked.diff"];
11
11
 
12
12
  function fail(message) { throw new TypeError(message); }
@@ -25,15 +25,6 @@ function splitNull(buffer) {
25
25
  if (start < buffer.length) result.push(buffer.subarray(start));
26
26
  return result;
27
27
  }
28
- function normalizeRelative(value, label) {
29
- ensure(typeof value === "string" && value.trim(), `${label} 不能为空`);
30
- const normalized = value.replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/$/, "");
31
- ensure(normalized && !path.posix.isAbsolute(normalized) && path.posix.normalize(normalized) === normalized && normalized !== ".." && !normalized.startsWith("../"), `${label} 必须是规范的仓库内相对路径`);
32
- return normalized;
33
- }
34
- function isMaintenanceEvidencePath(value) {
35
- return value === MAINTENANCE_EVIDENCE_ROOT || value.startsWith(`${MAINTENANCE_EVIDENCE_ROOT}/`);
36
- }
37
28
  function readLength(buffer, offset, bytes, label) {
38
29
  ensure(offset + bytes <= buffer.length, `packed candidate 缺少 ${label}`);
39
30
  const value = bytes === 8 ? buffer.readBigUInt64BE(offset) : BigInt(buffer.readUInt32BE(offset));
@@ -43,21 +34,14 @@ function readLength(buffer, offset, bytes, label) {
43
34
 
44
35
  export function captureMaintenanceCandidate({ root, outputDir, baseRef = "HEAD", excludePaths = [] }) {
45
36
  const repositoryRoot = path.resolve(root);
46
- const outputPath = path.resolve(repositoryRoot, outputDir);
47
- const outputRelative = normalizeRelative(path.relative(repositoryRoot, outputPath).replaceAll(path.sep, "/"), "outputDir");
48
- ensure(isMaintenanceEvidencePath(outputRelative), `outputDir 必须位于 ${MAINTENANCE_EVIDENCE_ROOT}`);
37
+ const outputPath = resolveMaintenanceOutput(outputDir, { root: repositoryRoot });
38
+ const outputRelative = maintenanceReference(outputPath, { root: repositoryRoot });
49
39
  ensure(!existsSync(outputPath), "outputDir 必须不存在,禁止复用可能含残留文件的候选目录");
50
40
  ensure(Array.isArray(excludePaths), "excludePaths 必须是数组");
51
- const explicitExclusions = excludePaths.map((value) => normalizeRelative(value, "excludePaths"));
52
- for (const exclusion of explicitExclusions) ensure(isMaintenanceEvidencePath(exclusion), `excludePaths 只允许 ${MAINTENANCE_EVIDENCE_ROOT} 下的维护证据`);
53
- const exclusions = [...new Set([outputRelative, ...explicitExclusions])];
41
+ ensure(excludePaths.length === 0, "excludePaths 已退役;新候选必须完整捕获,维护材料请保存到仓外");
54
42
  const mergeBase = git(["merge-base", baseRef, "HEAD"], repositoryRoot).trim();
55
43
  const trackedDiff = git(["diff", "--no-ext-diff", "--binary", "--full-index", mergeBase], repositoryRoot, null);
56
44
  const rawPaths = splitNull(git(["ls-files", "-z", "--others", "--exclude-standard"], repositoryRoot, null))
57
- .filter((rawPath) => {
58
- const value = rawPath.toString();
59
- return !exclusions.some((exclusion) => value === exclusion || value.startsWith(`${exclusion}/`));
60
- })
61
45
  .sort(Buffer.compare);
62
46
  ensure(trackedDiff.length > 0 || rawPaths.length > 0, "维护候选不能为空");
63
47
 
@@ -81,11 +65,13 @@ export function captureMaintenanceCandidate({ root, outputDir, baseRef = "HEAD",
81
65
  }
82
66
  const stream = Buffer.concat(parts);
83
67
  const digest = createHash("sha256").update(stream).digest("hex");
84
- const streamRef = `${outputRelative}/candidate.bin`;
85
- const diffRef = `${outputRelative}/tracked.diff`;
68
+ const streamRef = 'candidate.bin';
69
+ const diffRef = 'tracked.diff';
86
70
  const manifestRef = `${outputRelative}/candidate-manifest.yaml`;
87
71
  const manifest = {
88
- schema_version: 1,
72
+ schema_version: 2,
73
+ reference_base: 'bundle',
74
+ workspace_id: resolveMaintenanceLocation({ root: repositoryRoot }).workspaceId,
89
75
  candidate_kind: "yss-worktree-candidate-v1",
90
76
  storage: "packed-stream",
91
77
  review_mode: "worktree",
@@ -99,7 +85,7 @@ export function captureMaintenanceCandidate({ root, outputDir, baseRef = "HEAD",
99
85
  untracked_diff_command: "packed in candidate.bin",
100
86
  untracked_files: untrackedFiles,
101
87
  untracked_path_bytes: untrackedPathBytes,
102
- excluded_paths: exclusions,
88
+ excluded_paths: [],
103
89
  snapshot_stream_ref: streamRef,
104
90
  tracked_diff_ref: diffRef,
105
91
  commit_list_command: `git log ${baseRef}..HEAD --oneline`
@@ -115,10 +101,10 @@ export function captureMaintenanceCandidate({ root, outputDir, baseRef = "HEAD",
115
101
  } finally {
116
102
  if (existsSync(stagingPath)) rmSync(stagingPath, { recursive: true, force: true });
117
103
  }
118
- return { candidate_digest: digest, manifest, manifest_ref: manifestRef, files: [manifestRef, streamRef, diffRef] };
104
+ return { candidate_digest: digest, manifest, manifest_ref: manifestRef, files: [manifestRef, `${outputRelative}/${streamRef}`, `${outputRelative}/${diffRef}`] };
119
105
  }
120
106
 
121
- export function inspectMaintenanceCandidate({ manifestPath }) {
107
+ export function inspectMaintenanceCandidate({ manifestPath, root: repositoryRoot = process.cwd() }) {
122
108
  const absoluteManifest = path.resolve(manifestPath);
123
109
  const document = parseDocument(readFileSync(absoluteManifest, "utf8"), { uniqueKeys: true });
124
110
  ensure(document.errors.length === 0, document.errors[0]?.message || "candidate manifest 无法解析");
@@ -126,10 +112,18 @@ export function inspectMaintenanceCandidate({ manifestPath }) {
126
112
  ensure(manifest.storage === "packed-stream", "只支持 packed-stream candidate");
127
113
  const candidateDir = path.dirname(absoluteManifest);
128
114
  ensure(JSON.stringify(readdirSync(candidateDir).sort()) === JSON.stringify([...CANDIDATE_FILES].sort()), `packed candidate 目录必须恰好包含 ${CANDIDATE_FILES.join("、")}`);
129
- const root = path.resolve(path.dirname(absoluteManifest), ...Array(manifest.candidate_snapshot_ref.split("/").length - 1).fill(".."));
130
- ensure(path.resolve(root, manifest.candidate_snapshot_ref) === absoluteManifest, "candidate_snapshot_ref 未绑定当前 manifest");
131
- const streamPath = path.resolve(root, manifest.snapshot_stream_ref);
132
- const diffPath = path.resolve(root, manifest.tracked_diff_ref);
115
+ ensure([1, 2].includes(manifest.schema_version), 'candidate manifest schema 不支持');
116
+ const external = manifest.schema_version === 2;
117
+ if (external) {
118
+ ensure(Array.isArray(manifest.excluded_paths) && manifest.excluded_paths.length === 0, 'v2 候选不允许旧档案排除白名单');
119
+ ensure(manifest.reference_base === 'bundle', 'candidate reference_base 必须为 bundle');
120
+ ensure(manifest.workspace_id === resolveMaintenanceLocation({ root: repositoryRoot }).workspaceId, '候选不属于当前工作区');
121
+ ensure(resolveMaintenanceReference(manifest.candidate_snapshot_ref, { root: repositoryRoot }) === absoluteManifest, 'candidate_snapshot_ref 未绑定当前 manifest');
122
+ }
123
+ const root = external ? candidateDir : path.resolve(candidateDir, ...Array(manifest.candidate_snapshot_ref.split('/').length - 1).fill('..'));
124
+ if (!external) ensure(path.resolve(root, manifest.candidate_snapshot_ref) === absoluteManifest, 'candidate_snapshot_ref 未绑定当前 manifest');
125
+ const streamPath = external ? resolveMaintenanceBundleFile(candidateDir, manifest.snapshot_stream_ref) : path.resolve(root, manifest.snapshot_stream_ref);
126
+ const diffPath = external ? resolveMaintenanceBundleFile(candidateDir, manifest.tracked_diff_ref) : path.resolve(root, manifest.tracked_diff_ref);
133
127
  ensure(streamPath === path.join(candidateDir, "candidate.bin") && diffPath === path.join(candidateDir, "tracked.diff"), "packed candidate 引用必须绑定同目录规范文件");
134
128
  const stream = readFileSync(streamPath);
135
129
  ensure(createHash("sha256").update(stream).digest("hex") === manifest.candidate_digest.replace(/^sha256:/, ""), "candidate_digest 与 packed stream 不一致");