@rig-c/create 1.0.2 → 1.1.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 (629) hide show
  1. package/README.md +21 -5
  2. package/docs/AGENT-REFERENCE.md +62 -0
  3. package/docs/CHECKS.md +45 -9
  4. package/docs/INTERVIEW.md +19 -7
  5. package/docs/PROJECT.md +10 -0
  6. package/package.json +4 -1
  7. package/scripts/npm-json.ts +74 -0
  8. package/scripts/verify-example-seals.ts +148 -0
  9. package/src/agent-guide.ts +7 -4
  10. package/src/check.ts +7 -4
  11. package/src/choice-writers.ts +3 -14
  12. package/src/cli.ts +1 -0
  13. package/src/feedback.ts +3 -10
  14. package/src/fix-ledger.ts +1 -1
  15. package/src/job-acts.ts +4 -0
  16. package/src/job-host-state.ts +154 -0
  17. package/src/job-host.ts +37 -14
  18. package/src/job-outbox.ts +5 -3
  19. package/src/job-publication.ts +17 -13
  20. package/src/job-runtime.ts +17 -4
  21. package/src/next.ts +110 -24
  22. package/src/parts-review.ts +4 -11
  23. package/src/reopen.ts +72 -9
  24. package/src/review-act.ts +49 -14
  25. package/src/review-package.ts +3 -1
  26. package/src/rig-version.ts +219 -8
  27. package/src/scene-writers.ts +5 -3
  28. package/src/scene.ts +14 -4
  29. package/src/signable.ts +25 -3
  30. package/src/signoff-checkpoint-act.ts +2 -16
  31. package/src/signoff.ts +3 -15
  32. package/src/waypoints.ts +20 -9
  33. package/templates/agent-guide.md +2 -24
  34. package/templates/collection.json +10 -2
  35. package/templates/example-chain/.gitignore +6 -0
  36. package/templates/example-chain/.npmignore +1 -0
  37. package/templates/example-chain/AGENT-REFERENCE.md +62 -0
  38. package/templates/example-chain/AGENTS.md +4 -26
  39. package/templates/example-chain/README.md +1 -1
  40. package/templates/example-chain/chain.json +385 -319
  41. package/templates/example-chain/checkpoints/0a-interview-options/.gitignore +6 -0
  42. package/templates/example-chain/checkpoints/0a-interview-options/.npmignore +1 -0
  43. package/templates/example-chain/checkpoints/0a-interview-options/AGENT-REFERENCE.md +62 -0
  44. package/templates/example-chain/checkpoints/0a-interview-options/AGENTS.md +4 -26
  45. package/templates/example-chain/checkpoints/0a-interview-options/project.json +22 -5
  46. package/templates/example-chain/checkpoints/0a-interview-options.json +7 -3
  47. package/templates/example-chain/checkpoints/0b-plan-pending/.gitignore +6 -0
  48. package/templates/example-chain/checkpoints/0b-plan-pending/.npmignore +1 -0
  49. package/templates/example-chain/checkpoints/0b-plan-pending/AGENT-REFERENCE.md +62 -0
  50. package/templates/example-chain/checkpoints/0b-plan-pending/AGENTS.md +4 -26
  51. package/templates/example-chain/checkpoints/0b-plan-pending/project.json +22 -5
  52. package/templates/example-chain/checkpoints/0b-plan-pending.json +7 -3
  53. package/templates/example-chain/checkpoints/1-parts-verdict/.gitignore +6 -0
  54. package/templates/example-chain/checkpoints/1-parts-verdict/.npmignore +1 -0
  55. package/templates/example-chain/checkpoints/1-parts-verdict/AGENT-REFERENCE.md +62 -0
  56. package/templates/example-chain/checkpoints/1-parts-verdict/AGENTS.md +4 -26
  57. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/config.json +88 -0
  58. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/painting_in_rig.png +0 -0
  59. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/background.png +0 -0
  60. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/eye_l.png +0 -0
  61. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/eye_r.png +0 -0
  62. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/face.png +0 -0
  63. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/lantern.png +0 -0
  64. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/torso.png +0 -0
  65. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts.json +188 -0
  66. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/recomposite_rig.png +0 -0
  67. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/interview-requirements.json +8 -0
  68. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/run.json +40 -0
  69. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  70. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  71. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  72. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  73. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/background.png +0 -0
  74. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/eye_l.png +0 -0
  75. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/eye_r.png +0 -0
  76. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/face.png +0 -0
  77. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/lantern.png +0 -0
  78. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/torso.png +0 -0
  79. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/mesh_report.json +15 -0
  80. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/motion.json +137 -0
  81. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/rig.json +536 -0
  82. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/run.json +52 -0
  83. package/templates/example-chain/checkpoints/1-parts-verdict/project.json +24 -7
  84. package/templates/example-chain/checkpoints/1-parts-verdict.json +9 -5
  85. package/templates/example-chain/checkpoints/2-rigging-answers/.gitignore +6 -0
  86. package/templates/example-chain/checkpoints/2-rigging-answers/.npmignore +1 -0
  87. package/templates/example-chain/checkpoints/2-rigging-answers/AGENT-REFERENCE.md +62 -0
  88. package/templates/example-chain/checkpoints/2-rigging-answers/AGENTS.md +4 -26
  89. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/config.json +88 -0
  90. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/painting_in_rig.png +0 -0
  91. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/background.png +0 -0
  92. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/eye_l.png +0 -0
  93. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/eye_r.png +0 -0
  94. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/face.png +0 -0
  95. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/lantern.png +0 -0
  96. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/torso.png +0 -0
  97. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts.json +188 -0
  98. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/recomposite_rig.png +0 -0
  99. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/interview-requirements.json +8 -0
  100. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/run.json +40 -0
  101. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  102. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  103. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  104. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  105. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/background.png +0 -0
  106. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/eye_l.png +0 -0
  107. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/eye_r.png +0 -0
  108. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/face.png +0 -0
  109. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/lantern.png +0 -0
  110. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/torso.png +0 -0
  111. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/mesh_report.json +15 -0
  112. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/motion.json +137 -0
  113. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/rig.json +536 -0
  114. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/run.json +52 -0
  115. package/templates/example-chain/checkpoints/2-rigging-answers/project.json +24 -7
  116. package/templates/example-chain/checkpoints/2-rigging-answers.json +21 -5
  117. package/templates/example-chain/checkpoints/3-rig-review/.gitignore +6 -0
  118. package/templates/example-chain/checkpoints/3-rig-review/.npmignore +1 -0
  119. package/templates/example-chain/checkpoints/3-rig-review/AGENT-REFERENCE.md +62 -0
  120. package/templates/example-chain/checkpoints/3-rig-review/AGENTS.md +4 -26
  121. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/config.json +88 -0
  122. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/painting_in_rig.png +0 -0
  123. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/background.png +0 -0
  124. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/eye_l.png +0 -0
  125. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/eye_r.png +0 -0
  126. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/face.png +0 -0
  127. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/lantern.png +0 -0
  128. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/torso.png +0 -0
  129. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts.json +188 -0
  130. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/recomposite_rig.png +0 -0
  131. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/interview-requirements.json +8 -0
  132. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/run.json +40 -0
  133. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  134. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  135. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  136. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  137. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/background.png +0 -0
  138. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/eye_l.png +0 -0
  139. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/eye_r.png +0 -0
  140. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/face.png +0 -0
  141. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/lantern.png +0 -0
  142. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/torso.png +0 -0
  143. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/mesh_report.json +15 -0
  144. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/motion.json +137 -0
  145. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/rig.json +536 -0
  146. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/run.json +52 -0
  147. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/config.json +88 -0
  148. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/interview-requirements.json +8 -0
  149. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/run.json +40 -0
  150. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  151. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/skeleton.json +674 -0
  152. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/skeleton.model.json +1072 -0
  153. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/skeleton.png +0 -0
  154. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/background.png +0 -0
  155. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/eye_l.png +0 -0
  156. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/eye_r.png +0 -0
  157. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/face.png +0 -0
  158. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/lantern.png +0 -0
  159. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/torso.png +0 -0
  160. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts.json +188 -0
  161. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/background.png +0 -0
  162. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/eye_l.png +0 -0
  163. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/eye_r.png +0 -0
  164. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/face.png +0 -0
  165. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/lantern.png +0 -0
  166. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/torso.png +0 -0
  167. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/mesh_report.json +15 -0
  168. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/motion.json +137 -0
  169. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/rig.json +536 -0
  170. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/run.json +52 -0
  171. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/motion.json +1 -1
  172. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/turn.json +108 -0
  173. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/run.json +40 -0
  174. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/skeleton.atlas +28 -0
  175. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/skeleton.json +674 -0
  176. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/skeleton.model.json +1072 -0
  177. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/skeleton.png +0 -0
  178. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/painting_in_rig.png +0 -0
  179. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/background.png +0 -0
  180. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/eye_l.png +0 -0
  181. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/eye_r.png +0 -0
  182. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/face.png +0 -0
  183. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/lantern.png +0 -0
  184. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/torso.png +0 -0
  185. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts.json +188 -0
  186. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/background.png +0 -0
  187. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/eye_l.png +0 -0
  188. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/eye_r.png +0 -0
  189. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/face.png +0 -0
  190. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/lantern.png +0 -0
  191. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/torso.png +0 -0
  192. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/mesh_report.json +15 -0
  193. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/motion.json +137 -0
  194. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/rig.json +536 -0
  195. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/run.json +52 -0
  196. package/templates/example-chain/checkpoints/3-rig-review/project.json +77 -28
  197. package/templates/example-chain/checkpoints/3-rig-review.json +19 -11
  198. package/templates/example-chain/checkpoints/4-direction-post/.gitignore +6 -0
  199. package/templates/example-chain/checkpoints/4-direction-post/.npmignore +1 -0
  200. package/templates/example-chain/checkpoints/4-direction-post/AGENT-REFERENCE.md +62 -0
  201. package/templates/example-chain/checkpoints/4-direction-post/AGENTS.md +4 -26
  202. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/config.json +88 -0
  203. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/painting_in_rig.png +0 -0
  204. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/background.png +0 -0
  205. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/eye_l.png +0 -0
  206. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/eye_r.png +0 -0
  207. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/face.png +0 -0
  208. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/lantern.png +0 -0
  209. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/torso.png +0 -0
  210. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts.json +188 -0
  211. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/recomposite_rig.png +0 -0
  212. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/interview-requirements.json +8 -0
  213. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/run.json +40 -0
  214. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  215. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  216. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  217. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  218. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/background.png +0 -0
  219. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/eye_l.png +0 -0
  220. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/eye_r.png +0 -0
  221. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/face.png +0 -0
  222. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/lantern.png +0 -0
  223. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/torso.png +0 -0
  224. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/mesh_report.json +15 -0
  225. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/motion.json +137 -0
  226. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/rig.json +536 -0
  227. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/run.json +52 -0
  228. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/config.json +88 -0
  229. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/interview-requirements.json +8 -0
  230. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/run.json +40 -0
  231. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  232. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/skeleton.json +674 -0
  233. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/skeleton.model.json +1072 -0
  234. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/skeleton.png +0 -0
  235. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/background.png +0 -0
  236. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/eye_l.png +0 -0
  237. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/eye_r.png +0 -0
  238. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/face.png +0 -0
  239. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/lantern.png +0 -0
  240. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/torso.png +0 -0
  241. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts.json +188 -0
  242. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/background.png +0 -0
  243. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/eye_l.png +0 -0
  244. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/eye_r.png +0 -0
  245. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/face.png +0 -0
  246. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/lantern.png +0 -0
  247. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/torso.png +0 -0
  248. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/mesh_report.json +15 -0
  249. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/motion.json +137 -0
  250. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/rig.json +536 -0
  251. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/run.json +52 -0
  252. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/camera_depth.json +2 -2
  253. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/motion.json +1 -1
  254. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/post_composition.json +2 -2
  255. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/post_timing.json +2 -2
  256. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/turn.json +108 -0
  257. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/run.json +40 -0
  258. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/skeleton.atlas +28 -0
  259. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/skeleton.json +674 -0
  260. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/skeleton.model.json +1072 -0
  261. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/skeleton.png +0 -0
  262. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/painting_in_rig.png +0 -0
  263. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/background.png +0 -0
  264. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/eye_l.png +0 -0
  265. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/eye_r.png +0 -0
  266. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/face.png +0 -0
  267. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/lantern.png +0 -0
  268. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/torso.png +0 -0
  269. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts.json +188 -0
  270. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/background.png +0 -0
  271. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/eye_l.png +0 -0
  272. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/eye_r.png +0 -0
  273. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/face.png +0 -0
  274. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/lantern.png +0 -0
  275. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/torso.png +0 -0
  276. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/mesh_report.json +15 -0
  277. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/motion.json +137 -0
  278. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/rig.json +536 -0
  279. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/run.json +52 -0
  280. package/templates/example-chain/checkpoints/4-direction-post/project.json +106 -57
  281. package/templates/example-chain/checkpoints/4-direction-post.json +22 -14
  282. package/templates/example-chain/derived/drafts/chain/config.json +88 -0
  283. package/templates/example-chain/derived/drafts/chain/input/painting_in_rig.png +0 -0
  284. package/templates/example-chain/derived/drafts/chain/input/parts/background.png +0 -0
  285. package/templates/example-chain/derived/drafts/chain/input/parts/eye_l.png +0 -0
  286. package/templates/example-chain/derived/drafts/chain/input/parts/eye_r.png +0 -0
  287. package/templates/example-chain/derived/drafts/chain/input/parts/face.png +0 -0
  288. package/templates/example-chain/derived/drafts/chain/input/parts/lantern.png +0 -0
  289. package/templates/example-chain/derived/drafts/chain/input/parts/torso.png +0 -0
  290. package/templates/example-chain/derived/drafts/chain/input/parts.json +188 -0
  291. package/templates/example-chain/derived/drafts/chain/input/recomposite_rig.png +0 -0
  292. package/templates/example-chain/derived/drafts/chain/interview-requirements.json +8 -0
  293. package/templates/example-chain/derived/drafts/chain/out/check/build/run.json +40 -0
  294. package/templates/example-chain/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  295. package/templates/example-chain/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  296. package/templates/example-chain/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  297. package/templates/example-chain/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  298. package/templates/example-chain/derived/drafts/chain/out/images/background.png +0 -0
  299. package/templates/example-chain/derived/drafts/chain/out/images/eye_l.png +0 -0
  300. package/templates/example-chain/derived/drafts/chain/out/images/eye_r.png +0 -0
  301. package/templates/example-chain/derived/drafts/chain/out/images/face.png +0 -0
  302. package/templates/example-chain/derived/drafts/chain/out/images/lantern.png +0 -0
  303. package/templates/example-chain/derived/drafts/chain/out/images/torso.png +0 -0
  304. package/templates/example-chain/derived/drafts/chain/out/mesh_report.json +15 -0
  305. package/templates/example-chain/derived/drafts/chain/out/motion.json +137 -0
  306. package/templates/example-chain/derived/drafts/chain/out/rig.json +536 -0
  307. package/templates/example-chain/derived/drafts/chain/out/run.json +52 -0
  308. package/templates/example-chain/derived/review/v1/config.json +88 -0
  309. package/templates/example-chain/derived/review/v1/interview-requirements.json +8 -0
  310. package/templates/example-chain/derived/review/v1/out/check/build/run.json +40 -0
  311. package/templates/example-chain/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  312. package/templates/example-chain/derived/review/v1/out/check/build/skeleton.json +674 -0
  313. package/templates/example-chain/derived/review/v1/out/check/build/skeleton.model.json +1072 -0
  314. package/templates/example-chain/derived/review/v1/out/check/build/skeleton.png +0 -0
  315. package/templates/example-chain/derived/review/v1/out/parts/background.png +0 -0
  316. package/templates/example-chain/derived/review/v1/out/parts/eye_l.png +0 -0
  317. package/templates/example-chain/derived/review/v1/out/parts/eye_r.png +0 -0
  318. package/templates/example-chain/derived/review/v1/out/parts/face.png +0 -0
  319. package/templates/example-chain/derived/review/v1/out/parts/lantern.png +0 -0
  320. package/templates/example-chain/derived/review/v1/out/parts/torso.png +0 -0
  321. package/templates/example-chain/derived/review/v1/out/parts.json +188 -0
  322. package/templates/example-chain/derived/review/v1/out/rig/images/background.png +0 -0
  323. package/templates/example-chain/derived/review/v1/out/rig/images/eye_l.png +0 -0
  324. package/templates/example-chain/derived/review/v1/out/rig/images/eye_r.png +0 -0
  325. package/templates/example-chain/derived/review/v1/out/rig/images/face.png +0 -0
  326. package/templates/example-chain/derived/review/v1/out/rig/images/lantern.png +0 -0
  327. package/templates/example-chain/derived/review/v1/out/rig/images/torso.png +0 -0
  328. package/templates/example-chain/derived/review/v1/out/rig/mesh_report.json +15 -0
  329. package/templates/example-chain/derived/review/v1/out/rig/motion.json +137 -0
  330. package/templates/example-chain/derived/review/v1/out/rig/rig.json +536 -0
  331. package/templates/example-chain/derived/review/v1/out/rig/run.json +52 -0
  332. package/templates/example-chain/evidence/captions.json +1 -1
  333. package/templates/example-chain/evidence/direction/v2.json +1 -1
  334. package/templates/example-chain/evidence/direction-input.json +1 -1
  335. package/templates/example-chain/evidence/interview/camera_depth.json +2 -2
  336. package/templates/example-chain/evidence/interview/motion.json +1 -1
  337. package/templates/example-chain/evidence/interview/post_composition.json +2 -2
  338. package/templates/example-chain/evidence/interview/post_timing.json +2 -2
  339. package/templates/example-chain/evidence/interview/turn.json +108 -0
  340. package/templates/example-chain/evidence/scene/s1.json +2 -2
  341. package/templates/example-chain/outputs/v1/out/check/build/run.json +40 -0
  342. package/templates/example-chain/outputs/v1/out/check/build/skeleton.atlas +28 -0
  343. package/templates/example-chain/outputs/v1/out/check/build/skeleton.json +674 -0
  344. package/templates/example-chain/outputs/v1/out/check/build/skeleton.model.json +1072 -0
  345. package/templates/example-chain/outputs/v1/out/check/build/skeleton.png +0 -0
  346. package/templates/example-chain/outputs/v1/out/painting_in_rig.png +0 -0
  347. package/templates/example-chain/outputs/v1/out/parts/background.png +0 -0
  348. package/templates/example-chain/outputs/v1/out/parts/eye_l.png +0 -0
  349. package/templates/example-chain/outputs/v1/out/parts/eye_r.png +0 -0
  350. package/templates/example-chain/outputs/v1/out/parts/face.png +0 -0
  351. package/templates/example-chain/outputs/v1/out/parts/lantern.png +0 -0
  352. package/templates/example-chain/outputs/v1/out/parts/torso.png +0 -0
  353. package/templates/example-chain/outputs/v1/out/parts.json +188 -0
  354. package/templates/example-chain/outputs/v1/out/rig/images/background.png +0 -0
  355. package/templates/example-chain/outputs/v1/out/rig/images/eye_l.png +0 -0
  356. package/templates/example-chain/outputs/v1/out/rig/images/eye_r.png +0 -0
  357. package/templates/example-chain/outputs/v1/out/rig/images/face.png +0 -0
  358. package/templates/example-chain/outputs/v1/out/rig/images/lantern.png +0 -0
  359. package/templates/example-chain/outputs/v1/out/rig/images/torso.png +0 -0
  360. package/templates/example-chain/outputs/v1/out/rig/mesh_report.json +15 -0
  361. package/templates/example-chain/outputs/v1/out/rig/motion.json +137 -0
  362. package/templates/example-chain/outputs/v1/out/rig/rig.json +536 -0
  363. package/templates/example-chain/outputs/v1/out/rig/run.json +52 -0
  364. package/templates/example-chain/project.json +127 -78
  365. package/templates/example-direction/derived/review/v1/out/check/build/run.json +2 -2
  366. package/templates/example-draft/derived/drafts/lantern/out/check/build/run.json +2 -2
  367. package/templates/example-draft/derived/drafts/lantern/out/run.json +2 -2
  368. package/templates/example-draft/derived/review/v1/out/check/build/run.json +2 -2
  369. package/templates/example-draft/derived/review/v1/out/rig/run.json +2 -2
  370. package/templates/example-draft/derived/review/v2/out/check/build/run.json +2 -2
  371. package/templates/example-draft/derived/review/v2/out/rig/run.json +2 -2
  372. package/templates/example-draft/evidence/direction/v4.json +3 -3
  373. package/templates/example-draft/evidence/direction-input-v4.json +3 -3
  374. package/templates/example-draft/evidence/parts-review.json +1 -1
  375. package/templates/example-draft/evidence/review-reads/{52673b635b9cbc92da1a9e3d4c023a249bbacf79cd21b59724f03f18f8caf09b.json → 8866887a00012b5d5944b7525a478aea70931935bff35ddfcb186ffc515ef5af.json} +2 -2
  376. package/templates/example-draft/evidence/scene/s1.json +3 -3
  377. package/templates/example-draft/evidence/scene-citations.json +1 -1
  378. package/templates/example-draft/out/check/build/run.json +2 -2
  379. package/templates/example-draft/out/run.json +2 -2
  380. package/templates/example-draft/outputs/v1/out/check/build/run.json +2 -2
  381. package/templates/example-draft/outputs/v1/out/rig/run.json +2 -2
  382. package/templates/example-draft/outputs/v2/out/check/build/run.json +2 -2
  383. package/templates/example-draft/outputs/v2/out/rig/run.json +2 -2
  384. package/templates/example-interview-choice.json +113 -68
  385. package/templates/example-interview-options/constraint.json +2 -2
  386. package/templates/example-interview-options/example-assemble.json +2 -2
  387. package/templates/example-interview-options/example-bones.json +5 -5
  388. package/templates/example-interview-options/example-camera-depth.json +3 -3
  389. package/templates/example-interview-options/example-constraints.json +5 -5
  390. package/templates/example-interview-options/example-meshes.json +5 -5
  391. package/templates/example-interview-options/example-motion.json +5 -5
  392. package/templates/example-interview-options/example-picks.json +2 -2
  393. package/templates/example-interview-options/example-post-composition.json +3 -3
  394. package/templates/example-interview-options/example-post-timing.json +3 -3
  395. package/templates/example-interview-options/example-reference.json +2 -2
  396. package/templates/example-interview-options/example-rig-type.json +2 -2
  397. package/templates/example-interview-options/example-seethrough.json +2 -2
  398. package/templates/example-interview-options/example-turn.json +108 -0
  399. package/templates/example-interview-options/fullscreen.json +2 -2
  400. package/templates/example-interview-options/other-explicit.json +2 -2
  401. package/templates/example-interview-options/other-pending.json +2 -2
  402. package/templates/example-interview-options/other-picks.json +2 -2
  403. package/templates/example-invariants/invariants.json +223 -164
  404. package/templates/example-project.json +301 -249
  405. package/templates/example-remesh/.gitignore +6 -0
  406. package/templates/example-remesh/.npmignore +1 -0
  407. package/templates/example-remesh/AGENT-REFERENCE.md +62 -0
  408. package/templates/example-remesh/AGENTS.md +4 -26
  409. package/templates/example-remesh/derived/drafts/remesh/config.json +88 -0
  410. package/templates/example-remesh/derived/drafts/remesh/input/painting_in_rig.png +0 -0
  411. package/templates/example-remesh/derived/drafts/remesh/input/parts/background.png +0 -0
  412. package/templates/example-remesh/derived/drafts/remesh/input/parts/eye_l.png +0 -0
  413. package/templates/example-remesh/derived/drafts/remesh/input/parts/eye_r.png +0 -0
  414. package/templates/example-remesh/derived/drafts/remesh/input/parts/face.png +0 -0
  415. package/templates/example-remesh/derived/drafts/remesh/input/parts/lantern.png +0 -0
  416. package/templates/example-remesh/derived/drafts/remesh/input/parts/torso.png +0 -0
  417. package/templates/example-remesh/derived/drafts/remesh/input/parts.json +188 -0
  418. package/templates/example-remesh/derived/drafts/remesh/input/recomposite_rig.png +0 -0
  419. package/templates/example-remesh/derived/drafts/remesh/interview-requirements.json +8 -0
  420. package/templates/example-remesh/derived/drafts/remesh/out/check/build/run.json +40 -0
  421. package/templates/example-remesh/derived/drafts/remesh/out/check/build/skeleton.atlas +28 -0
  422. package/templates/example-remesh/derived/drafts/remesh/out/check/build/skeleton.json +674 -0
  423. package/templates/example-remesh/derived/drafts/remesh/out/check/build/skeleton.model.json +1072 -0
  424. package/templates/example-remesh/derived/drafts/remesh/out/check/build/skeleton.png +0 -0
  425. package/templates/example-remesh/derived/drafts/remesh/out/images/background.png +0 -0
  426. package/templates/example-remesh/derived/drafts/remesh/out/images/eye_l.png +0 -0
  427. package/templates/example-remesh/derived/drafts/remesh/out/images/eye_r.png +0 -0
  428. package/templates/example-remesh/derived/drafts/remesh/out/images/face.png +0 -0
  429. package/templates/example-remesh/derived/drafts/remesh/out/images/lantern.png +0 -0
  430. package/templates/example-remesh/derived/drafts/remesh/out/images/torso.png +0 -0
  431. package/templates/example-remesh/derived/drafts/remesh/out/mesh_report.json +15 -0
  432. package/templates/example-remesh/derived/drafts/remesh/out/motion.json +137 -0
  433. package/templates/example-remesh/derived/drafts/remesh/out/rig.json +536 -0
  434. package/templates/example-remesh/derived/drafts/remesh/out/run.json +52 -0
  435. package/templates/example-remesh/derived/review/v1/config.json +88 -0
  436. package/templates/example-remesh/derived/review/v1/interview-requirements.json +8 -0
  437. package/templates/example-remesh/derived/review/v1/out/check/build/run.json +44 -0
  438. package/templates/example-remesh/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  439. package/templates/example-remesh/derived/review/v1/out/check/build/skeleton.json +674 -0
  440. package/templates/example-remesh/derived/review/v1/out/check/build/skeleton.model.json +1072 -0
  441. package/templates/example-remesh/derived/review/v1/out/check/build/skeleton.png +0 -0
  442. package/templates/example-remesh/derived/review/v1/out/painting_in_rig.png +0 -0
  443. package/templates/example-remesh/derived/review/v1/out/parts/background.png +0 -0
  444. package/templates/example-remesh/derived/review/v1/out/parts/eye_l.png +0 -0
  445. package/templates/example-remesh/derived/review/v1/out/parts/eye_r.png +0 -0
  446. package/templates/example-remesh/derived/review/v1/out/parts/face.png +0 -0
  447. package/templates/example-remesh/derived/review/v1/out/parts/lantern.png +0 -0
  448. package/templates/example-remesh/derived/review/v1/out/parts/torso.png +0 -0
  449. package/templates/example-remesh/derived/review/v1/out/parts.json +188 -0
  450. package/templates/example-remesh/derived/review/v1/out/rig/images/background.png +0 -0
  451. package/templates/example-remesh/derived/review/v1/out/rig/images/eye_l.png +0 -0
  452. package/templates/example-remesh/derived/review/v1/out/rig/images/eye_r.png +0 -0
  453. package/templates/example-remesh/derived/review/v1/out/rig/images/face.png +0 -0
  454. package/templates/example-remesh/derived/review/v1/out/rig/images/lantern.png +0 -0
  455. package/templates/example-remesh/derived/review/v1/out/rig/images/torso.png +0 -0
  456. package/templates/example-remesh/derived/review/v1/out/rig/mesh_report.json +15 -0
  457. package/templates/example-remesh/derived/review/v1/out/rig/motion.json +137 -0
  458. package/templates/example-remesh/derived/review/v1/out/rig/rig.json +536 -0
  459. package/templates/example-remesh/derived/review/v1/out/rig/run.json +52 -0
  460. package/templates/example-remesh/derived/review/v2/config.json +88 -0
  461. package/templates/example-remesh/derived/review/v2/interview-requirements.json +8 -0
  462. package/templates/example-remesh/derived/review/v2/out/check/build/run.json +44 -0
  463. package/templates/example-remesh/derived/review/v2/out/check/build/skeleton.atlas +28 -0
  464. package/templates/example-remesh/derived/review/v2/out/check/build/skeleton.json +674 -0
  465. package/templates/example-remesh/derived/review/v2/out/check/build/skeleton.model.json +1072 -0
  466. package/templates/example-remesh/derived/review/v2/out/check/build/skeleton.png +0 -0
  467. package/templates/example-remesh/derived/review/v2/out/painting_in_rig.png +0 -0
  468. package/templates/example-remesh/derived/review/v2/out/parts/background.png +0 -0
  469. package/templates/example-remesh/derived/review/v2/out/parts/eye_l.png +0 -0
  470. package/templates/example-remesh/derived/review/v2/out/parts/eye_r.png +0 -0
  471. package/templates/example-remesh/derived/review/v2/out/parts/face.png +0 -0
  472. package/templates/example-remesh/derived/review/v2/out/parts/lantern.png +0 -0
  473. package/templates/example-remesh/derived/review/v2/out/parts/torso.png +0 -0
  474. package/templates/example-remesh/derived/review/v2/out/parts.json +188 -0
  475. package/templates/example-remesh/derived/review/v2/out/rig/images/background.png +0 -0
  476. package/templates/example-remesh/derived/review/v2/out/rig/images/eye_l.png +0 -0
  477. package/templates/example-remesh/derived/review/v2/out/rig/images/eye_r.png +0 -0
  478. package/templates/example-remesh/derived/review/v2/out/rig/images/face.png +0 -0
  479. package/templates/example-remesh/derived/review/v2/out/rig/images/lantern.png +0 -0
  480. package/templates/example-remesh/derived/review/v2/out/rig/images/torso.png +0 -0
  481. package/templates/example-remesh/derived/review/v2/out/rig/mesh_report.json +15 -0
  482. package/templates/example-remesh/derived/review/v2/out/rig/motion.json +137 -0
  483. package/templates/example-remesh/derived/review/v2/out/rig/rig.json +536 -0
  484. package/templates/example-remesh/derived/review/v2/out/rig/run.json +52 -0
  485. package/templates/example-remesh/derived/review/v3/config.json +88 -0
  486. package/templates/example-remesh/derived/review/v3/interview-requirements.json +8 -0
  487. package/templates/example-remesh/derived/review/v3/out/check/build/run.json +44 -0
  488. package/templates/example-remesh/derived/review/v3/out/check/build/skeleton.atlas +28 -0
  489. package/templates/example-remesh/derived/review/v3/out/check/build/skeleton.json +674 -0
  490. package/templates/example-remesh/derived/review/v3/out/check/build/skeleton.model.json +1072 -0
  491. package/templates/example-remesh/derived/review/v3/out/check/build/skeleton.png +0 -0
  492. package/templates/example-remesh/derived/review/v3/out/painting_in_rig.png +0 -0
  493. package/templates/example-remesh/derived/review/v3/out/parts/background.png +0 -0
  494. package/templates/example-remesh/derived/review/v3/out/parts/eye_l.png +0 -0
  495. package/templates/example-remesh/derived/review/v3/out/parts/eye_r.png +0 -0
  496. package/templates/example-remesh/derived/review/v3/out/parts/face.png +0 -0
  497. package/templates/example-remesh/derived/review/v3/out/parts/lantern.png +0 -0
  498. package/templates/example-remesh/derived/review/v3/out/parts/torso.png +0 -0
  499. package/templates/example-remesh/derived/review/v3/out/parts.json +188 -0
  500. package/templates/example-remesh/derived/review/v3/out/rig/images/background.png +0 -0
  501. package/templates/example-remesh/derived/review/v3/out/rig/images/eye_l.png +0 -0
  502. package/templates/example-remesh/derived/review/v3/out/rig/images/eye_r.png +0 -0
  503. package/templates/example-remesh/derived/review/v3/out/rig/images/face.png +0 -0
  504. package/templates/example-remesh/derived/review/v3/out/rig/images/lantern.png +0 -0
  505. package/templates/example-remesh/derived/review/v3/out/rig/images/torso.png +0 -0
  506. package/templates/example-remesh/derived/review/v3/out/rig/mesh_report.json +15 -0
  507. package/templates/example-remesh/derived/review/v3/out/rig/motion.json +137 -0
  508. package/templates/example-remesh/derived/review/v3/out/rig/rig.json +536 -0
  509. package/templates/example-remesh/derived/review/v3/out/rig/run.json +52 -0
  510. package/templates/example-remesh/evidence/captions.json +1 -1
  511. package/templates/example-remesh/evidence/direction/v4.json +1 -1
  512. package/templates/example-remesh/evidence/direction/v5.json +1 -1
  513. package/templates/example-remesh/evidence/direction-input-v4.json +1 -1
  514. package/templates/example-remesh/evidence/direction-input-v5.json +1 -1
  515. package/templates/example-remesh/evidence/interview/assemble.json +1 -1
  516. package/templates/example-remesh/evidence/interview/bones.json +4 -4
  517. package/templates/example-remesh/evidence/interview/camera_depth.json +2 -2
  518. package/templates/example-remesh/evidence/interview/constraints.json +4 -4
  519. package/templates/example-remesh/evidence/interview/meshes.json +4 -4
  520. package/templates/example-remesh/evidence/interview/motion.json +4 -4
  521. package/templates/example-remesh/evidence/interview/post_composition.json +2 -2
  522. package/templates/example-remesh/evidence/interview/post_timing.json +2 -2
  523. package/templates/example-remesh/evidence/interview/reference.json +1 -1
  524. package/templates/example-remesh/evidence/interview/rig_type.json +1 -1
  525. package/templates/example-remesh/evidence/interview/seethrough.json +1 -1
  526. package/templates/example-remesh/evidence/interview/turn.json +108 -0
  527. package/templates/example-remesh/evidence/parts-review.json +1 -1
  528. package/templates/example-remesh/evidence/review-reads/{afe2522be4087f7f2fa7e97746d5f8574b0aedb474245ce2dbce0455e662f041.json → 99ade3eb19d70bd5f727138b3b4876ce86f1e1c22a59b516639bf85593996c32.json} +2 -2
  529. package/templates/example-remesh/evidence/scene/s1.json +2 -2
  530. package/templates/example-remesh/evidence/v1/registration/at-source.json +2 -2
  531. package/templates/example-remesh/evidence/v1/registration/rigc-run-1.json +2 -2
  532. package/templates/example-remesh/evidence/v2/registration/at-source.json +2 -2
  533. package/templates/example-remesh/evidence/v2/registration/rigc-run-1.json +2 -2
  534. package/templates/example-remesh/evidence/v3/registration/at-source.json +2 -2
  535. package/templates/example-remesh/evidence/v3/registration/rigc-run-1.json +2 -2
  536. package/templates/example-remesh/outputs/v1/idle/frames.json +29 -0
  537. package/templates/example-remesh/outputs/v1/idle/idle@1fps/contact.png +0 -0
  538. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0000.png +0 -0
  539. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0001.png +0 -0
  540. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0002.png +0 -0
  541. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0003.png +0 -0
  542. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0004.png +0 -0
  543. package/templates/example-remesh/outputs/v1/out/check/build/run.json +44 -0
  544. package/templates/example-remesh/outputs/v1/out/check/build/skeleton.atlas +28 -0
  545. package/templates/example-remesh/outputs/v1/out/check/build/skeleton.json +674 -0
  546. package/templates/example-remesh/outputs/v1/out/check/build/skeleton.model.json +1072 -0
  547. package/templates/example-remesh/outputs/v1/out/check/build/skeleton.png +0 -0
  548. package/templates/example-remesh/outputs/v1/out/painting_in_rig.png +0 -0
  549. package/templates/example-remesh/outputs/v1/out/parts/background.png +0 -0
  550. package/templates/example-remesh/outputs/v1/out/parts/eye_l.png +0 -0
  551. package/templates/example-remesh/outputs/v1/out/parts/eye_r.png +0 -0
  552. package/templates/example-remesh/outputs/v1/out/parts/face.png +0 -0
  553. package/templates/example-remesh/outputs/v1/out/parts/lantern.png +0 -0
  554. package/templates/example-remesh/outputs/v1/out/parts/torso.png +0 -0
  555. package/templates/example-remesh/outputs/v1/out/parts.json +188 -0
  556. package/templates/example-remesh/outputs/v1/out/rig/images/background.png +0 -0
  557. package/templates/example-remesh/outputs/v1/out/rig/images/eye_l.png +0 -0
  558. package/templates/example-remesh/outputs/v1/out/rig/images/eye_r.png +0 -0
  559. package/templates/example-remesh/outputs/v1/out/rig/images/face.png +0 -0
  560. package/templates/example-remesh/outputs/v1/out/rig/images/lantern.png +0 -0
  561. package/templates/example-remesh/outputs/v1/out/rig/images/torso.png +0 -0
  562. package/templates/example-remesh/outputs/v1/out/rig/mesh_report.json +15 -0
  563. package/templates/example-remesh/outputs/v1/out/rig/motion.json +137 -0
  564. package/templates/example-remesh/outputs/v1/out/rig/rig.json +536 -0
  565. package/templates/example-remesh/outputs/v1/out/rig/run.json +52 -0
  566. package/templates/example-remesh/outputs/v2/idle/frames.json +29 -0
  567. package/templates/example-remesh/outputs/v2/idle/idle@1fps/contact.png +0 -0
  568. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0000.png +0 -0
  569. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0001.png +0 -0
  570. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0002.png +0 -0
  571. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0003.png +0 -0
  572. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0004.png +0 -0
  573. package/templates/example-remesh/outputs/v2/out/check/build/run.json +44 -0
  574. package/templates/example-remesh/outputs/v2/out/check/build/skeleton.atlas +28 -0
  575. package/templates/example-remesh/outputs/v2/out/check/build/skeleton.json +674 -0
  576. package/templates/example-remesh/outputs/v2/out/check/build/skeleton.model.json +1072 -0
  577. package/templates/example-remesh/outputs/v2/out/check/build/skeleton.png +0 -0
  578. package/templates/example-remesh/outputs/v2/out/painting_in_rig.png +0 -0
  579. package/templates/example-remesh/outputs/v2/out/parts/background.png +0 -0
  580. package/templates/example-remesh/outputs/v2/out/parts/eye_l.png +0 -0
  581. package/templates/example-remesh/outputs/v2/out/parts/eye_r.png +0 -0
  582. package/templates/example-remesh/outputs/v2/out/parts/face.png +0 -0
  583. package/templates/example-remesh/outputs/v2/out/parts/lantern.png +0 -0
  584. package/templates/example-remesh/outputs/v2/out/parts/torso.png +0 -0
  585. package/templates/example-remesh/outputs/v2/out/parts.json +188 -0
  586. package/templates/example-remesh/outputs/v2/out/rig/images/background.png +0 -0
  587. package/templates/example-remesh/outputs/v2/out/rig/images/eye_l.png +0 -0
  588. package/templates/example-remesh/outputs/v2/out/rig/images/eye_r.png +0 -0
  589. package/templates/example-remesh/outputs/v2/out/rig/images/face.png +0 -0
  590. package/templates/example-remesh/outputs/v2/out/rig/images/lantern.png +0 -0
  591. package/templates/example-remesh/outputs/v2/out/rig/images/torso.png +0 -0
  592. package/templates/example-remesh/outputs/v2/out/rig/mesh_report.json +15 -0
  593. package/templates/example-remesh/outputs/v2/out/rig/motion.json +137 -0
  594. package/templates/example-remesh/outputs/v2/out/rig/rig.json +536 -0
  595. package/templates/example-remesh/outputs/v2/out/rig/run.json +52 -0
  596. package/templates/example-remesh/outputs/v3/idle/frames.json +29 -0
  597. package/templates/example-remesh/outputs/v3/idle/idle@1fps/contact.png +0 -0
  598. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0000.png +0 -0
  599. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0001.png +0 -0
  600. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0002.png +0 -0
  601. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0003.png +0 -0
  602. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0004.png +0 -0
  603. package/templates/example-remesh/outputs/v3/out/check/build/run.json +44 -0
  604. package/templates/example-remesh/outputs/v3/out/check/build/skeleton.atlas +28 -0
  605. package/templates/example-remesh/outputs/v3/out/check/build/skeleton.json +674 -0
  606. package/templates/example-remesh/outputs/v3/out/check/build/skeleton.model.json +1072 -0
  607. package/templates/example-remesh/outputs/v3/out/check/build/skeleton.png +0 -0
  608. package/templates/example-remesh/outputs/v3/out/painting_in_rig.png +0 -0
  609. package/templates/example-remesh/outputs/v3/out/parts/background.png +0 -0
  610. package/templates/example-remesh/outputs/v3/out/parts/eye_l.png +0 -0
  611. package/templates/example-remesh/outputs/v3/out/parts/eye_r.png +0 -0
  612. package/templates/example-remesh/outputs/v3/out/parts/face.png +0 -0
  613. package/templates/example-remesh/outputs/v3/out/parts/lantern.png +0 -0
  614. package/templates/example-remesh/outputs/v3/out/parts/torso.png +0 -0
  615. package/templates/example-remesh/outputs/v3/out/parts.json +188 -0
  616. package/templates/example-remesh/outputs/v3/out/rig/images/background.png +0 -0
  617. package/templates/example-remesh/outputs/v3/out/rig/images/eye_l.png +0 -0
  618. package/templates/example-remesh/outputs/v3/out/rig/images/eye_r.png +0 -0
  619. package/templates/example-remesh/outputs/v3/out/rig/images/face.png +0 -0
  620. package/templates/example-remesh/outputs/v3/out/rig/images/lantern.png +0 -0
  621. package/templates/example-remesh/outputs/v3/out/rig/images/torso.png +0 -0
  622. package/templates/example-remesh/outputs/v3/out/rig/mesh_report.json +15 -0
  623. package/templates/example-remesh/outputs/v3/out/rig/motion.json +137 -0
  624. package/templates/example-remesh/outputs/v3/out/rig/rig.json +536 -0
  625. package/templates/example-remesh/outputs/v3/out/rig/run.json +52 -0
  626. package/templates/example-remesh/project.json +279 -230
  627. package/templates/example-reopened/project.json +341 -289
  628. package/templates/example-split/captions.json +1 -1
  629. package/templates/project.json +10 -2
package/src/next.ts CHANGED
@@ -32,7 +32,7 @@ import { pausedFrom } from './pause.ts';
32
32
  import { carriedRefusals, findingKey, newFindings } from './refusal-baseline.ts';
33
33
  import { refuse, USAGE_EXIT } from './refusal.ts';
34
34
  import { reopenLapseWarnings } from './reopen-lapses.ts';
35
- import { collectReopens, liveSignoff } from './reopen.ts';
35
+ import { collectReopens, directionReviewClosed, liveSignoff } from './reopen.ts';
36
36
  import { acceptedReviewVerdict } from './review.ts';
37
37
  import {
38
38
  advanceOrder,
@@ -53,7 +53,9 @@ import {
53
53
  stageOfStep,
54
54
  } from './stages.ts';
55
55
  import type { Json, JsonObject } from './templates.ts';
56
- import { sceneCurrentAt } from './scene.ts';
56
+ import { sceneCurrentAt, sceneRig, SceneError } from './scene.ts';
57
+ import { depthPlanMoves } from './rig-version.ts';
58
+ import { resolveAgentCitationSpec } from './scene-authority.ts';
57
59
 
58
60
  export const NEXT_SCHEMA = 'rig-create/next@1';
59
61
 
@@ -71,7 +73,7 @@ export interface NextRefusal {
71
73
  }
72
74
 
73
75
  export interface NextReviewAct {
74
- kind: 'parts-verdict' | 'interview-picks' | 'review-verdict' | 'signoff' | 'signoff-checkpoint';
76
+ kind: 'parts-verdict' | 'interview-picks' | 'review-verdict' | 'signoff' | 'signoff-checkpoint' | 'reopen';
75
77
  stage: string;
76
78
  draft_id?: string;
77
79
  question_id?: string;
@@ -202,6 +204,76 @@ function optionCommand(id: string, dir: string): string {
202
204
  return `rig-create interview-options ${shellWord(id)} ${shellWord(dir)} --file '<option-set.json>'`;
203
205
  }
204
206
 
207
+ /** The person acts in Review; the agent only hosts and ingests its exported act. */
208
+ function reviewCommands(dir: string, project: JsonObject, move: NextMove): NextMove[] {
209
+ const act = move.review_act;
210
+ if (move.role !== 'human' || move.unanswered_by_record || move.field === 'pauses' || !act) return [move];
211
+ let selector: string;
212
+ let writer: string;
213
+ if (act.kind === 'reopen') {
214
+ selector = '--plan';
215
+ writer = `reopen ${act.stage}`;
216
+ } else if (act.kind === 'interview-picks' && act.question_id) {
217
+ selector = `--question ${shellWord(act.question_id)}`;
218
+ writer = `interview-answer ${shellWord(act.question_id)}`;
219
+ } else if (act.kind === 'signoff' && ['interview', 'plan-approved', 'rigging-interview', 'post-interview', 'direction-review'].includes(act.stage)) {
220
+ selector = '--plan';
221
+ writer = `signoff ${act.stage}`;
222
+ } else if (act.kind === 'parts-verdict' && act.draft_id) {
223
+ selector = `--draft ${shellWord(act.draft_id)}`;
224
+ writer = 'parts-review';
225
+ } else if (act.kind === 'signoff' && act.stage === 'parts-review' && act.draft_id) {
226
+ selector = `--draft ${shellWord(act.draft_id)}`;
227
+ const structure = partsStructureSnapshot(dir, project, act.draft_id);
228
+ writer = `signoff parts-review --draft ${shellWord(act.draft_id)} --structure-file ${shellWord(structure.path)}`;
229
+ } else if (act.kind === 'signoff' && act.stage === 'rig-review' && act.version_id) {
230
+ selector = `--rig ${shellWord(act.version_id.slice(1))}`;
231
+ writer = 'signoff rig-review';
232
+ } else if (['rig-review', 'direction-review'].includes(act.stage) && act.kind === 'review-verdict' && act.version_id) {
233
+ const n = act.version_id.slice(1);
234
+ selector = `--rig ${shellWord(n)}`;
235
+ writer = `review ${shellWord(n)}`;
236
+ } else return [move];
237
+ const agent = (command: string, description: string): NextMove => ({
238
+ role: 'agent', field: move.field, awaits: move.awaits, command, act: description,
239
+ });
240
+ const root = shellWord(dir);
241
+ return [
242
+ agent(`rig-create job open ${root} ${selector} --reviewer '<reviewer>' --role owner`, 'host this Review page; keep the host running in a separate terminal until job close'),
243
+ move,
244
+ agent(`rig-create job acts ${root} --json`, `after the person submits in Review, list exported acts and use the matching actId below${act.stage === 'parts-review' ? '; run its reported preconditions before ingestion (parts-review signoff includes structure-snapshot)' : ''}`),
245
+ agent(`rig-create ${writer} ${root} --from-review '<actId>'`, 'ingest the matching exported Review act; never supply the human answer or words'),
246
+ agent(`rig-create job close ${root}`, 'after successful ingestion, close this job before opening the next Review page'),
247
+ ];
248
+ }
249
+
250
+ function sceneWriteCommand(dir: string, project: JsonObject, rigN: string): string {
251
+ let flags = ` --background '<background.png>'`;
252
+ const item = collectItems(project, { collection: loadCollection(dir) }).find(item => item.id === 'post_composition');
253
+ if (item && (item.state.state === 'user' || item.state.state === 'delegated')) {
254
+ const answer = item.state.answer;
255
+ const citation = { guide: 'post_composition', asks: ['post_composition'],
256
+ ...(item.state.state === 'delegated' ? { delegated: true } : { quote: answer.verbatim! }) };
257
+ try {
258
+ const spec = resolveAgentCitationSpec(dir, project, citation);
259
+ const stage = sceneRig(dir, project, Number(rigN)).stage;
260
+ for (const role of ['background', 'foreground'] as const) {
261
+ const plate = spec[role];
262
+ if (!plate) continue;
263
+ if (role === 'foreground') flags += ` --foreground '<foreground.png>'`;
264
+ const { x, y, width, height } = plate.rect;
265
+ if (x !== stage.x || y !== stage.y || width !== stage.width || height !== stage.height) {
266
+ flags += ` --${role}-rect ${shellWord([x, y, width, height].join(','))}`;
267
+ }
268
+ }
269
+ } catch (error) {
270
+ if (!(error instanceof SceneError)) throw error;
271
+ // The scene writer reports the existing named refusal for an unresolved choice.
272
+ }
273
+ }
274
+ return `rig-create scene write ${shellWord(dir)} --rig ${shellWord(rigN)}${flags} --citations-file '<scene-citations.json>'`;
275
+ }
276
+
205
277
  function candidateAdvance(
206
278
  dir: string,
207
279
  project: JsonObject,
@@ -623,18 +695,12 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
623
695
  if (kind === 'post') {
624
696
  // Match the direction writer's authoring gate, including earlier
625
697
  // accepted verdicts that a later bounce does not itself reopen.
626
- const reopens = collectReopens(project, []);
627
- const closed = collectSignoffs(project, []).some(s => s.stage === 'direction-review'
628
- && s.checkpoint === null && liveSignoff(reopens, s.stage, s.at))
629
- || versions.some(v => v.kind === 'post' && asArray(v.verdicts).filter(isObject).some(d =>
630
- d.review === 'direction-review' && d.verdict === 'accepted'
631
- && liveSignoff(reopens, 'direction-review', Date.parse(String(d.at)))));
632
- if (closed) {
698
+ if (directionReviewClosed(project)) {
633
699
  const target = 'reopens[stage=direction-review]';
634
700
  addAwait(target);
635
701
  moves.push({ role: 'human', field: 'reopens', awaits: target,
636
- command: `rig-create reopen direction-review ${shellWord(dir)} --by '<human>' --verbatim-file '<absolute-human-words-file>' --source '<reopen-act-id>'`,
637
- act: 'Until create#493, an agent may type this human reopen only from Review host raw export act@4: save its unchanged nonempty value.words byte-for-byte to an absolute verbatim-file path and name actId with --source. Empty/missing words: STOP; the agent never supplies words. Do not use job fetch-act (it rejects act@4). Create cannot ingest Review reopen acts yet.' });
702
+ command: null, review_act: { kind: 'reopen', stage: 'direction-review' },
703
+ act: 'reopen direction-review in Review, then ingest the exported reopen act before writing the replacement post' });
638
704
  continue;
639
705
  }
640
706
  }
@@ -648,7 +714,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
648
714
  command: `rig-create ${writer} ${shellWord(dir)} ${inputs.replace(/<[^>]+>/g, shellWord)} ${refs.map(r => `--answers ${r.version}:${r.verdict}`).join(' ')}`,
649
715
  act: `build the next ${kind} version with ${writer}, recording answers_feedback ${JSON.stringify(refs)}` });
650
716
  }
651
- if (moves.length > 0) return { schema: NEXT_SCHEMA, project_id: String(project.name ?? ''), stage, effective_stage: effectiveStage, accepted: false, refusals, ...warningFields, awaits: awaitsList, moves };
717
+ if (moves.length > 0) return { schema: NEXT_SCHEMA, project_id: String(project.name ?? ''), stage, effective_stage: effectiveStage, accepted: false, refusals, ...warningFields, awaits: awaitsList, moves: moves.flatMap(move => reviewCommands(dir, project, move)) };
652
718
  }
653
719
  const recordedLapseTargets = new Set<string>();
654
720
  const steps = asArray(isObject(project.plan) ? project.plan.steps : undefined).filter(isObject);
@@ -805,6 +871,12 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
805
871
  const splitOrder = hasStageOrder(project);
806
872
  const drafts = asArray(project.drafts).filter(isObject);
807
873
  const versions = asArray(project.versions).filter(isObject);
874
+ if (effectiveStage === 'rigging-interview' && depthPlanMoves(project, collection).length > 0
875
+ && !steps.some(s => s.id === 'turn' && s.phase === 'rig')) {
876
+ addAwait('plan.steps[turn]');
877
+ moves.push({ role: 'agent', field: 'plan.steps[turn]', awaits: 'plan.steps[turn]', command: null,
878
+ act: 'Draft plan add turn --phase rig --rests-on turn before the rig steps, record the chosen depth route and reason in its text, with a bar that reads the producer depth reports; approve it at rigging-interview.' });
879
+ }
808
880
 
809
881
  if (stage === PAUSED_STAGE) {
810
882
  const resumeTarget = pausedFrom(project);
@@ -880,9 +952,9 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
880
952
  }
881
953
 
882
954
  const planIds = effectiveStage === 'rigging-interview' ? ['bones', 'meshes', 'constraints', 'motion']
883
- : effectiveStage === 'post-interview' ? ['camera', 'timing'] : ['seethrough', 'assemble'];
955
+ : effectiveStage === 'post-interview' ? ['camera', 'timing', 'composition'] : ['seethrough', 'assemble'];
884
956
  const missingPlanIds = planIds.filter(id => {
885
- const guide = id === 'camera' ? 'camera_depth' : id === 'timing' ? 'post_timing' : id;
957
+ const guide = id === 'camera' ? 'camera_depth' : id === 'timing' ? 'post_timing' : id === 'composition' ? 'post_composition' : id;
886
958
  const phase = effectiveStage === 'post-interview' ? 'post' : 'rig';
887
959
  return !steps.some(step => step.phase === phase && (step.id === id
888
960
  || phase === 'post' && asArray(step.rests_on).includes(guide)));
@@ -891,7 +963,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
891
963
  if (needsPlanSteps) {
892
964
  addAwait('plan.steps');
893
965
  for (const [index, id] of missingPlanIds.entries()) {
894
- const guideId = id === 'camera' ? 'camera_depth' : id === 'timing' ? 'post_timing' : id;
966
+ const guideId = id === 'camera' ? 'camera_depth' : id === 'timing' ? 'post_timing' : id === 'composition' ? 'post_composition' : id;
895
967
  const item = stageItems.find(item => item.id === guideId);
896
968
  if (!item || item.state.state === 'silent' || (item.state.state === 'delegated' && !item.state.decided)) continue;
897
969
  const order = Math.max(0, ...steps.map(step => Number(step.order) || 0)) + index + 1;
@@ -902,6 +974,10 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
902
974
  }
903
975
  }
904
976
 
977
+ const missingStepNames = missingPlanIds.length === planIds.length ? '' : `${missingPlanIds.join(', ')} `;
978
+ const missingStepKind = effectiveStage === 'post-interview' ? 'post' : 'rig';
979
+ const missingPlanReason = `plan.steps has no ${missingStepNames}${missingStepKind} step${missingPlanIds.length === 1 ? '' : 's'}`;
980
+
905
981
  const signoffAwait = `signoffs[stage=${effectiveStage}]`;
906
982
  if (!hasLiveStageSignoff(effectiveStage) && !recordedLapseTargets.has(signoffAwait)) {
907
983
  addAwait(signoffAwait);
@@ -912,10 +988,10 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
912
988
  command: null,
913
989
  act: needsPlanSteps
914
990
  ? effectiveStage === 'rigging-interview'
915
- ? 'review-tool act signoff for stage rigging-interview (unanswered by record: plan.steps has no rig steps approved at rigging-interview)'
916
- : `review-tool act signoff for stage ${effectiveStage} (unanswered by record: ${effectiveStage === 'post-interview' ? 'plan.steps has no post steps' : steps.length === 0 ? 'plan.steps is empty' : 'plan.steps has uncovered parts guides'} in project.json)`
991
+ ? `review-tool act signoff for stage rigging-interview (unanswered by record: ${missingPlanReason} approved at rigging-interview)`
992
+ : `review-tool act signoff for stage ${effectiveStage} (unanswered by record: ${effectiveStage === 'post-interview' ? missingPlanReason : steps.length === 0 ? 'plan.steps is empty' : 'plan.steps has uncovered parts guides'} in project.json)`
917
993
  : effectiveStage === 'interview'
918
- ? 'review-tool act signoff for stage interview on the record page with job open --plan (source-linked Review); ingest signoff interview --from-review <actId>, then advance plan-approved'
994
+ ? 'review-tool act signoff for stage interview on the record page with job open --plan; ingest signoff interview --from-review <actId>, then advance plan-approved'
919
995
  : `review-tool act signoff for stage ${effectiveStage}`,
920
996
  review_act: {
921
997
  kind: 'signoff',
@@ -1163,6 +1239,10 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1163
1239
  }
1164
1240
  }
1165
1241
  } else if (effectiveStage === 'rigging' || effectiveStage === 'rig-review') {
1242
+ if (effectiveStage === 'rigging') for (const move of depthPlanMoves(project, collection)) {
1243
+ addAwait(move.awaits);
1244
+ moves.push(move);
1245
+ }
1166
1246
  const rigSteps = steps.filter(
1167
1247
  s => (s.phase === 'rig' || s.phase === 'post') && stageOfStep(s.phase, String(s.id)) === 'rigging',
1168
1248
  );
@@ -1389,7 +1469,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1389
1469
  } else if (currentScene === undefined) {
1390
1470
  addAwait('scenes[n=1]');
1391
1471
  moves.push({ role: 'agent', field: 'scenes', awaits: 'scenes[n=1]',
1392
- command: `rig-create scene write ${shellWord(dir)} --rig ${shellWord(rigN)} --background '<background.png>' --citations-file '<scene-citations.json>'`,
1472
+ command: sceneWriteCommand(dir, project, rigN),
1393
1473
  act: 'author scene inputs matching the current post_composition Review choice, then write the scene' });
1394
1474
  } else {
1395
1475
  addAwait(`versions[n=${nextPostN}]`);
@@ -1432,7 +1512,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1432
1512
  field: `versions[v${postN}].verdicts`,
1433
1513
  awaits: verdictAwait,
1434
1514
  command: null,
1435
- act: `review-tool act review-verdict for versions[v${postN}] (direction-review) on the post page: job open --rig ${postN}; ingest with review ${postN} --from-review <actId>; then request record-page sign-off with job open --plan (source-linked Review)`,
1515
+ act: `review-tool act review-verdict for versions[v${postN}] (direction-review) on the post page: job open --rig ${postN}; ingest with review ${postN} --from-review <actId>; then request record-page sign-off with job open --plan`,
1436
1516
  review_act: {
1437
1517
  kind: 'review-verdict',
1438
1518
  stage: 'direction-review',
@@ -1454,8 +1534,8 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1454
1534
  command: null,
1455
1535
  act:
1456
1536
  postN === null
1457
- ? `after recording the current post and accepted direction verdict, request review-tool act signoff for direction-review on the record page with job open --plan (source-linked Review; unanswered by record: ${scenes.length === 0 ? 'scenes[n=1] and ' : ''}versions[n=${nextPostN}] are not recorded in project.json)`
1458
- : `after ingesting the accepted direction-review verdict for v${postN}, request review-tool act signoff on the record page with job open --plan (source-linked Review), ingest signoff direction-review --from-review <actId>, then advance accepted`,
1537
+ ? `after recording the current post and accepted direction verdict, request review-tool act signoff for direction-review on the record page with job open --plan (unanswered by record: ${scenes.length === 0 ? 'scenes[n=1] and ' : ''}versions[n=${nextPostN}] are not recorded in project.json)`
1538
+ : `after ingesting the accepted direction-review verdict for v${postN}, request review-tool act signoff on the record page with job open --plan, ingest signoff direction-review --from-review <actId>, then advance accepted`,
1459
1539
  review_act: {
1460
1540
  kind: 'signoff',
1461
1541
  stage: 'direction-review',
@@ -1503,6 +1583,12 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1503
1583
  });
1504
1584
  }
1505
1585
 
1586
+ const runnableMoves = moves.flatMap(move => {
1587
+ if (move.review_act?.stage === 'direction-review' && move.review_act.kind === 'signoff'
1588
+ && moves.some(other => other.review_act?.stage === 'direction-review' && other.review_act.kind === 'review-verdict')) return [move];
1589
+ return reviewCommands(dir, project, move);
1590
+ });
1591
+
1506
1592
  return {
1507
1593
  schema: NEXT_SCHEMA,
1508
1594
  project_id: String(project.name ?? ''),
@@ -1512,7 +1598,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1512
1598
  refusals,
1513
1599
  ...warningFields,
1514
1600
  awaits: awaitsList,
1515
- moves,
1601
+ moves: runnableMoves,
1516
1602
  };
1517
1603
  }
1518
1604
 
@@ -3,12 +3,11 @@ import { assertPartsCliArgs, assertPartsReadDraft, decodePartsRead, partsReadFin
3
3
  import { randomUUID } from 'node:crypto';
4
4
  import { closeSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
5
5
  import { dirname, join, resolve } from 'node:path';
6
- import { fileURLToPath } from 'node:url';
7
6
  import { readProject } from './feedback.ts';
8
7
  import { readPartsReview, ReviewReadError, storeReviewRead, type ReviewReadRunner } from './review-read.ts';
9
- import { acquireBoundJobWrite, jobRuntimeExecArgv } from './job-writer.ts';
8
+ import { acquireBoundJobWrite } from './job-writer.ts';
10
9
  import { acquireJobLock, jobHash, readAcknowledgedPublication, readWriterBinding } from './job-outbox.ts';
11
- import { decodeReviewAct, reviewActFindings, reviewActTransport, reviewActVerbatim } from './review-act.ts';
10
+ import { decodeReviewAct, fetchReviewActBytes, reviewActFindings, reviewActTransport, reviewActVerbatim } from './review-act.ts';
12
11
  import { assertPartsActSource, partsActDraftHash, partsActFindings, partsActReceipt } from './parts-act.ts';
13
12
  import { newRefusals } from './refusal-baseline.ts';
14
13
  import { refuse, USAGE_EXIT } from './refusal.ts';
@@ -58,14 +57,8 @@ export function partsReviewCommand(args: string[], now: number, hooks: PartsRevi
58
57
  let committed = false;
59
58
  const temporary = join(root, `.parts-review-${randomUUID()}.tmp`);
60
59
  try {
61
- const transport = { ...reviewActTransport(root, actId!), kind: 'parts-verdict' };
62
- const child = Bun.spawnSync([process.execPath, ...jobRuntimeExecArgv(), fileURLToPath(new URL('./review-act-runtime.ts', import.meta.url))], {
63
- stdin: Buffer.from(JSON.stringify(transport)), stdout: 'pipe', stderr: 'pipe',
64
- });
65
- let response: { ok: boolean; bytes: string; code: string; message: string };
66
- try { response = JSON.parse(child.stdout.toString()); }
67
- catch { return refuse('REVIEW_ACT_FETCH_REFUSED', 'project.json.review_acts: fetch adapter failed; restore the live Review job'); }
68
- if (!response.ok || child.exitCode) refuse(response.code, response.message);
60
+ const transport = { ...reviewActTransport(root, actId!), kind: 'parts-verdict' as const };
61
+ const response = { bytes: fetchReviewActBytes(transport) };
69
62
  const act = decodeReviewAct(response.bytes, 'parts-verdict');
70
63
  if (Date.parse(act.at) > now) refuse('REVIEW_ACT_INVALID', 'project.json.review_acts: act is dated in the future; restore the clock before recording');
71
64
  const { file } = readProject(root);
package/src/reopen.ts CHANGED
@@ -1,9 +1,15 @@
1
1
  import { writeFileSync } from 'node:fs';
2
+ import { readFileSync } from './check-reads.ts';
3
+ import { isDeepStrictEqual } from 'node:util';
2
4
  import { resolve } from 'node:path';
3
5
 
4
- import { asArray, asString, isObject, type Finding } from './check.ts';
6
+ import { asArray, asString, collectSignoffs, isObject, type Finding } from './check.ts';
5
7
  import { collectAmendments } from './amend.ts';
6
8
  import { readProject } from './feedback.ts';
9
+ import { jobHash } from './job-outbox.ts';
10
+ import { acquireBoundJobWrite } from './job-writer.ts';
11
+ import { assertActSubjectDeclared, decodeReviewAct, fetchReviewActBytes, reviewActFindings, reviewActTransport, type ReviewActTransport, type ReopenAct } from './review-act.ts';
12
+ import { stepHash } from './step-hash.ts';
7
13
  import { readVerbatim } from './record-input.ts';
8
14
  import { refuse, USAGE_EXIT } from './refusal.ts';
9
15
  import { newRefusals } from './refusal-baseline.ts';
@@ -77,6 +83,16 @@ function reachedIndex(project: JsonObject, at: number, fromStage: string): numbe
77
83
  return reached;
78
84
  }
79
85
 
86
+ /** An acceptance remains authoring authority until an explicit reopen supersedes it. */
87
+ export function directionReviewClosed(project: JsonObject): boolean {
88
+ const reopens = collectReopens(project, []);
89
+ return collectSignoffs(project, []).some(signoff => signoff.stage === 'direction-review'
90
+ && signoff.checkpoint === null && liveSignoff(reopens, signoff.stage, signoff.at))
91
+ || asArray(project.versions).filter(isObject).some(version => version.kind === 'post'
92
+ && asArray(version.verdicts).filter(isObject).some(verdict => verdict.review === 'direction-review'
93
+ && verdict.verdict === 'accepted' && liveSignoff(reopens, 'direction-review', Date.parse(String(verdict.at)))));
94
+ }
95
+
80
96
  /** Each reopen invalidates its suffix; a later, narrower reopen cannot resurrect an earlier suffix. */
81
97
  export function reopenTime(reopens: readonly Reopen[], stage: string): number {
82
98
  return Math.max(-Infinity, ...reopens.filter(r => stageIndex(r.stage) <= stageIndex(stage)).map(r => r.at));
@@ -94,38 +110,77 @@ export function liveSignoff(reopens: readonly Reopen[], stage: string, at: numbe
94
110
 
95
111
  export const REOPEN_HELP = `reopen:
96
112
  <stage> [<project dir>] record a human backward move and set project.stage
113
+ --from-review <actId> ingest the exported Review reopen (excludes --by, --verbatim-file and --source)
97
114
  --by <who> human signer (agent is refused)
98
115
  --verbatim-file <file> unchanged UTF-8 words; relative to the current working directory, not the project; or - for stdin (default)
99
116
  --source <text> optional origin of the words, separate from verbatim
100
117
  --json print the reopen record
101
118
  The clock supplies at; sign-offs and versions remain history.`;
102
119
 
103
- export function reopenCommand(args: string[], now: number): { stdout: string; exit: number } {
120
+ export function reopenCommand(args: string[], now: number, hooks: { fetch?: (transport: ReviewActTransport) => { bytes: string } } = {}): { stdout: string; exit: number } {
104
121
  const opts: Record<string, string> = {};
105
122
  const positional: string[] = [];
106
123
  let json = false;
107
124
  for (let i = 0; i < args.length; i++) {
108
125
  const arg = args[i] as string;
109
126
  if (arg === '--json') json = true;
110
- else if (['--by', '--verbatim-file', '--source'].includes(arg)) {
127
+ else if (['--by', '--verbatim-file', '--source', '--from-review'].includes(arg)) {
111
128
  const value = args[++i];
112
129
  if (arg in opts || value === undefined || value === '') refuse('REOPEN_OPTION_INVALID', `reopens: ${arg} needs one non-empty value; supply it once`, USAGE_EXIT);
113
130
  opts[arg] = value;
114
131
  } else if (arg.startsWith('-')) refuse('UNKNOWN_OPTION', `reopens: unsupported ${arg}; see reopen help`, USAGE_EXIT);
115
132
  else positional.push(arg);
116
133
  }
117
- if (positional.length < 1 || positional.length > 2 || opts['--by'] === undefined) refuse('REOPEN_OPTION_INVALID', 'reopens: supply a stage, --by and one optional project directory', USAGE_EXIT);
134
+ const actId = opts['--from-review'];
135
+ if (positional.length < 1 || positional.length > 2 || actId === undefined && opts['--by'] === undefined) refuse('REOPEN_OPTION_INVALID', 'reopens: supply a stage, --by or --from-review, and one optional project directory', USAGE_EXIT);
136
+ if (actId !== undefined && ['--by', '--verbatim-file', '--source'].some(flag => opts[flag] !== undefined)) {
137
+ refuse('REOPEN_OPTION_INVALID', 'project.json.reopens: --from-review excludes --by, --verbatim-file and --source; use the exported human values', USAGE_EXIT);
138
+ }
118
139
  const dir = resolve(positional[1] ?? process.cwd());
140
+ const release = actId === undefined ? () => {} : acquireBoundJobWrite(dir);
141
+ try { return recordReopen(dir, positional[0]!, opts, json, now, hooks); }
142
+ finally { release(); }
143
+ }
144
+
145
+ function recordReopen(dir: string, stage: string, opts: Record<string, string>, json: boolean, now: number,
146
+ hooks: { fetch?: (transport: ReviewActTransport) => { bytes: string } }): { stdout: string; exit: number } {
119
147
  const { file, project } = readProject(dir);
148
+ const original = readFileSync(file);
149
+ let review: { act: ReopenAct; bytes: string } | undefined;
150
+ const result = (entry: JsonObject): { stdout: string; exit: number } => ({ stdout: json ? JSON.stringify(entry, null, 2) : `reopen: ${String(entry.stage)} by ${String(entry.by)} at ${String(entry.at)}`, exit: 0 });
151
+ const actId = opts['--from-review'];
152
+ if (actId !== undefined) {
153
+ const invalid = reviewActFindings(project)[0];
154
+ if (invalid) refuse(invalid.code, invalid.message);
155
+ const transport: ReviewActTransport = { ...reviewActTransport(dir, actId), kind: 'reopen' };
156
+ const bytes = hooks.fetch ? hooks.fetch(transport).bytes : fetchReviewActBytes(transport);
157
+ const act = decodeReviewAct(bytes, 'reopen');
158
+ if (act.jobId !== transport.jobId || act.actId !== actId || Date.parse(act.at) > now) {
159
+ refuse('REVIEW_ACT_INVALID', 'project.json.reopens: fetched act identity or date differs from the request; request the correct reopen act');
160
+ }
161
+ if (act.value.stage !== stage) refuse('REVIEW_ACT_KIND_MISMATCH', `project.json.reopens: act reopens ${act.value.stage}, not ${stage}; invoke reopen for the exported stage`);
162
+ const existing = asArray(project.review_acts).filter(isObject).find(entry => entry.jobId === act.jobId && entry.actId === actId);
163
+ if (existing) {
164
+ if (existing.kind !== 'reopen' || existing.bytes !== bytes) refuse('REVIEW_ACT_REPLAY_CONFLICT', 'project.json.review_acts: immutable reopen act changed; restore the original receipt');
165
+ return result(asArray(project.reopens)[Number(existing.reopen)] as JsonObject);
166
+ }
167
+ if (act.source.projectHash !== jobHash(original) || !isDeepStrictEqual(act.source.plan.steps,
168
+ asArray(isObject(project.plan) ? project.plan.steps : undefined).map(raw => ({ id: isObject(raw) ? raw.id : null, hash: isObject(raw) ? stepHash(raw) : null })))) {
169
+ refuse('REVIEW_ACT_SOURCE_STALE', 'project.json.reopens: displayed record or plan changed; request a reopen on the current record');
170
+ }
171
+ assertActSubjectDeclared(dir, act, 'project.json.reopens');
172
+ review = { act, bytes };
173
+ }
120
174
  const before = structuredClone(project);
121
175
  const steps = asArray(isObject(project.plan) ? project.plan.steps : undefined);
122
176
  if (steps.some(s => !isObject(s) || typeof s.id !== 'string' || (s.phase !== 'rig' && s.phase !== 'post'))) {
123
177
  refuse('REOPEN_MALFORMED', 'plan.steps: each step needs id and phase; restore the plan before reopening');
124
178
  }
125
179
  const affected = steps.filter((s): s is JsonObject => isObject(s)
126
- && stageIndex(stageOfStep(s.phase as 'rig' | 'post', s.id as string)) >= stageIndex(positional[0] as string));
127
- const entry: JsonObject = { from_stage: project.stage ?? null, steps_before: affected.map(s => ({ id: s.id as string, ...(s.status === undefined ? {} : { status: s.status }) })), stage: positional[0] as string, by: opts['--by'], at: new Date(now).toISOString(), verbatim: '' };
128
- if (opts['--source'] !== undefined) entry.source = opts['--source'];
180
+ && stageIndex(stageOfStep(s.phase as 'rig' | 'post', s.id as string)) >= stageIndex(stage));
181
+ const entry: JsonObject = { from_stage: project.stage ?? null, steps_before: affected.map(s => ({ id: s.id as string, ...(s.status === undefined ? {} : { status: s.status }) })), stage, by: review?.act.authority.reviewer.id ?? opts['--by']!, at: review?.act.at ?? new Date(now).toISOString(), verbatim: '' };
182
+ if (review) entry.source = `review act ${review.act.jobId}/${review.act.actId}`;
183
+ else if (opts['--source'] !== undefined) entry.source = opts['--source'];
129
184
  const refusals: Finding[] = [];
130
185
  // Validate against the original reached stage before moving it backwards.
131
186
  const candidate = { ...project, reopens: [...asArray(project.reopens), entry] };
@@ -133,12 +188,20 @@ export function reopenCommand(args: string[], now: number): { stdout: string; ex
133
188
  collectReopens(candidate, refusals);
134
189
  const first = refusals[0];
135
190
  if (first !== undefined) refuse(first.code, first.message);
136
- entry.verbatim = readVerbatim(opts['--verbatim-file'] ?? '-');
191
+ entry.verbatim = review ? review.act.value.words : readVerbatim(opts['--verbatim-file'] ?? '-');
137
192
  for (const step of affected) step.status = 'pending';
138
193
  project.reopens = candidate.reopens;
139
194
  project.stage = entry.stage;
195
+ if (review) {
196
+ project.review_acts = [...asArray(project.review_acts), { schema: 'rig-create/review-act@1', kind: 'reopen',
197
+ jobId: review.act.jobId, actId: review.act.actId, reopen: asArray(project.reopens).length - 1,
198
+ bytes: review.bytes, sha256: jobHash(review.bytes), version_hash: jobHash(JSON.stringify(entry)) }];
199
+ const invalid = reviewActFindings(project)[0];
200
+ if (invalid) refuse(invalid.code, invalid.message);
201
+ }
140
202
  const rejected = newRefusals(dir, before, project, { now })[0];
141
203
  if (rejected !== undefined) refuse(rejected.code, rejected.message);
204
+ if (review && !readFileSync(file).equals(original)) refuse('REVIEW_ACT_SOURCE_STALE', 'project.json.reopens: record changed during fetch; retry on the current record');
142
205
  writeFileSync(file, `${JSON.stringify(project, null, 2)}\n`);
143
- return { stdout: json ? JSON.stringify(entry, null, 2) : `reopen: ${String(entry.stage)} by ${String(entry.by)} at ${String(entry.at)}`, exit: 0 };
206
+ return result(entry);
144
207
  }
package/src/review-act.ts CHANGED
@@ -3,6 +3,8 @@ import { PARTS_CLI_RECEIPT } from './parts-verdict-record.ts';
3
3
  import { randomUUID } from 'node:crypto';
4
4
  import { readFileSync, realpathSync } from './check-reads.ts';
5
5
  import { dirname, join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { jobRuntimeExecArgv } from './job-writer.ts';
6
8
  import { isDeepStrictEqual } from 'node:util';
7
9
  import { JOB_COMMENTS_ACT_SCHEMA, parseCommentsAct, parseRecordAct, projectComments,
8
10
  type JobAct, type JobCommentPartsAnchor, type JobCommentsAct, type JobModelSourceBinding, type JobRigStill, type RecordAct } from '@rig-c/review/job-host';
@@ -28,6 +30,9 @@ export type PartsIssue = {
28
30
  };
29
31
  /** Review's JobAct now includes comments; legacy adapters keep their original source guarantees. */
30
32
  type LegacyJobAct = Exclude<JobAct, { schema: typeof JOB_COMMENTS_ACT_SCHEMA }>;
33
+ export type ReopenAct = Extract<RecordAct, { kind: 'reopen' }>;
34
+ export type ReviewActKind = 'review-verdict' | 'parts-verdict' | 'interview-picks' | 'checkpoint' | 'signoff' | 'reopen';
35
+ export type DecodedReviewAct = ReviewVerdictAct | PartsVerdictAct | InterviewPicksAct | CheckpointAct | SignoffAct | ReopenAct;
31
36
  export type InterviewPicksAct = Extract<LegacyJobAct | RecordAct, { kind: 'interview-picks' }>;
32
37
  export type PartsVerdictActV2 = Extract<LegacyJobAct, { kind: 'parts-verdict' }>;
33
38
  export type PartsVerdictActV5 = Omit<PartsVerdictActV2, 'schema' | 'value'> & {
@@ -88,7 +93,7 @@ function failure(code: string, detail: string): never {
88
93
  }
89
94
 
90
95
  /** The shared decoder validates grammar; Create separately admits its existing source adapters. */
91
- function decodeCommentsReviewAct(raw: JsonObject, kind: 'review-verdict' | 'parts-verdict' | 'interview-picks' | 'checkpoint' | 'signoff'): ReviewVerdictAct | PartsVerdictAct | CheckpointAct | SignoffAct {
96
+ function decodeCommentsReviewAct(raw: JsonObject, kind: ReviewActKind): ReviewVerdictAct | PartsVerdictAct | CheckpointAct | SignoffAct {
92
97
  if (kind === 'interview-picks' || raw.kind === 'interview-picks') failure('REVIEW_ACT_KIND_MISMATCH', 'comments acts do not carry interview answers');
93
98
  let act: JobCommentsAct;
94
99
  try { act = parseCommentsAct(raw); }
@@ -151,18 +156,22 @@ export function decodeReviewAct(bytes: string, kind: 'interview-picks'): Intervi
151
156
  export function decodeReviewAct(bytes: string, kind: 'parts-verdict'): PartsVerdictAct;
152
157
  export function decodeReviewAct(bytes: string, kind: 'checkpoint'): CheckpointAct;
153
158
  export function decodeReviewAct(bytes: string, kind: 'signoff'): SignoffAct;
154
- export function decodeReviewAct(bytes: string, kind: 'review-verdict' | 'parts-verdict' | 'interview-picks' | 'checkpoint' | 'signoff'): ReviewVerdictAct | PartsVerdictAct | InterviewPicksAct | CheckpointAct | SignoffAct;
155
- export function decodeReviewAct(bytes: string, kind: 'review-verdict' | 'parts-verdict' | 'interview-picks' | 'checkpoint' | 'signoff' = 'review-verdict'): ReviewVerdictAct | PartsVerdictAct | InterviewPicksAct | CheckpointAct | SignoffAct {
159
+ export function decodeReviewAct(bytes: string, kind: 'reopen'): ReopenAct;
160
+ export function decodeReviewAct(bytes: string, kind: ReviewActKind): DecodedReviewAct;
161
+ export function decodeReviewAct(bytes: string, kind: ReviewActKind = 'review-verdict'): DecodedReviewAct {
156
162
  let act: JsonObject;
157
163
  try { const parsed: unknown = JSON.parse(bytes); if (!object(parsed)) throw Error(); act = parsed; }
158
164
  catch { return failure('REVIEW_ACT_INVALID', 'act is not a JSON object'); }
165
+ if (kind === 'reopen' && act.schema !== 'rig-review/act@4') failure('REVIEW_ACT_SCHEMA_UNSUPPORTED', 'reopen requires a record act@4');
166
+ if (act.schema === 'rig-review/act@4' && act.kind === 'reopen' && kind !== 'reopen') {
167
+ failure('REVIEW_ACT_KIND_MISMATCH', 'record reopen acts require the reopen writer');
168
+ }
159
169
  if (act.schema === JOB_COMMENTS_ACT_SCHEMA) return decodeCommentsReviewAct(act, kind);
160
- if (act.schema === 'rig-review/act@4' && act.kind === 'reopen' && kind !== 'checkpoint') failure('REVIEW_ACT_SCHEMA_UNSUPPORTED', 'record reopen acts have no Create writer mapping');
161
- if (['checkpoint', 'interview-picks', 'signoff'].includes(kind) && act.schema === 'rig-review/act@4') {
170
+ if (['checkpoint', 'interview-picks', 'signoff', 'reopen'].includes(kind) && act.schema === 'rig-review/act@4') {
162
171
  try {
163
172
  const recordAct = parseRecordAct(act);
164
173
  if (recordAct.kind !== kind) return failure('REVIEW_ACT_KIND_MISMATCH', 'record act kind differs from requested kind');
165
- return recordAct as CheckpointAct | InterviewPicksAct | SignoffAct;
174
+ return recordAct as CheckpointAct | InterviewPicksAct | SignoffAct | ReopenAct;
166
175
  } catch { return failure('REVIEW_ACT_INVALID', 'record act or its sealed source is malformed'); }
167
176
  }
168
177
  if (act.schema !== 'rig-review/act@2' && !(kind === 'review-verdict' && act.schema === 'rig-review/act@3')
@@ -292,7 +301,7 @@ export function decodeReviewAct(bytes: string, kind: 'review-verdict' | 'parts-v
292
301
  return act as unknown as ReviewVerdictAct;
293
302
  }
294
303
 
295
- export function decodeReviewResponse(text: string, jobId: string, actId: string, requestId: string, kind: 'review-verdict' | 'parts-verdict' | 'interview-picks' | 'checkpoint' | 'signoff' = 'review-verdict'): { act: ReviewVerdictAct | PartsVerdictAct | InterviewPicksAct | CheckpointAct | SignoffAct; bytes: string } {
304
+ export function decodeReviewResponse(text: string, jobId: string, actId: string, requestId: string, kind: ReviewActKind = 'review-verdict'): { act: DecodedReviewAct; bytes: string } {
296
305
  let response: JsonObject;
297
306
  try { const parsed: unknown = JSON.parse(text); if (!object(parsed)) throw Error(); response = parsed; }
298
307
  catch { return failure('REVIEW_ACT_INVALID', 'Review response is not JSON'); }
@@ -312,7 +321,23 @@ export interface ReviewActTransport {
312
321
  jobId: string;
313
322
  actId: string;
314
323
  fetchCapability: string;
315
- kind?: 'parts-verdict' | 'interview-picks' | 'checkpoint' | 'signoff';
324
+ kind?: Exclude<ReviewActKind, 'review-verdict'>;
325
+ }
326
+
327
+ /** Synchronous writers use the same authenticated fetch/decoder through the private runtime. */
328
+ export function fetchReviewActRuntime(transport: ReviewActTransport): { bytes: string; stillBytes?: string } {
329
+ const child = Bun.spawnSync([process.execPath, ...jobRuntimeExecArgv(), fileURLToPath(new URL('./review-act-runtime.ts', import.meta.url))], {
330
+ stdin: Buffer.from(JSON.stringify(transport)), stdout: 'pipe', stderr: 'pipe',
331
+ });
332
+ let response: { ok: boolean; bytes: string; stillBytes?: string; code: string; message: string };
333
+ try { response = JSON.parse(child.stdout.toString()); }
334
+ catch { return failure('REVIEW_ACT_FETCH_REFUSED', 'fetch adapter failed'); }
335
+ if (!response.ok || child.exitCode !== 0) refuse(response.code, response.message);
336
+ return { bytes: response.bytes, stillBytes: response.stillBytes };
337
+ }
338
+
339
+ export function fetchReviewActBytes(transport: ReviewActTransport): string {
340
+ return fetchReviewActRuntime(transport).bytes;
316
341
  }
317
342
 
318
343
  /** Only the route and fetch grant leave the binding reader. Never attach a host. */
@@ -329,7 +354,7 @@ export function reviewActTransport(root: string, actId: string): ReviewActTransp
329
354
  return { origin: origin.origin, jobId: binding.jobId, actId, fetchCapability: binding.fetchCapability };
330
355
  }
331
356
 
332
- export async function fetchReviewAct(transport: ReviewActTransport, fetchAdapter: typeof fetch = fetch): Promise<{ act: ReviewVerdictAct | PartsVerdictAct | InterviewPicksAct | CheckpointAct | SignoffAct; bytes: string; stillBytes?: string }> {
357
+ export async function fetchReviewAct(transport: ReviewActTransport, fetchAdapter: typeof fetch = fetch): Promise<{ act: DecodedReviewAct; bytes: string; stillBytes?: string }> {
333
358
  const requestId = randomUUID();
334
359
  const request = JSON.stringify({ schema: 'rig-review/job-api@2', verb: 'fetch-act', jobId: transport.jobId, actId: transport.actId, requestId });
335
360
  async function read(accept: string): Promise<Response> {
@@ -342,7 +367,7 @@ export async function fetchReviewAct(transport: ReviewActTransport, fetchAdapter
342
367
  return response;
343
368
  } catch { return failure('REVIEW_ACT_FETCH_REFUSED', 'live Review fetch failed'); }
344
369
  }
345
- if (transport.kind === 'parts-verdict' || transport.kind === 'interview-picks' || transport.kind === 'checkpoint' || transport.kind === 'signoff') return decodeReviewResponse(await (await read('application/json')).text(), transport.jobId, transport.actId, requestId, transport.kind);
370
+ if (transport.kind === 'parts-verdict' || transport.kind === 'interview-picks' || transport.kind === 'checkpoint' || transport.kind === 'signoff' || transport.kind === 'reopen') return decodeReviewResponse(await (await read('application/json')).text(), transport.jobId, transport.actId, requestId, transport.kind);
346
371
  const bytes = await (await read('application/vnd.rig-review.act+json')).text();
347
372
  const act = decodeReviewAct(bytes);
348
373
  if (act.jobId !== transport.jobId || act.actId !== transport.actId) failure('REVIEW_ACT_INVALID', 'fetched act identity differs from the request');
@@ -459,12 +484,12 @@ export function reviewActSignoff(act: SignoffAct): JsonObject {
459
484
  * acknowledged receipt keeps the subjects create published; a receipt that predates
460
485
  * them, or none (a clone), leaves only Review's own ask binding to vouch for it.
461
486
  */
462
- export function assertActSubjectDeclared(root: string, act: SignoffAct | CheckpointAct | InterviewPicksAct, path: string): void {
487
+ export function assertActSubjectDeclared(root: string, act: SignoffAct | CheckpointAct | InterviewPicksAct | ReopenAct, path: string): void {
463
488
  const receipt = readAcknowledgedPublication(root, act.jobId, act.publicationId);
464
489
  if (receipt?.subjects === undefined) return;
465
- const subject = act.kind === 'interview-picks' ? { kind: 'interview-picks', questionId: act.value.questionId, setId: act.source.optionSet.id } : act.kind === 'signoff' ? { kind: 'signoff', stage: act.value.stage } : { kind: 'checkpoint', checkpointId: act.value.checkpointId };
490
+ const subject = act.kind === 'interview-picks' ? { kind: 'interview-picks', questionId: act.value.questionId, setId: act.source.optionSet.id } : act.kind === 'signoff' || act.kind === 'reopen' ? { kind: act.kind, stage: act.value.stage } : { kind: 'checkpoint', checkpointId: act.value.checkpointId };
466
491
  if (receipt.subjects.some(declared => isDeepStrictEqual(declared, subject))) return;
467
- const named = act.kind === 'interview-picks' ? `answers ${act.value.questionId}` : act.kind === 'signoff' ? `signs ${act.value.stage}` : `passes checkpoint ${act.value.checkpointId}`;
492
+ const named = act.kind === 'interview-picks' ? `answers ${act.value.questionId}` : act.kind === 'signoff' || act.kind === 'reopen' ? `${act.kind} ${act.value.stage}` : `passes checkpoint ${act.value.checkpointId}`;
468
493
  refuse('REVIEW_ACT_SUBJECT_UNDECLARED', `${path}: act ${act.jobId}/${act.actId} ${named}, which its publication ${act.publicationId} did not declare; ask for it in Review on a publication made while the record can sign it`);
469
494
  }
470
495
 
@@ -512,7 +537,7 @@ export function reviewActFindings(project: JsonObject): { code: string; path: st
512
537
  try {
513
538
  if (!object(entry) || entry.schema !== 'rig-create/review-act@1' || typeof entry.bytes !== 'string'
514
539
  || !sha(entry.sha256) || jobHash(entry.bytes) !== entry.sha256 || !sha(entry.version_hash)) failure('REVIEW_ACT_LEDGER_INVALID', 'receipt shape or bytes hash is invalid');
515
- const act = decodeReviewAct(entry.bytes, entry.kind === 'parts-verdict' ? 'parts-verdict' : entry.kind === 'interview-picks' ? 'interview-picks' : entry.kind === 'checkpoint' ? 'checkpoint' : entry.kind === 'signoff' ? 'signoff' : 'review-verdict');
540
+ const act = decodeReviewAct(entry.bytes, entry.kind === 'parts-verdict' ? 'parts-verdict' : entry.kind === 'interview-picks' ? 'interview-picks' : entry.kind === 'checkpoint' ? 'checkpoint' : entry.kind === 'signoff' ? 'signoff' : entry.kind === 'reopen' ? 'reopen' : 'review-verdict');
516
541
  if (entry.jobId !== act.jobId || entry.actId !== act.actId) failure('REVIEW_ACT_LEDGER_INVALID', 'receipt identity differs from its act');
517
542
  const key = JSON.stringify([act.jobId, act.actId]);
518
543
  if (seen.has(key)) failure('REVIEW_ACT_REPLAY_CONFLICT', 'duplicate act receipt');
@@ -537,6 +562,16 @@ export function reviewActFindings(project: JsonObject): { code: string; path: st
537
562
  }
538
563
  return;
539
564
  }
565
+ if (act.kind === 'reopen') {
566
+ const recorded = Number.isSafeInteger(entry.reopen) && Number(entry.reopen) >= 0 ? asArray(project.reopens)[Number(entry.reopen)] : null;
567
+ if (!object(recorded) || entry.version_hash !== jobHash(JSON.stringify(recorded))
568
+ || recorded.stage !== act.value.stage || recorded.by !== act.authority.reviewer.id
569
+ || recorded.at !== act.at || recorded.verbatim !== act.value.words
570
+ || recorded.source !== `review act ${act.jobId}/${act.actId}`) {
571
+ failure('REVIEW_ACT_LEDGER_INVALID', 'recorded reopen differs from the immutable act');
572
+ }
573
+ return;
574
+ }
540
575
  if (act.kind === 'checkpoint') {
541
576
  const signoffs = Array.isArray(project.signoffs) ? project.signoffs : [];
542
577
  const signoff = Number.isSafeInteger(entry.signoff) && Number(entry.signoff) >= 0 ? signoffs[Number(entry.signoff)] : undefined;
@@ -13,6 +13,7 @@ import { asArray, isObject, readJsonObject, type Ctx } from './check.ts';
13
13
  import { draftFileUnavailable, draftVersionFindings } from './drafts.ts';
14
14
  import { Refusal, refuse, USAGE_EXIT } from './refusal.ts';
15
15
  import { assertRigVersionDate, rigVersionDateFinding } from './rig-version-date.ts';
16
+ import { registeredDepthPartsMatch } from './rig-version.ts';
16
17
  import { latestPartsApproval, retainedJson } from './structure.ts';
17
18
  import type { Json, JsonObject } from './templates.ts';
18
19
 
@@ -50,7 +51,8 @@ function checkBuildIdentity(ctx: Pick<Ctx, 'dir' | 'project' | 'refusals' | 'war
50
51
  const files = asArray(parts.files).filter(isObject);
51
52
  const manifest = files.find(file => file.path === `${parts.path}/parts.json`);
52
53
  const packaged = asArray(record.files).find(f => isObject(f) && f.path === 'out/parts.json');
53
- if (isObject(manifest) && typeof manifest.sha256 === 'string' && isObject(packaged) && typeof packaged.sha256 === 'string' && manifest.sha256 !== packaged.sha256) {
54
+ if (isObject(manifest) && typeof manifest.sha256 === 'string' && isObject(packaged) && typeof packaged.sha256 === 'string' && manifest.sha256 !== packaged.sha256
55
+ && !registeredDepthPartsMatch(ctx.dir, version, manifest.sha256, packaged.sha256)) {
54
56
  mismatch('REVIEW_PACKAGE_PARTS_MISMATCH', 'files[out/parts.json]', manifest.sha256, packaged.sha256);
55
57
  }
56
58
  if (!isObject(manifest) || typeof manifest.path !== 'string') return;