create-yss-spec 3.1.0 → 3.2.0

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 (302) hide show
  1. package/README.md +119 -89
  2. package/bin/create-yss-spec.js +11 -3
  3. package/package.json +9 -2
  4. package/src/api/_sync-service.js +191 -0
  5. package/src/api/index.js +22 -0
  6. package/src/api/project-diff.js +9 -0
  7. package/src/api/project-doctor.js +10 -0
  8. package/src/api/template-apply.js +10 -0
  9. package/src/api/template-plan.js +9 -0
  10. package/src/cli/args.js +60 -0
  11. package/src/cli/error-output.js +52 -0
  12. package/src/cli/flags.js +9 -0
  13. package/src/cli/help.js +95 -0
  14. package/src/cli/index.js +82 -0
  15. package/src/cli/plan-output.js +61 -0
  16. package/src/cli/prompts.js +91 -0
  17. package/src/cli/router.js +41 -0
  18. package/src/cli.js +5 -2253
  19. package/src/commands/attach.js +280 -0
  20. package/src/commands/diff.js +23 -0
  21. package/src/commands/doctor.js +417 -0
  22. package/src/commands/init.js +193 -0
  23. package/src/commands/sync.js +146 -0
  24. package/src/commands/update.js +14 -0
  25. package/src/contracts/apply-result-v1.json +45 -0
  26. package/src/contracts/customization-policy-v1.json +28 -0
  27. package/src/contracts/doctor-report-v1.json +29 -0
  28. package/src/contracts/error-envelope-v1.json +24 -0
  29. package/src/contracts/generator-policy-v1.json +24 -0
  30. package/src/contracts/ownership-policy-v1.json +40 -0
  31. package/src/contracts/plan-schema-v1.json +115 -0
  32. package/src/family-identity.js +365 -0
  33. package/src/family-runtime.js +23 -0
  34. package/src/filesystem/apply-plan.js +44 -0
  35. package/src/filesystem/copy-path.js +28 -0
  36. package/src/filesystem/path-utils.js +67 -0
  37. package/src/filesystem/transaction-runner.js +41 -0
  38. package/src/filesystem/transaction.js +153 -0
  39. package/src/git/submodule.js +115 -0
  40. package/src/git/worktree.js +69 -0
  41. package/src/template/attach-planner-runtime.js +51 -0
  42. package/src/template/attach-planner.js +160 -0
  43. package/src/template/instance-runtime.js +463 -0
  44. package/src/template/lifecycle-metadata.js +99 -0
  45. package/src/template/lifecycle-policy.js +129 -0
  46. package/src/template/lifecycle-runtime.js +90 -0
  47. package/src/template/migration-planner.js +95 -0
  48. package/src/template/migration-runtime.js +247 -0
  49. package/src/template/ownership-metadata.js +79 -0
  50. package/src/template/ownership-policy.js +149 -0
  51. package/src/template/ownership-runtime.js +109 -0
  52. package/src/template/plan-schema.js +36 -0
  53. package/src/template/sync-planner-runtime.js +57 -0
  54. package/src/template/sync-planner.js +206 -0
  55. package/src/template/verification-runtime.js +154 -0
  56. package/src/validation/identity.js +41 -0
  57. package/src/validation/metadata.js +105 -0
  58. package/src/validation/security.js +67 -0
  59. package/src/validation/snapshot.js +47 -0
  60. package/template/.agents/skills/.strategic-design-skills-manifest.json +1 -1
  61. package/template/.agents/skills/yss-domain/SKILL.md +3 -3
  62. package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  63. package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  64. package/template/.agents/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  65. package/template/.agents/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  66. package/template/.agents/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  67. package/template/.agents/skills/yss-mvc-design/SKILL.md +16 -0
  68. package/template/.agents/skills/yss-mvc-design/agents/openai.yaml +4 -0
  69. package/template/.agents/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  70. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +4 -2
  71. package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  72. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  73. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  74. package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +1 -1
  75. package/template/.agents/skills/yss-tactical-design/SKILL.md +2 -2
  76. package/template/.agents/skills/yss-tactical-design/references/output-template.md +2 -0
  77. package/template/.agents/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  78. package/template/.agents/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  79. package/template/.agents/skills/yss-technical-design/SKILL.md +31 -0
  80. package/template/.agents/skills/yss-technical-design/agents/openai.yaml +4 -0
  81. package/template/.agents/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  82. package/template/.agents/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  83. package/template/.agents/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  84. package/template/.agents/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  85. package/template/.agents/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  86. package/template/.agents/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  87. package/template/.agents/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  88. package/template/.agents/skills/yss-ui/SKILL.md +2 -0
  89. package/template/.claude/skills/yss-domain/SKILL.md +3 -3
  90. package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  91. package/template/.claude/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  92. package/template/.claude/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  93. package/template/.claude/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  94. package/template/.claude/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  95. package/template/.claude/skills/yss-mvc-design/SKILL.md +16 -0
  96. package/template/.claude/skills/yss-mvc-design/agents/openai.yaml +4 -0
  97. package/template/.claude/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  98. package/template/.claude/skills/yss-product-lifecycle/SKILL.md +4 -2
  99. package/template/.claude/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  100. package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  101. package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  102. package/template/.claude/skills/yss-product-lifecycle/references/state-model.md +1 -1
  103. package/template/.claude/skills/yss-tactical-design/SKILL.md +2 -2
  104. package/template/.claude/skills/yss-tactical-design/references/output-template.md +2 -0
  105. package/template/.claude/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  106. package/template/.claude/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  107. package/template/.claude/skills/yss-technical-design/SKILL.md +31 -0
  108. package/template/.claude/skills/yss-technical-design/agents/openai.yaml +4 -0
  109. package/template/.claude/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  110. package/template/.claude/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  111. package/template/.claude/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  112. package/template/.claude/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  113. package/template/.claude/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  114. package/template/.claude/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  115. package/template/.claude/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  116. package/template/.claude/skills/yss-ui/SKILL.md +2 -0
  117. package/template/.codex/skills/yss-domain/SKILL.md +3 -3
  118. package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  119. package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  120. package/template/.codex/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  121. package/template/.codex/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  122. package/template/.codex/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  123. package/template/.codex/skills/yss-mvc-design/SKILL.md +16 -0
  124. package/template/.codex/skills/yss-mvc-design/agents/openai.yaml +4 -0
  125. package/template/.codex/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  126. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +4 -2
  127. package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  128. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  129. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  130. package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +1 -1
  131. package/template/.codex/skills/yss-tactical-design/SKILL.md +2 -2
  132. package/template/.codex/skills/yss-tactical-design/references/output-template.md +2 -0
  133. package/template/.codex/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  134. package/template/.codex/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  135. package/template/.codex/skills/yss-technical-design/SKILL.md +31 -0
  136. package/template/.codex/skills/yss-technical-design/agents/openai.yaml +4 -0
  137. package/template/.codex/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  138. package/template/.codex/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  139. package/template/.codex/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  140. package/template/.codex/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  141. package/template/.codex/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  142. package/template/.codex/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  143. package/template/.codex/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  144. package/template/.codex/skills/yss-ui/SKILL.md +2 -0
  145. package/template/.cursor/skills/yss-domain/SKILL.md +3 -3
  146. package/template/.cursor/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  147. package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  148. package/template/.cursor/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  149. package/template/.cursor/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  150. package/template/.cursor/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  151. package/template/.cursor/skills/yss-mvc-design/SKILL.md +16 -0
  152. package/template/.cursor/skills/yss-mvc-design/agents/openai.yaml +4 -0
  153. package/template/.cursor/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  154. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +4 -2
  155. package/template/.cursor/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  156. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  157. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  158. package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +1 -1
  159. package/template/.cursor/skills/yss-tactical-design/SKILL.md +2 -2
  160. package/template/.cursor/skills/yss-tactical-design/references/output-template.md +2 -0
  161. package/template/.cursor/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  162. package/template/.cursor/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  163. package/template/.cursor/skills/yss-technical-design/SKILL.md +31 -0
  164. package/template/.cursor/skills/yss-technical-design/agents/openai.yaml +4 -0
  165. package/template/.cursor/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  166. package/template/.cursor/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  167. package/template/.cursor/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  168. package/template/.cursor/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  169. package/template/.cursor/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  170. package/template/.cursor/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  171. package/template/.cursor/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  172. package/template/.cursor/skills/yss-ui/SKILL.md +2 -0
  173. package/template/.pi/skills/yss-domain/SKILL.md +3 -3
  174. package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  175. package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  176. package/template/.pi/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  177. package/template/.pi/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  178. package/template/.pi/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  179. package/template/.pi/skills/yss-mvc-design/SKILL.md +16 -0
  180. package/template/.pi/skills/yss-mvc-design/agents/openai.yaml +4 -0
  181. package/template/.pi/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  182. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +4 -2
  183. package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  184. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  185. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  186. package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +1 -1
  187. package/template/.pi/skills/yss-tactical-design/SKILL.md +2 -2
  188. package/template/.pi/skills/yss-tactical-design/references/output-template.md +2 -0
  189. package/template/.pi/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  190. package/template/.pi/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  191. package/template/.pi/skills/yss-technical-design/SKILL.md +31 -0
  192. package/template/.pi/skills/yss-technical-design/agents/openai.yaml +4 -0
  193. package/template/.pi/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  194. package/template/.pi/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  195. package/template/.pi/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  196. package/template/.pi/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  197. package/template/.pi/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  198. package/template/.pi/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  199. package/template/.pi/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  200. package/template/.pi/skills/yss-ui/SKILL.md +2 -0
  201. package/template/.qoder/skills/yss-domain/SKILL.md +3 -3
  202. package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  203. package/template/.qoder/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  204. package/template/.qoder/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  205. package/template/.qoder/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  206. package/template/.qoder/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  207. package/template/.qoder/skills/yss-mvc-design/SKILL.md +16 -0
  208. package/template/.qoder/skills/yss-mvc-design/agents/openai.yaml +4 -0
  209. package/template/.qoder/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  210. package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +4 -2
  211. package/template/.qoder/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  212. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  213. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  214. package/template/.qoder/skills/yss-product-lifecycle/references/state-model.md +1 -1
  215. package/template/.qoder/skills/yss-tactical-design/SKILL.md +2 -2
  216. package/template/.qoder/skills/yss-tactical-design/references/output-template.md +2 -0
  217. package/template/.qoder/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  218. package/template/.qoder/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  219. package/template/.qoder/skills/yss-technical-design/SKILL.md +31 -0
  220. package/template/.qoder/skills/yss-technical-design/agents/openai.yaml +4 -0
  221. package/template/.qoder/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  222. package/template/.qoder/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  223. package/template/.qoder/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  224. package/template/.qoder/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  225. package/template/.qoder/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  226. package/template/.qoder/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  227. package/template/.qoder/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  228. package/template/.qoder/skills/yss-ui/SKILL.md +2 -0
  229. package/template/.trae/skills/yss-domain/SKILL.md +3 -3
  230. package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  231. package/template/.trae/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  232. package/template/.trae/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  233. package/template/.trae/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  234. package/template/.trae/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  235. package/template/.trae/skills/yss-mvc-design/SKILL.md +16 -0
  236. package/template/.trae/skills/yss-mvc-design/agents/openai.yaml +4 -0
  237. package/template/.trae/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  238. package/template/.trae/skills/yss-product-lifecycle/SKILL.md +4 -2
  239. package/template/.trae/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  240. package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  241. package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  242. package/template/.trae/skills/yss-product-lifecycle/references/state-model.md +1 -1
  243. package/template/.trae/skills/yss-tactical-design/SKILL.md +2 -2
  244. package/template/.trae/skills/yss-tactical-design/references/output-template.md +2 -0
  245. package/template/.trae/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  246. package/template/.trae/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  247. package/template/.trae/skills/yss-technical-design/SKILL.md +31 -0
  248. package/template/.trae/skills/yss-technical-design/agents/openai.yaml +4 -0
  249. package/template/.trae/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  250. package/template/.trae/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  251. package/template/.trae/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  252. package/template/.trae/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  253. package/template/.trae/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  254. package/template/.trae/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  255. package/template/.trae/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  256. package/template/.trae/skills/yss-ui/SKILL.md +2 -0
  257. package/template/CONTEXT.md +4 -1
  258. package/template/README.md +4 -0
  259. package/template/docs/agents/digital-human-roles.yaml +3 -2
  260. package/template/docs/agents/yss-skill-registry.yaml +20 -1
  261. package/template/docs/architecture/templates/architecture-review-checklist.md +1 -1
  262. package/template/docs/architecture/templates/system-overview-design-template.md +15 -4
  263. package/template/docs/process/frontend-backend-delivery.md +72 -0
  264. package/template/docs/process/implementation-repo-integration.md +2 -0
  265. package/template/docs/process/lifecycle-artifact-map.md +3 -0
  266. package/template/docs/process/lifecycle-registry-baseline.json +4 -1
  267. package/template/docs/process/lifecycle-registry.yaml +14 -2
  268. package/template/docs/process/schemas/backend-delivery-verification.schema.json +113 -0
  269. package/template/docs/process/schemas/backend-delivery.schema.json +301 -0
  270. package/template/docs/process/schemas/digital-human-task-package.schema.json +8 -0
  271. package/template/docs/process/schemas/frontend-delivery-acceptance.schema.json +200 -0
  272. package/template/docs/process/schemas/frontend-implementation-evidence.schema.json +3 -0
  273. package/template/docs/process/schemas/strategic-design-handoff.schema.json +77 -4
  274. package/template/docs/process/strategic-handoff-package.md +4 -2
  275. package/template/docs/process/template-verification-profiles.yaml +20 -0
  276. package/template/docs/user-guide//346/210/230/346/234/257/350/256/276/350/256/241/345/255/220/351/241/271/347/233/256/347/224/250/346/210/267/346/211/213/345/206/214.md +21 -206
  277. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +63 -963
  278. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214/347/264/242/345/274/225.md +11 -14
  279. package/template/docs/user-guide//350/256/276/345/244/207/345/200/237/347/224/250/350/264/257/347/251/277/346/241/210/344/276/213.md +127 -0
  280. package/template/scripts/backend-delivery +14 -0
  281. package/template/scripts/fixtures/backend-delivery/revision-server.mjs +11 -0
  282. package/template/scripts/fixtures/strategic-handoff/fixture.mjs +3 -2
  283. package/template/scripts/instantiate-harness +69 -0
  284. package/template/scripts/lib/backend-delivery.mjs +164 -0
  285. package/template/scripts/lib/frontend-delivery-boundary.mjs +49 -0
  286. package/template/scripts/lib/frontend-delivery.mjs +73 -0
  287. package/template/scripts/lib/harness-execution-scope.mjs +52 -0
  288. package/template/scripts/lib/implementation-contract-compiler.mjs +19 -2
  289. package/template/scripts/lib/lifecycle-transition.mjs +7 -0
  290. package/template/scripts/lib/strategic-handoff-consumption.mjs +17 -10
  291. package/template/scripts/lib/strategic-handoff-design-targets.mjs +15 -0
  292. package/template/scripts/lib/strategic-handoff.mjs +1 -1
  293. package/template/scripts/lib/task-package.mjs +7 -0
  294. package/template/scripts/lib/technical-design-boundary.mjs +23 -0
  295. package/template/scripts/sync-strategic-handoff-tools +5 -2
  296. package/template/scripts/verify-frontend-delivery +9 -0
  297. package/template/scripts/verify-frontend-delivery-scenarios +131 -0
  298. package/template/scripts/verify-frontend-implementation-evidence +2 -0
  299. package/template/scripts/verify-strategic-handoff-package-scenarios +7 -1
  300. package/template/skills-lock.json +43 -13
  301. package/template.manifest.json +43 -1
  302. package/template.snapshot.json +5 -5
@@ -1,21 +1,18 @@
1
1
  # 用户手册索引
2
2
 
3
- 这里集中放置 YSS 模板和生命周期的入门手册。第一次使用时,先看总览,再进入与你当前工作阶段对应的子项目手册。
3
+ ## 第一次使用
4
4
 
5
- ## 推荐阅读顺序
5
+ 1. [YSS 用户手册](用户手册.md):五类项目选型、首次创建、确认与升级。
6
+ 2. [设备借用贯穿案例](设备借用贯穿案例.md):输入、提示词、命令、成功标准及异常恢复。
7
+ 3. [战术设计指南](战术设计子项目用户手册.md):批准战略如何落到设计和测试。
6
8
 
7
- 1. [YSS 用户手册](./用户手册.md):了解仓库身份、生命周期主链和 Agent 使用模式。
8
- 2. [战略设计子项目用户手册](../../submodules/yss-harness-design-agent/docs/user-guide/战略设计子项目用户手册.md):从模糊想法形成 Strategic Design Handoff。
9
- 3. [战术设计子项目用户手册](./战术设计子项目用户手册.md):把交接包细化为 Tactical Design,供研发实现和评审。
9
+ ## 专项路线
10
10
 
11
- ## 按任务查找
11
+ - [战略:澄清、设计、交接](https://github.com/iloveZzz/yss-harness-design-agent/blob/main/docs/user-guide/用户手册索引.md)
12
+ - [通用研发:接收、合同、实现与验证](https://github.com/iloveZzz/yss-harness-dev-agent/blob/main/docs/user-guide/用户手册索引.md)
13
+ - [后端:接口、实现与交付](https://github.com/iloveZzz/yss-harness-backend-agent/blob/main/docs/user-guide/用户手册索引.md)
14
+ - [前端:联合接收、页面与验收](https://github.com/iloveZzz/yss-harness-frontend-agent/blob/main/docs/user-guide/用户手册索引.md)
12
15
 
13
- | 你现在要做什么 | 推荐手册 |
14
- |---|---|
15
- | 创建、接管或更新 YSS 项目 | [YSS 用户手册](./用户手册.md) |
16
- | 澄清需求、确定用户和范围 | [战略设计子项目用户手册](../../submodules/yss-harness-design-agent/docs/user-guide/战略设计子项目用户手册.md) |
17
- | 设计聚合、状态、不变量和领域事件 | [战术设计子项目用户手册](./战术设计子项目用户手册.md) |
18
- | 了解完整生命周期和阶段门禁 | [产品生命周期工作流](../../submodules/yss-harness-design-agent/docs/user-guide/产品生命周期工作流.md) |
19
- | 查找长期协作习惯和反模式 | [生命周期最佳实践](../../submodules/yss-harness-design-agent/docs/user-guide/生命周期最佳实践.md) |
16
+ 跨项目导航使用 GitHub 链接;生成实例不需要兄弟仓或 submodules 目录。链接指向各仓 main,实际执行仍核对本地 profile、包版本和固定模板 SHA。
20
17
 
21
- > 本仓库是 `template-source`。手册中的业务名称和示例只用于教学;真实产品资料应在 `project-instance` 中建立,并遵守对应的生命周期门禁。
18
+ CLI 参数详解:[综合 CLI](https://github.com/iloveZzz/create-yss-spec/blob/main/docs/user-guide/create-yss-spec-cli-guide.md)、[战略 CLI](https://github.com/iloveZzz/create-yss-harness-design)、[研发 CLI](https://github.com/iloveZzz/create-yss-harness-dev)。组件工具专项见 [YSS UI MCP](yss-ui-mcp.md)。
@@ -0,0 +1,127 @@
1
+ # 内部设备借用:贯穿五类项目的教学案例
2
+
3
+ 本文是虚构教学说明,不是已批准 Spec、真实交付包或可直接执行的产品合同。示例路径、规则和标识由学习者在独立 `project-instance` 中确认后落盘;模板源不登记这些业务词汇。
4
+
5
+ ## 业务故事与范围
6
+
7
+ 员工申请借用设备,负责人审批,管理员记录领用和归还。第一轮仅支持一张申请借用一台设备;采购、计费和维修不在案例范围。统一管理方协调战略、后端和前端版本。
8
+
9
+ | 场景 | 正常结果 | 必须讨论的反例 |
10
+ |---|---|---|
11
+ | 提交申请 | 形成待审批申请 | 日期非法、设备不可借 |
12
+ | 审批 | 形成批准或驳回结果 | 无权限、重复审批 |
13
+ | 领用 | 记录领用并改变设备占用状态 | 未批准、设备被另一申请占用 |
14
+ | 归还 | 记录归还并释放设备 | 重复归还、设备损坏如何另行处置 |
15
+
16
+ “审批是否预占设备”“谁能代领”“超期如何处理”是待用户决定,不由 Agent 默认为业务规则。完整故事贯穿教学;每次实现仍只选一个窄业务切片,例如“已批准申请领用设备”。
17
+
18
+ ## 1. 选择工作组织
19
+
20
+ 综合模板可承载从澄清到业务验收的管理资产。战略模板只负责上游方案;研发既可以交给通用研发模板,也可以交给后端/前端专职模板。后两者必须登记统一管理方及独立实现仓,不把源代码复制进模板。
21
+
22
+ ## 2. 战略方形成可交接输入
23
+
24
+ ```text
25
+ 请按本仓战略流程澄清“内部设备借用”。
26
+ 逐轮确认参与者、目标、范围、申请/审批/领用/归还规则及失败场景。
27
+ 先提出会改变业务结果的问题,不替我决定审批是否占用库存。
28
+ 确认后再起草 Spec、需要的页面流程、视觉基线和业务级 Ticket。
29
+ 列出准备交接的规则、关键场景、版本、批准证据和研发待决事项。
30
+ ```
31
+
32
+ 用户逐项核对业务和页面。预期输出为本仓合同要求的已批准战略资产、根词汇、交接描述及证据闭包,不能只交聊天摘要。战略方不在此生成后端工程或冻结工程 API。
33
+
34
+ 由 Agent 给出实际交接描述路径后,在战略实例执行以下命令。尖括号必须替换为真实路径,输出目录须新建;`--handoff` 是相对源实例的文件路径。
35
+
36
+ ```bash
37
+ node scripts/strategic-handoff export --source-root . --handoff <交接描述相对路径> --output <新包目录> --zip
38
+ node scripts/strategic-handoff verify --bundle <包目录或ZIP>
39
+ ```
40
+
41
+ 预期验包输出 `result: verified` 及包摘要;缺证据或被修改的包会失败。把完整目录/ZIP交给下游,保留版本与摘要,不手改包内文件。
42
+
43
+ ## 3. 后端或通用研发接收
44
+
45
+ 在接收实例运行:
46
+
47
+ ```bash
48
+ node scripts/strategic-handoff verify --bundle <包目录或ZIP>
49
+ node scripts/strategic-handoff import --bundle <包目录或ZIP> --target-root .
50
+ ```
51
+
52
+ ```text
53
+ 请读取导入收据和包内规则/场景,核对本仓根 CONTEXT.md 并形成正式对账。
54
+ 为“已批准申请领用设备”逐项登记承接、冲突和依赖。
55
+ 按当前流程准备战术设计、API Draft/Freeze 和后端 Slice Contract,
56
+ 登记真实实现仓、验证命令和回滚点。合同获准前只准备材料,不写代码。
57
+ ```
58
+
59
+ 预期保存导入收据、目标词汇对账、规则/场景承接与当前合同;导入成功不会自动批准这些资产。设备占用竞争应落实到设计与可执行测试,不能只在页面禁用按钮。API 变化回到冻结流程。后端专职只承担后端;通用研发按本仓合同承担实际受影响的两端工作。
60
+
61
+ ## 4. 后端交付当前切片
62
+
63
+ ```text
64
+ 请按已批准且当前的合同实现领用切片,使用登记实现仓根 ./mvnw 验证。
65
+ 整理成功/失败契约测试、冻结接口、合同批准、构建产物、部署身份和测试数据证据。
66
+ 按本仓 backend-delivery schema 起草交付描述,核对本次切片范围与战略摘要。
67
+ 缺可达环境或版本证据就列为缺口,不写成已完成。
68
+ ```
69
+
70
+ 在后端实例执行(交付描述已由实际证据形成):
71
+
72
+ ```bash
73
+ node scripts/backend-delivery export --source-root . --delivery <交付描述相对路径> --output <新交付包目录> --zip
74
+ node scripts/backend-delivery verify --bundle <交付包目录或ZIP>
75
+ ```
76
+
77
+ 预期 `verified`,但 `live_service_checked: false`:这里只验证快照,不能证明环境当前可用。交付包含战略绑定、冻结接口、批准合同、构建部署及成功/失败验证;不把账号密码装入包。实际 API 和版本探测由已登记环境提供,不凭手册假设已有固定端点。
78
+
79
+ ## 5. 前端联合接收与准备
80
+
81
+ 在前端实例执行:
82
+
83
+ ```bash
84
+ node scripts/backend-delivery import --bundle <交付包目录或ZIP> --target-root .
85
+ ```
86
+
87
+ 战略快照随交付链导入,后端包与战略包分别验证。导入产生接收草稿;核对目标词汇、规则/场景、接口和视觉用例后才能形成正式接收记录。
88
+
89
+ ```text
90
+ 请联合核对战略和后端交付,完成目标词汇对账与前端场景映射。
91
+ 检查部署/源码/接口/构建/测试数据版本及真实服务。
92
+ 通过后只准备前端工程设计、frontend_implementation_plan 和 Slice Contract,
93
+ 列出待批准事项。输入不齐时只诊断并回交缺口,不写前端或后端代码。
94
+ ```
95
+
96
+ 由 Agent 返回当前接收记录相对路径和切片 ID 后执行:
97
+
98
+ ```bash
99
+ node scripts/verify-frontend-delivery --root . --slice <切片ID> <接收记录相对路径>
100
+ ```
101
+
102
+ 成功是 `inputs-verified` 且 `ready_for_agent: false`。这允许准备计划和合同,正式编码仍须批准且当前的 Slice Contract。前端实现消费冻结 API;发现业务/API缺口回交维护方,不在前端仓悄悄重定义。
103
+
104
+ ## 6. 实现、联调与业务验收
105
+
106
+ ```text
107
+ 请复验接收输入与合同仍然当前,再按批准写范围实现前端领用流程。
108
+ 使用登记前端工程的 pnpm 命令,记录实际退出码、截图、状态交互、
109
+ console warning、失败恢复及真实后端联调结果;交独立 Reviewer 审查。
110
+ ```
111
+
112
+ 后端记录可交付、前端记录可验收,统一管理方汇总同一战略、API、部署、前端版本的业务证据。用户检查一次真实领用及“重复领用/无权限”等约定反例,再按角色政策完成验收和发布裁决。单端完成、离线验包或一张截图都不能替代整体业务验收。
113
+
114
+ ## 7. 变更、失败与恢复
115
+
116
+ | 情况 | 应做的事 |
117
+ |---|---|
118
+ | 包摘要不一致/批准缺失 | 保留失败输出,要求源方重出完整包;不手改摘要 |
119
+ | 对账冲突/规则含糊 | 回交战略方决定,阻断依赖切片 |
120
+ | 服务不可达或版本不符 | 后端补环境/部署证据,前端重新接收 |
121
+ | 已导入更新的同身份后端包 | 旧接收记录失效,重新验证并编译依赖合同 |
122
+ | 战略或视觉基线变化 | 评估规则/场景/页面依赖,更新合同后恢复 |
123
+ | 模板同步失败 | 检查事务回滚结果和旧 metadata;从 Git 基线或备份恢复 |
124
+
125
+ 重试使用真实当前输入,不能复用旧成功日志当本次放行。已成功导入的战略快照可在后端包导入失败后保留,修复后幂等重试。
126
+
127
+ 权威接力语义见 [前后端交付与联合接收](../process/frontend-backend-delivery.md),具体阶段/门禁见本仓 lifecycle-registry.yaml;案例不另定义状态、角色或批准政策。
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from 'node:util';
3
+ import path from 'node:path';
4
+ import { exportBackendDelivery, openBackendDelivery, importBackendDelivery } from './lib/backend-delivery.mjs';
5
+ try {
6
+ const {values,positionals}=parseArgs({allowPositionals:true,options:{'source-root':{type:'string'},delivery:{type:'string'},output:{type:'string'},zip:{type:'boolean'},bundle:{type:'string'},'target-root':{type:'string'}}});
7
+ if(positionals.length!==1)throw new TypeError('必须指定 export / verify / import');
8
+ let result;
9
+ if(positionals[0]==='export'&&values['source-root']&&values.delivery&&values.output)result=await exportBackendDelivery({sourceRoot:values['source-root'],deliveryRef:values.delivery,output:values.output,zip:values.zip});
10
+ else if(positionals[0]==='verify'&&values.bundle)result=await openBackendDelivery(path.resolve(values.bundle),b=>({result:'verified',delivery_id:b.delivery.delivery_id,version:b.delivery.version,bundle_digest:b.manifest.bundle_digest,live_service_checked:false}));
11
+ else if(positionals[0]==='import'&&values.bundle&&values['target-root'])result=await importBackendDelivery({bundle:path.resolve(values.bundle),targetRoot:values['target-root']});
12
+ else throw new TypeError('用法: backend-delivery export --source-root <repo> --delivery <ref> --output <new-dir> [--zip] | verify --bundle <dir|zip> | import --bundle <dir|zip> --target-root <repo>');
13
+ process.stdout.write(`${JSON.stringify(result,null,2)}\n`);
14
+ } catch(error) { process.stderr.write(`${JSON.stringify({result:'blocked',error:error.message})}\n`);process.exitCode=1; }
@@ -0,0 +1,11 @@
1
+ // Synthetic maintenance service. Never used as evidence of product API readiness.
2
+ import { createServer } from 'node:http';
3
+ import { readFileSync } from 'node:fs';
4
+ const server=createServer((request,response)=>{
5
+ if(request.method!=='GET'||request.url!=='/version') {response.writeHead(404);response.end();return;}
6
+ const state=JSON.parse(readFileSync(process.argv[2],'utf8'));
7
+ response.writeHead(state.status||200,{'content-type':'application/json'});
8
+ response.end(JSON.stringify(state.body));
9
+ });
10
+ server.listen(0,'127.0.0.1',()=>process.send({port:server.address().port}));
11
+ process.on('disconnect',()=>server.close(()=>process.exit(0)));
@@ -16,7 +16,8 @@ context_schema_version: 1
16
16
  |---|---|---|---|---|
17
17
  | 供应商 | 提供产品或服务的主体 | Supplier | Global | |
18
18
  `;
19
- export async function fixture(root) {
19
+ // Legacy fixture remains the default for released CLI compatibility tests.
20
+ export async function fixture(root, { technicalDesign = false } = {}) {
20
21
  const put=(ref,value)=>{const p=path.join(root,ref);mkdirSync(path.dirname(p),{recursive:true});writeFileSync(p,typeof value==='string'?value:json(value));};
21
22
  put('yss-project.yaml','schema_version: 1\nrepository_mode: project-instance\n');put('CONTEXT.md',context);
22
23
  const source=parseContextSource(context), resolved=resolveContextTermRefs(source,['Global/Supplier']);
@@ -51,7 +52,7 @@ const visualBaselineRef = { baseline_id: sealedBaseline.baseline_id, version: se
51
52
  const terminalGate=countersignRuleForGate(roles.gate_policy,'gate.strategic-design-handoff-approved')?'gate.strategic-design-handoff-approved':'gate.stage-decision-package-approved';
52
53
  const gates={domain_strategy_ref:'gate.domain-strategy-approved',stage_decision_package_ref:'gate.stage-decision-package-approved',spec_ref:'gate.spec-baseline-approved',prototype_ref:'gate.user-confirmation',visual_baseline_ref:'gate.user-confirmation',business_ticket_set_ref:terminalGate,handoff:terminalGate};
53
54
  const approvals=Object.fromEntries([...Object.keys(sourceRefs),'handoff'].map(key=>[key,{record_ref:`approvals/${key}.yaml`,gate_id:gates[key],digest_kind:key==='visual_baseline_ref'?'visual-baseline':['domain_strategy_ref','stage_decision_package_ref','business_ticket_set_ref'].includes(key)?'canonical-json':'sha256-bytes'}]));
54
- const handoff={schema_version:3,handoff_id:'strategic-design-handoff.supplier',handoff_version:'v1',status:'approved',source:sourceRefs,source_context_snapshot:snapshot,context_delta:{added:resolved.terms.map(({term_ref,term,meaning,english_identifier,context_id,forbidden_aliases})=>({term_ref,term,meaning,english_identifier,context_id,forbidden_aliases})),updated:[],deprecated:[]},target_context_reconciliation:{target_context_ref:'CONTEXT.md',reconciliation_schema_ref:'docs/process/schemas/context-reconciliation.schema.json',required_before_skill:'yss-tactical-design',status:'pending'},target:{team:'downstream-rd-team',skill:'yss-tactical-design',output:'tactical-design-contract'},problem_and_business_outcomes:['提交供应商材料'],bounded_context_and_subdomain_map:['SupplierManagement'],context_map_and_translation_responsibility:['SupplierManagement'],ubiquitous_language_and_concept_candidates:['Global/Supplier'],scenarios_and_business_invariants:['rule.complete','scenario.submit'],tactical_design_questions:['一致性边界'],deferred_decisions_and_ownership:[],evidence_and_version_digests:['evidence/offline.log'],acceptance:['traceability'],package_export:{schema_version:1,approvals,additional_files:[],reference_map:{},prototype:{profile:'H2',preview_root:'preview',entry_ref:'preview/index.html',verification_ref:'evidence/offline.json',verification_digest:hash(readFileSync(path.join(root,'evidence/offline.json'))),source_digest:treeDigest(root,'prototype-src'),source_root:'prototype-src',lock_ref:'prototype-src/pnpm-lock.yaml'}}};
55
+ const handoff={schema_version:3,handoff_id:'strategic-design-handoff.supplier',handoff_version:'v1',status:'approved',source:sourceRefs,source_context_snapshot:snapshot,context_delta:{added:resolved.terms.map(({term_ref,term,meaning,english_identifier,context_id,forbidden_aliases})=>({term_ref,term,meaning,english_identifier,context_id,forbidden_aliases})),updated:[],deprecated:[]},target_context_reconciliation:{target_context_ref:'CONTEXT.md',reconciliation_schema_ref:'docs/process/schemas/context-reconciliation.schema.json',required_before_skill:technicalDesign?'yss-technical-design':'yss-tactical-design',status:'pending'},target:{team:'downstream-rd-team',skill:technicalDesign?'yss-technical-design':'yss-tactical-design',output:technicalDesign?'technical-design-contract':'tactical-design-contract'},problem_and_business_outcomes:['提交供应商材料'],bounded_context_and_subdomain_map:['SupplierManagement'],context_map_and_translation_responsibility:['SupplierManagement'],ubiquitous_language_and_concept_candidates:['Global/Supplier'],scenarios_and_business_invariants:['rule.complete','scenario.submit'],tactical_design_questions:['一致性边界'],deferred_decisions_and_ownership:[],evidence_and_version_digests:['evidence/offline.log'],acceptance:['traceability'],package_export:{schema_version:1,approvals,additional_files:[],reference_map:{},prototype:{profile:'H2',preview_root:'preview',entry_ref:'preview/index.html',verification_ref:'evidence/offline.json',verification_digest:hash(readFileSync(path.join(root,'evidence/offline.json'))),source_digest:treeDigest(root,'prototype-src'),source_root:'prototype-src',lock_ref:'prototype-src/pnpm-lock.yaml'}}};
55
56
  const sign=()=>{put('handoff.yaml',handoff);for(const[key,approval]of Object.entries(approvals)){const asset=key==='handoff'?{id:handoff.handoff_id,version:handoff.handoff_version,digest:hash(readFileSync(path.join(root,'handoff.yaml')))}:sourceRefs[key];put(approval.record_ref,{schema_version:1,gate_id:approval.gate_id,decision:'approved',actor_kind:'digital-human',role_id:countersignRuleForGate(roles.gate_policy,approval.gate_id).countersigners[0],runtime_id:'runtime.generic',principal_ref:'synthetic-maintenance-fixture',artifact_bindings:[{id:asset.id||asset.baseline_id,version:asset.version,digest:asset.digest}]});}};
56
57
  sign();return{handoff,strategy,stage,put,sign,snapshot};
57
58
  }
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ // Repository-local distribution for the two dedicated Harness templates.
3
+ import { existsSync, readFileSync, mkdirSync, mkdtempSync, renameSync, rmSync, statSync, lstatSync, readlinkSync, realpathSync, symlinkSync, chmodSync } from 'node:fs';
4
+ import { execFileSync } from 'node:child_process';
5
+ import path from 'node:path';
6
+ import { ROOT, read, safe, ensure, hash, digest, write, json } from './lib/strategic-handoff-io.mjs';
7
+
8
+ try {
9
+ const args=process.argv.slice(2),options={};
10
+ while(args.length) {
11
+ const key=args.shift();
12
+ if(key==='--allow-working-tree')options.working=true;
13
+ else if(['--target','--project-name'].includes(key)) {ensure(args.length&&!args[0].startsWith('--'),`${key} 缺少值`);options[key.slice(2)]=args.shift();}
14
+ else throw new Error(`未知参数 ${key};使用 --target <新目录> [--project-name <名称>]`);
15
+ }
16
+ ensure(options.target,'必须指定 --target <新目录>');
17
+ const identity=read(safe(ROOT,'yss-project.yaml'));
18
+ ensure(identity.schema_version===1&&identity.repository_mode==='template-source','仅模板源可初始化新项目');
19
+ const profile=read(safe(ROOT,'docs/process/harness-profile.yaml'));
20
+ ensure(['harness.backend-delivery','harness.frontend-delivery'].includes(profile.profile_id),'仅支持后端/前端专职模板');
21
+ const target=path.resolve(options.target);
22
+ ensure(!target.startsWith(ROOT+path.sep)&&!ROOT.startsWith(target+path.sep)&&target!==ROOT,'目标不得包含模板源或位于模板源内');
23
+ ensure(!existsSync(target),'目标已存在;不覆盖或静默转换既有项目 profile');
24
+ const git=args=>execFileSync('git',args,{cwd:ROOT,encoding:'utf8',maxBuffer:16*1024*1024}).trim();
25
+ const commit=git(['rev-parse','HEAD']);
26
+ ensure(/^[0-9a-f]{40}$/.test(commit),'模板必须有不可变 Git 提交');
27
+ const dirty=Boolean(git(['status','--porcelain','--untracked-files=all']));
28
+ ensure(!dirty||options.working,'模板工作树未提交;维护测试可显式使用 --allow-working-tree,正式分发须先提交');
29
+ const manifest=read(safe(ROOT,profile.instantiation.distribution_manifest));
30
+ const names=execFileSync('git',['ls-files','-co','--exclude-standard','-z'],{cwd:ROOT,encoding:'utf8',maxBuffer:16*1024*1024}).split('\0').filter(Boolean);
31
+ const prefix=(ref,base)=>ref===base||ref.startsWith(base+'/');
32
+ const selected=[...new Set(names)].filter(ref=>{
33
+ const top=ref.split('/')[0];
34
+ const allowed=(manifest.allowRootEntries||[]).includes(top)||(manifest.allowRootFiles||[]).includes(ref)||(manifest.allowFiles||[]).includes(ref);
35
+ return allowed&&![...(manifest.excludeRootEntries||[]),...(manifest.initExcludeRootEntries||[])].includes(top)
36
+ &&![...(manifest.excludeRootFiles||[]),...(manifest.initExcludeRootFiles||[])].includes(ref)
37
+ &&![...(manifest.excludePaths||[]),...(manifest.initExcludePaths||[])].some(excluded=>prefix(ref,excluded));
38
+ }).sort();
39
+ ensure(selected.includes('yss-project.yaml')&&selected.includes('AGENTS.md')&&selected.includes('CONTEXT.md'),'分发缺少入口合同');
40
+ const capture=ref=>{
41
+ const file=path.join(ROOT,ref);if(path.dirname(ref)!=='.')safe(ROOT,path.dirname(ref));
42
+ if(lstatSync(file).isSymbolicLink()) {
43
+ const link=readlinkSync(file),resolved=realpathSync(file);
44
+ ensure(!path.isAbsolute(link)&&resolved.startsWith(path.join(ROOT,'.agents/skills')+path.sep),'仅允许指向本仓 canonical skills 的相对投影链接');
45
+ return {ref,link,bytes:Buffer.from(`symlink:${link}`),mode:0o777};
46
+ }
47
+ return {ref,bytes:readFileSync(safe(ROOT,ref)),mode:statSync(file).mode&0o777};
48
+ };
49
+ const captured=selected.map(capture);
50
+ const sourceFiles=captured.map(({ref,bytes,mode})=>({ref,digest:hash(bytes),mode}));
51
+ const sourceDigest=digest(sourceFiles);
52
+ mkdirSync(path.dirname(target),{recursive:true});
53
+ const staging=mkdtempSync(path.join(path.dirname(target),'.harness-init-'));
54
+ try {
55
+ const managed={};
56
+ for(const file of captured) {
57
+ let bytes=file.bytes;
58
+ if(file.ref==='yss-project.yaml') bytes=Buffer.from('schema_version: 1\nrepository_mode: project-instance\n');
59
+ if(file.ref==='README.md') bytes=Buffer.from(`# ${options['project-name']||path.basename(target)}\n\n本仓是 \`${profile.profile_id}\` 的 \`project-instance\`。先读 [AGENTS.md](AGENTS.md)、根 CONTEXT.md 与 [profile](docs/process/harness-profile.yaml)。接力输入与执行条件见 [交付合同](docs/process/frontend-backend-delivery.md)。\n`);
60
+ if(file.link) {mkdirSync(path.dirname(path.join(staging,file.ref)),{recursive:true});symlinkSync(file.link,path.join(staging,file.ref));}
61
+ else {write(staging,file.ref,bytes);chmodSync(path.join(staging,file.ref),file.mode);}
62
+ managed[file.ref]={digest:hash(bytes),mode:file.mode};
63
+ }
64
+ write(staging,profile.instantiation.metadata_file,json({schema_version:1,profile_id:profile.profile_id,template_source:profile.instantiation.template_source,template_commit:commit,source_tree_digest:sourceDigest,source_files:sourceFiles,source_working_tree:dirty,release_snapshot:!dirty,managed_files:managed}));
65
+ for(const {ref,bytes} of captured)ensure(hash(capture(ref).bytes)===hash(bytes),`初始化期间模板变化: ${ref}`);
66
+ ensure(!existsSync(target),'目标目录并发冲突');renameSync(staging,target);
67
+ process.stdout.write(json({result:'initialized',profile_id:profile.profile_id,target,template_commit:commit,source_tree_digest:sourceDigest,release_snapshot:!dirty}));
68
+ } finally {rmSync(staging,{recursive:true,force:true});}
69
+ } catch(error) {process.stderr.write(`${error.message}\n`);process.exitCode=1;}
@@ -0,0 +1,164 @@
1
+ import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { tmpdir } from 'node:os';
4
+ import { openBundle, importBundle, sourceApproval } from './strategic-handoff.mjs';
5
+ import { read, safe, ensure, hash, digest, json, files, write, project, schema, archive, sourceApprovalPolicy } from './strategic-handoff-io.mjs';
6
+
7
+ // Evidence binds the deliverable basis, avoiding a circular hash through its own logs.
8
+ export function backendDeliveryBasis(delivery) {
9
+ return digest(Object.fromEntries(['delivery_id','version','strategic_bundle_digest','scope','openapi','slice_contract','build','environment'].map(key=>[key,delivery[key]])));
10
+ }
11
+
12
+ function boundFile(root, binding) {
13
+ const bytes=readFileSync(safe(root,binding.ref));
14
+ ensure(hash(bytes)===binding.digest,`交付资产摘要不一致: ${binding.ref}`);
15
+ return bytes;
16
+ }
17
+
18
+ async function approvedFile(root, binding, gate) {
19
+ const bytes=boundFile(root,binding);
20
+ const record=read(safe(root,binding.approval_ref));
21
+ const roles=sourceApprovalPolicy(read(safe(root,'docs/agents/digital-human-roles.yaml')));
22
+ await sourceApproval(record,roles,root);
23
+ ensure((Array.isArray(gate)?gate:[gate]).includes(record.gate_id),`交付资产批准门禁不匹配: ${binding.ref}`);
24
+ ensure(record.artifact_bindings?.some(x=>x.id===binding.id&&x.version===binding.version&&x.digest===binding.digest),`批准未绑定当前交付资产: ${binding.ref}`);
25
+ return bytes;
26
+ }
27
+
28
+ function verification(root, binding, basis, kind) {
29
+ boundFile(root,binding);
30
+ const record=read(safe(root,binding.ref));
31
+ schema(record,'docs/process/schemas/backend-delivery-verification.schema.json');
32
+ ensure(record.kind===kind&&record.subject_digest===basis,`验证未绑定当前交付: ${kind}`);
33
+ ensure(record.results.every(x=>x.exit_code===0),`后端验证失败: ${kind}`);
34
+ for(const result of record.results) {
35
+ ensure(Number.isFinite(Date.parse(result.executed_at))&&Date.parse(result.executed_at)<=Date.now()+60000,'验证执行时间无效');
36
+ result.evidence.forEach(file=>boundFile(root,file));
37
+ }
38
+ return record;
39
+ }
40
+
41
+ export async function inspectBackendDelivery(root, ref) {
42
+ project(root);
43
+ const delivery=read(safe(root,ref));
44
+ schema(delivery,'docs/process/schemas/backend-delivery.schema.json');
45
+ ensure(boundFile(root,delivery.environment.test_data).length>0,'测试数据准备说明为空');
46
+ await approvedFile(root,delivery.openapi,['gate.openapi-frozen','gate.openapi-freeze-confirmed']);
47
+ await approvedFile(root,delivery.slice_contract,'gate.slice-contract-approved');
48
+ const contractDoc=read(safe(root,delivery.slice_contract.ref));
49
+ const contract=contractDoc.slice_contract||contractDoc;
50
+ ensure(contract.status==='approved'&&contract.slice_id===delivery.scope.slice_id&&contract.contract_id===delivery.slice_contract.id&&contract.contract_version===delivery.slice_contract.version,'后端 Slice Contract 身份/状态/切片不匹配');
51
+ const api=read(safe(root,delivery.openapi.ref));
52
+ ensure(/^3\.1\./.test(api.openapi),'后端交付必须使用 OpenAPI 3.1');
53
+ const operations=Object.values(api.paths||{}).flatMap(item=>Object.entries(item).filter(([method])=>['get','put','post','delete','options','head','patch','trace'].includes(method)).map(([,operation])=>operation.operationId));
54
+ ensure(delivery.scope.operation_ids.every(id=>operations.includes(id)),'交付接口不在冻结 OpenAPI 中');
55
+ const basis=backendDeliveryBasis(delivery);
56
+ const tests=verification(root,delivery.verification.contract,basis,'backend-contract');
57
+ verification(root,delivery.verification.deployment,basis,'backend-deployment');
58
+ return openBundle(safe(root,delivery.strategic_bundle_ref),bundle=>{
59
+ ensure(bundle.manifest.bundle_digest===delivery.strategic_bundle_digest,'后端交付与战略版本不一致');
60
+ const sources=new Set([...bundle.indexes.rules.map(x=>x.rule_id),...bundle.indexes.scenarios.map(x=>x.scenario_id)]);
61
+ ensure(delivery.scope.source_ids.every(id=>sources.has(id)),'后端交付引用未知规则/场景');
62
+ const scenarios=bundle.indexes.scenarios.filter(x=>delivery.scope.source_ids.includes(x.scenario_id));
63
+ ensure(scenarios.length>0,'后端交付范围缺少业务成功/失败场景');
64
+ for(const scenario of scenarios) {
65
+ ensure(scenario.rule_refs.every(id=>delivery.scope.source_ids.includes(id)),'交付场景缺少关联规则');
66
+ for(const outcome of ['success','failure'])ensure(tests.coverage.some(x=>x.source_id===scenario.scenario_id&&x.outcome===outcome),'后端交付缺少成功/失败场景验证');
67
+ }
68
+ ensure(delivery.scope.operation_ids.every(id=>tests.operation_ids.includes(id)),'后端契约验证未覆盖交付接口');
69
+ return {delivery,basis};
70
+ });
71
+ }
72
+
73
+ function validManifest(manifest,root) {
74
+ ensure(manifest.schema_version===1&&manifest.kind==='backend-delivery','后端包类型或 schema 不支持');
75
+ const {bundle_digest,...body}=manifest;
76
+ ensure(bundle_digest===digest(body),'后端包清单摘要不一致');
77
+ ensure(Array.isArray(manifest.files)&&manifest.files.length<=20000,'后端包文件清单无效');
78
+ const names=manifest.files.map(x=>x.path);
79
+ ensure(new Set(names.map(x=>x.toLowerCase())).size===names.length,'后端包路径重复');
80
+ ensure(json([...names,'manifest.json'].sort())===json(files(root).sort()),'后端包文件缺失或存在未登记文件');
81
+ ensure(manifest.files.reduce((total,file)=>total+file.size_bytes,0)<=512*1024*1024,'后端包大小超限');
82
+ const originals=manifest.files.filter(x=>x.original_ref).map(x=>x.original_ref);
83
+ ensure(new Set(originals.map(x=>x.toLowerCase())).size===originals.length,'后端包源路径重复');
84
+ for(const file of manifest.files) {
85
+ const bytes=readFileSync(safe(root,file.path));
86
+ ensure(bytes.length===file.size_bytes&&hash(bytes)===file.sha256,`后端包文件摘要不一致: ${file.path}`);
87
+ }
88
+ }
89
+
90
+ export async function openBackendDelivery(input, action) {
91
+ const temporary=mkdtempSync(path.join(tmpdir(),'yss-backend-delivery-'));
92
+ try {
93
+ ensure(existsSync(input)&&!lstatSync(input).isSymbolicLink(),'后端交付包不存在或是 symlink');
94
+ let root=path.resolve(input);
95
+ if(lstatSync(root).isFile()) { root=path.join(temporary,'unpacked');mkdirSync(root);archive('unpack',path.resolve(input),root); }
96
+ const manifest=read(safe(root,'manifest.json'));validManifest(manifest,root);
97
+ const source=path.join(temporary,'source');mkdirSync(source);
98
+ for(const file of manifest.files)if(file.original_ref)write(source,file.original_ref,readFileSync(safe(root,file.path)));
99
+ const inspected=await inspectBackendDelivery(source,manifest.delivery_ref);
100
+ ensure(manifest.delivery_id===inspected.delivery.delivery_id&&manifest.version===inspected.delivery.version,'后端包身份不一致');
101
+ return await action({root,source,manifest,...inspected});
102
+ } finally { rmSync(temporary,{recursive:true,force:true}); }
103
+ }
104
+
105
+ export async function exportBackendDelivery({sourceRoot,deliveryRef,output,zip=false}) {
106
+ const root=project(sourceRoot), target=path.resolve(output);
107
+ ensure(!existsSync(target)&&(!zip||!existsSync(`${target}.zip`)),'后端包输出已存在');
108
+ const {delivery}=await inspectBackendDelivery(root,deliveryRef);
109
+ const refs=new Set([deliveryRef,'yss-project.yaml','CONTEXT.md','docs/agents/digital-human-roles.yaml',delivery.openapi.ref,delivery.openapi.approval_ref,delivery.slice_contract.ref,delivery.slice_contract.approval_ref,delivery.environment.test_data.ref,...delivery.supporting_files]);
110
+ for(const binding of Object.values(delivery.verification)) {
111
+ refs.add(binding.ref);
112
+ for(const result of read(safe(root,binding.ref)).results)for(const file of result.evidence)refs.add(file.ref);
113
+ }
114
+ // Keep the original strategic bytes and paths; offline validation reconstructs a temporary source view.
115
+ const strategy=safe(root,delivery.strategic_bundle_ref);
116
+ if(lstatSync(strategy).isDirectory())files(root,delivery.strategic_bundle_ref).forEach(ref=>refs.add(ref));
117
+ else refs.add(delivery.strategic_bundle_ref);
118
+ ensure(refs.size<=20000,'后端包文件数量超限');
119
+ const captured=[...refs].sort().map(ref=>({ref,bytes:readFileSync(safe(root,ref))}));
120
+ mkdirSync(path.dirname(target),{recursive:true});
121
+ const staging=mkdtempSync(path.join(path.dirname(target),'.backend-export-'));
122
+ try {
123
+ const entries=[];
124
+ for(const {ref,bytes} of captured) {
125
+ const name=ref==='CONTEXT.md'?'payload/source-context.snapshot.md':`payload/files/${ref}`;
126
+ write(staging,name,bytes);entries.push({path:name,original_ref:ref,size_bytes:bytes.length,sha256:hash(bytes)});
127
+ }
128
+ const body={schema_version:1,kind:'backend-delivery',delivery_id:delivery.delivery_id,version:delivery.version,delivery_ref:deliveryRef,files:entries};
129
+ const manifest={...body,bundle_digest:digest(body)};write(staging,'manifest.json',json(manifest));
130
+ await openBackendDelivery(staging,()=>null);
131
+ for(const {ref,bytes} of captured)ensure(hash(readFileSync(safe(root,ref)))===hash(bytes),`导出期间后端源资产变化: ${ref}`);
132
+ if(zip)archive('pack',staging,`${staging}.zip`);
133
+ ensure(!existsSync(target)&&(!zip||!existsSync(`${target}.zip`)),'后端包输出并发冲突');
134
+ renameSync(staging,target);if(zip)renameSync(`${staging}.zip`,`${target}.zip`);
135
+ return {result:'exported',delivery_id:delivery.delivery_id,version:delivery.version,bundle_digest:manifest.bundle_digest,output:target,...(zip?{zip:`${target}.zip`}:{})};
136
+ } finally { rmSync(staging,{recursive:true,force:true});rmSync(`${staging}.zip`,{force:true}); }
137
+ }
138
+
139
+ export async function importBackendDelivery({bundle,targetRoot}) {
140
+ const target=project(targetRoot);
141
+ return openBackendDelivery(bundle,async b=>{
142
+ const ref=`docs/backend-deliveries/${b.delivery.delivery_id}/${b.delivery.version}`;
143
+ const destination=safe(target,ref,{missing:true});
144
+ if(existsSync(destination)) {
145
+ const receipt=read(safe(destination,'import-receipt.json'));
146
+ ensure(receipt.bundle_digest===b.manifest.bundle_digest,'同 ID/version 后端包内容冲突');
147
+ await openBackendDelivery(safe(destination,'package'),()=>null);
148
+ return {result:'already-imported',receipt_ref:`${ref}/import-receipt.json`,acceptance_ref:`${ref}/frontend-acceptance-draft.json`};
149
+ }
150
+ const strategic=await importBundle({bundle:safe(b.source,b.delivery.strategic_bundle_ref),targetRoot:target});
151
+ const strategicReceipt=read(safe(target,strategic.receipt_ref));
152
+ const trace=read(safe(target,`${path.posix.dirname(strategic.receipt_ref)}/tactical-traceability-draft.json`));
153
+ mkdirSync(path.dirname(destination),{recursive:true});
154
+ const staging=mkdtempSync(path.join(path.dirname(destination),'.backend-import-'));
155
+ try {
156
+ cpSync(b.root,path.join(staging,'package'),{recursive:true,errorOnExist:true,force:false});
157
+ const receipt={schema_version:1,delivery_id:b.delivery.delivery_id,version:b.delivery.version,bundle_digest:b.manifest.bundle_digest,package_ref:`${ref}/package`};
158
+ write(staging,'import-receipt.json',json(receipt));
159
+ write(staging,'frontend-acceptance-draft.json',json({schema_version:1,status:'draft',slice_id:b.delivery.scope.slice_id,backend_delivery:{import_receipt_ref:`${ref}/import-receipt.json`,bundle_digest:b.manifest.bundle_digest},strategic_handoff:{import_receipt_ref:strategic.receipt_ref,bundle_digest:strategicReceipt.bundle_digest,context_reconciliation_ref:'',rows:trace.rows.map(({tactical_refs,test_seam_refs,...row})=>({...row,frontend_case_refs:[]}))},frontend_cases:[]}));
160
+ ensure(!existsSync(destination),'后端包导入并发冲突');renameSync(staging,destination);
161
+ return {result:'imported-pending-acceptance',receipt_ref:`${ref}/import-receipt.json`,acceptance_ref:`${ref}/frontend-acceptance-draft.json`};
162
+ } finally { rmSync(staging,{recursive:true,force:true}); }
163
+ });
164
+ }
@@ -0,0 +1,49 @@
1
+ import { loadDeliveryProfile } from './harness-execution-scope.mjs';
2
+ import { existsSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { ROOT, read, safe, ensure, digest } from './strategic-handoff-io.mjs';
6
+
7
+ // Shared synchronous adapter for existing compiler, lifecycle and task-package seams.
8
+ // Always re-executes the verifier; a caller-supplied "verified" flag is never evidence.
9
+ export function enforceFrontendDelivery(state={}, {root=ROOT,phase='inputs'}={}) {
10
+ const profile=loadDeliveryProfile(root);
11
+ let contract;
12
+ const contractRef=state.slice_contract_ref||state.contract?.slice_contract_ref;
13
+ const selected=profile?.profile_id==='harness.frontend-delivery'||profile?.frontend_delivery?.required===true;
14
+ const identity=selected?read(safe(root,'yss-project.yaml')):null;
15
+ if(selected)ensure(identity.schema_version===1&&['template-source','project-instance'].includes(identity.repository_mode),'前端项目仓库身份无效');
16
+ const dedicated=selected&&identity.repository_mode==='project-instance';
17
+ if(dedicated)ensure(state.contract?.kind!=='template-maintenance','前端产品项目不得用模板维护任务绕过输入条件');
18
+ let binding=state.frontend_delivery||state.frontend?.delivery||state.resolution?.frontend_delivery;
19
+ if(contractRef) {
20
+ // Legacy callers may supply an absolute external contract. Discover whether
21
+ // the new boundary applies before enforcing its repository-relative policy.
22
+ const file=path.resolve(root,contractRef);
23
+ if(existsSync(file)) {
24
+ const document=read(file);contract=document.slice_contract||document;
25
+ const direct=contract.frontend?.delivery, resolved=contract.resolution?.frontend_delivery;
26
+ ensure(!direct||!resolved||digest(direct)===digest(resolved),'Slice Contract 前端交付绑定冲突');
27
+ binding=direct||resolved||binding;
28
+ }
29
+ }
30
+ if(!dedicated&&!binding)return {result:'not-applicable'};
31
+ if(contractRef)safe(root,contractRef);
32
+ ensure(binding?.acceptance_ref,'frontend-delivery-required: 缺少战略与后端联合接收记录');
33
+ const slice=contract?.slice_id||state.slice_id;
34
+ ensure(!contract?.slice_id||!state.slice_id||contract.slice_id===state.slice_id,'前端任务与 Slice Contract 切片不一致');
35
+ ensure(slice,'frontend-delivery-required: 缺少明确切片');
36
+ if(phase==='implementation') {
37
+ ensure(contract?.status==='approved','frontend-delivery-required: 必须读取已持久化的 approved Slice Contract');
38
+ ensure(contract.frontend?.delivery||contract.resolution?.frontend_delivery,'frontend-delivery-required: Slice Contract 未绑定前端交付');
39
+ ensure(binding.digest,'frontend-delivery-required: Slice Contract 未冻结接收记录摘要');
40
+ }
41
+ const args=[path.join(ROOT,'scripts/verify-frontend-delivery'),'--root',root,'--slice',slice];
42
+ if(binding.digest)args.push('--expected-digest',binding.digest);
43
+ args.push(binding.acceptance_ref);
44
+ const verified=spawnSync(process.execPath,args,{cwd:root,encoding:'utf8',timeout:60000,maxBuffer:2*1024*1024});
45
+ ensure(verified.status===0,`frontend-delivery-blocked: ${verified.error?.message||verified.stderr||verified.stdout}`);
46
+ const result=JSON.parse(verified.stdout);
47
+ ensure(result.result==='inputs-verified'&&result.ready_for_agent===false,'前端接收校验返回非法状态');
48
+ return result;
49
+ }
@@ -0,0 +1,73 @@
1
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { openBackendDelivery } from './backend-delivery.mjs';
4
+ import { openBundle } from './strategic-handoff.mjs';
5
+ import { verifyConsumption } from './strategic-handoff-consumption.mjs';
6
+ import { read, safe, ensure, hash, schema, project } from './strategic-handoff-io.mjs';
7
+
8
+ function pointer(value, ref) {
9
+ ensure(ref.startsWith('/')&&!ref.includes('//'),'服务版本 JSON Pointer 无效');
10
+ return ref.slice(1).split('/').reduce((node,key)=>node?.[key.replace(/~1/g,'/').replace(/~0/g,'~')],value);
11
+ }
12
+
13
+ export async function probeBackend(delivery) {
14
+ const base=new URL(delivery.environment.base_url);
15
+ const url=new URL(delivery.environment.revision_path,base);
16
+ ensure(['http:','https:'].includes(base.protocol)&&!base.username&&!base.password&&!base.hash&&!base.search,'服务环境 URL 无效或包含凭据');
17
+ ensure(url.origin===base.origin&&!url.username&&!url.password&&!url.hash&&!url.search,'版本探测必须在登记环境内');
18
+ const headers={Accept:'application/json'};
19
+ if(delivery.environment.authorization_env) {
20
+ const authorization=process.env[delivery.environment.authorization_env];
21
+ ensure(authorization,'版本探测缺少登记的授权环境配置');headers.Authorization=authorization;
22
+ }
23
+ const response=await fetch(url,{method:'GET',redirect:'error',signal:AbortSignal.timeout(5000),headers});
24
+ ensure(response.ok,`真实接口不可用: HTTP ${response.status}`);
25
+ const reader=response.body.getReader();let size=0;const chunks=[];
26
+ try {
27
+ while(true) { const {done,value}=await reader.read();if(done)break;size+=value.length;ensure(size<=1024*1024,'版本探测响应超限');chunks.push(value); }
28
+ } finally { await reader.cancel(); }
29
+ const body=JSON.parse(Buffer.concat(chunks).toString('utf8'));
30
+ const expected={deployment_id:delivery.environment.deployment_id,source_commit:delivery.build.source_commit,openapi_digest:delivery.openapi.digest,artifact_digest:delivery.build.artifact_digest,test_data_digest:delivery.environment.test_data.digest};
31
+ for(const [key,value] of Object.entries(expected))ensure(pointer(body,delivery.environment.revision_pointers[key])===value,`真实服务版本不匹配: ${key}`);
32
+ return {command:`GET ${url.href}`,executed_at:new Date().toISOString(),exit_code:0,observed:expected};
33
+ }
34
+
35
+ export async function verifyFrontendDelivery({root=process.cwd(),acceptanceRef,sliceRef,expectedDigest}) {
36
+ project(root);
37
+ const file=safe(root,acceptanceRef), acceptance=read(file);
38
+ schema(acceptance,'docs/process/schemas/frontend-delivery-acceptance.schema.json');
39
+ const acceptanceDigest=hash(readFileSync(file));
40
+ if(expectedDigest)ensure(expectedDigest===acceptanceDigest,'前端接收记录摘要已变化,需重编译合同');
41
+ ensure(sliceRef&&acceptance.slice_id===sliceRef,'前端接收记录与执行切片不匹配');
42
+ const binding=acceptance.backend_delivery, receipt=read(safe(root,binding.import_receipt_ref));
43
+ const base=`docs/backend-deliveries/${receipt.delivery_id}/${receipt.version}`;
44
+ ensure(binding.import_receipt_ref===`${base}/import-receipt.json`&&receipt.package_ref===`${base}/package`,'后端收据路径与身份不匹配');
45
+ ensure(receipt.bundle_digest===binding.bundle_digest,'后端收据与接收记录摘要不匹配');
46
+ const versions=readdirSync(safe(root,`docs/backend-deliveries/${receipt.delivery_id}`)).filter(name=>/^v[1-9][0-9]*$/.test(name)&&existsSync(safe(root,`docs/backend-deliveries/${receipt.delivery_id}/${name}/import-receipt.json`,{missing:true}))).sort((a,b)=>Number(b.slice(1))-Number(a.slice(1)));
47
+ ensure(versions[0]===receipt.version,'已接收更新的后端交付,旧前端接收记录 stale');
48
+ return openBackendDelivery(safe(root,receipt.package_ref),async backend=>{
49
+ const delivery=backend.delivery;
50
+ ensure(backend.manifest.bundle_digest===receipt.bundle_digest&&backend.manifest.delivery_id===receipt.delivery_id&&backend.manifest.version===receipt.version,'后端包与收据不一致');
51
+ ensure(delivery.scope.slice_id===sliceRef&&delivery.strategic_bundle_digest===acceptance.strategic_handoff.bundle_digest,'后端、战略与前端切片版本不一致');
52
+ const strategic=await verifyConsumption(acceptance,{root,sliceRef,consumer:'frontend'});
53
+ ensure(strategic.result==='verified',`战略承接阻断: ${JSON.stringify(strategic.issues)}`);
54
+ const ids=acceptance.frontend_cases.map(item=>item.case_id);
55
+ ensure(new Set(ids).size===ids.length,'前端验收用例 ID 重复');
56
+ await openBundle(safe(backend.source,delivery.strategic_bundle_ref),bundle=>{
57
+ const visualCases=bundle.handoff.source.visual_baseline_ref.case_ids;
58
+ for(const item of acceptance.frontend_cases) {
59
+ ensure(item.operation_ids.every(id=>delivery.scope.operation_ids.includes(id)),'前端用例依赖未交付接口');
60
+ ensure(item.source_ids.every(id=>delivery.scope.source_ids.includes(id)),'前端用例依赖未交付规则/场景');
61
+ ensure(item.visual_case_ids.every(id=>visualCases.includes(id)),'前端用例视觉基线悬空');
62
+ const evidence=readFileSync(safe(root,item.evidence_ref));
63
+ ensure(evidence.length>0&&hash(evidence)===item.evidence_digest,'前端承接用例说明为空或摘要漂移');
64
+ }
65
+ });
66
+ for(const id of delivery.scope.source_ids) {
67
+ const row=acceptance.strategic_handoff.rows.find(item=>item.source_id===id);
68
+ ensure(row?.disposition==='mapped'&&row.dependent_slice_refs.includes(sliceRef),'当前交付规则/场景未承接到当前前端切片');
69
+ }
70
+ const actual=await probeBackend(delivery);
71
+ return {result:'inputs-verified',ready_for_agent:false,slice_id:sliceRef,acceptance_ref:acceptanceRef,acceptance_digest:acceptanceDigest,backend_bundle_digest:receipt.bundle_digest,strategic_bundle_digest:strategic.consumed_bundle_digest,actual_verification:actual,next_action:'prepare-or-revalidate-frontend-plan-and-slice-contract'};
72
+ });
73
+ }