rig-create 1.0.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (598) hide show
  1. package/README.md +47 -23
  2. package/docs/CHECKS.md +9 -8
  3. package/docs/INTERVIEW.md +11 -4
  4. package/docs/LIVE-REVIEW.md +525 -0
  5. package/docs/PROJECT.md +10 -0
  6. package/package.json +5 -2
  7. package/scripts/npm-json.ts +74 -0
  8. package/scripts/verify-example-seals.ts +148 -0
  9. package/src/agent-guide.ts +16 -13
  10. package/src/choice-writers.ts +8 -2
  11. package/src/choices.ts +1 -1
  12. package/src/cli.ts +9 -1
  13. package/src/direction-writers.ts +3 -1
  14. package/src/direction.ts +2 -1
  15. package/src/feedback.ts +5 -2
  16. package/src/init.ts +1 -1
  17. package/src/job-acts.ts +44 -3
  18. package/src/job-host.ts +1 -1
  19. package/src/next.ts +197 -59
  20. package/src/record-input.ts +1 -1
  21. package/src/reopen.ts +1 -1
  22. package/src/review-package.ts +2 -1
  23. package/src/scene-writers.ts +2 -1
  24. package/src/scene.ts +3 -1
  25. package/src/signoff-pair.ts +60 -0
  26. package/src/signoff-target.ts +7 -4
  27. package/src/signoff.ts +5 -0
  28. package/src/structure.ts +1 -1
  29. package/templates/agent-guide.md +29 -31
  30. package/templates/example-chain/.gitignore +6 -0
  31. package/templates/example-chain/.npmignore +1 -0
  32. package/templates/example-chain/AGENTS.md +41 -43
  33. package/templates/example-chain/chain.json +55 -55
  34. package/templates/example-chain/checkpoints/0a-interview-options/.gitignore +6 -0
  35. package/templates/example-chain/checkpoints/0a-interview-options/.npmignore +1 -0
  36. package/templates/example-chain/checkpoints/0a-interview-options/AGENTS.md +41 -43
  37. package/templates/example-chain/checkpoints/0a-interview-options.json +1 -1
  38. package/templates/example-chain/checkpoints/0b-plan-pending/.gitignore +6 -0
  39. package/templates/example-chain/checkpoints/0b-plan-pending/.npmignore +1 -0
  40. package/templates/example-chain/checkpoints/0b-plan-pending/AGENTS.md +41 -43
  41. package/templates/example-chain/checkpoints/0b-plan-pending.json +1 -1
  42. package/templates/example-chain/checkpoints/1-parts-verdict/.gitignore +6 -0
  43. package/templates/example-chain/checkpoints/1-parts-verdict/.npmignore +1 -0
  44. package/templates/example-chain/checkpoints/1-parts-verdict/AGENTS.md +41 -43
  45. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/config.json +88 -0
  46. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/painting_in_rig.png +0 -0
  47. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/background.png +0 -0
  48. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/eye_l.png +0 -0
  49. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/eye_r.png +0 -0
  50. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/face.png +0 -0
  51. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/lantern.png +0 -0
  52. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts/torso.png +0 -0
  53. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/parts.json +188 -0
  54. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/input/recomposite_rig.png +0 -0
  55. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/interview-requirements.json +8 -0
  56. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/run.json +40 -0
  57. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  58. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  59. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  60. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  61. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/background.png +0 -0
  62. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/eye_l.png +0 -0
  63. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/eye_r.png +0 -0
  64. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/face.png +0 -0
  65. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/lantern.png +0 -0
  66. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/images/torso.png +0 -0
  67. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/mesh_report.json +15 -0
  68. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/motion.json +137 -0
  69. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/rig.json +536 -0
  70. package/templates/example-chain/checkpoints/1-parts-verdict/derived/drafts/chain/out/run.json +52 -0
  71. package/templates/example-chain/checkpoints/1-parts-verdict/project.json +2 -2
  72. package/templates/example-chain/checkpoints/1-parts-verdict.json +5 -5
  73. package/templates/example-chain/checkpoints/2-rigging-answers/.gitignore +6 -0
  74. package/templates/example-chain/checkpoints/2-rigging-answers/.npmignore +1 -0
  75. package/templates/example-chain/checkpoints/2-rigging-answers/AGENTS.md +41 -43
  76. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/config.json +88 -0
  77. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/painting_in_rig.png +0 -0
  78. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/background.png +0 -0
  79. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/eye_l.png +0 -0
  80. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/eye_r.png +0 -0
  81. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/face.png +0 -0
  82. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/lantern.png +0 -0
  83. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts/torso.png +0 -0
  84. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/parts.json +188 -0
  85. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/input/recomposite_rig.png +0 -0
  86. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/interview-requirements.json +8 -0
  87. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/run.json +40 -0
  88. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  89. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  90. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  91. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  92. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/background.png +0 -0
  93. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/eye_l.png +0 -0
  94. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/eye_r.png +0 -0
  95. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/face.png +0 -0
  96. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/lantern.png +0 -0
  97. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/images/torso.png +0 -0
  98. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/mesh_report.json +15 -0
  99. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/motion.json +137 -0
  100. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/rig.json +536 -0
  101. package/templates/example-chain/checkpoints/2-rigging-answers/derived/drafts/chain/out/run.json +52 -0
  102. package/templates/example-chain/checkpoints/2-rigging-answers/project.json +2 -2
  103. package/templates/example-chain/checkpoints/2-rigging-answers.json +5 -5
  104. package/templates/example-chain/checkpoints/3-rig-review/.gitignore +6 -0
  105. package/templates/example-chain/checkpoints/3-rig-review/.npmignore +1 -0
  106. package/templates/example-chain/checkpoints/3-rig-review/AGENTS.md +41 -43
  107. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/config.json +88 -0
  108. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/painting_in_rig.png +0 -0
  109. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/background.png +0 -0
  110. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/eye_l.png +0 -0
  111. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/eye_r.png +0 -0
  112. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/face.png +0 -0
  113. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/lantern.png +0 -0
  114. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts/torso.png +0 -0
  115. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/parts.json +188 -0
  116. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/input/recomposite_rig.png +0 -0
  117. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/interview-requirements.json +8 -0
  118. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/run.json +40 -0
  119. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  120. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  121. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  122. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  123. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/background.png +0 -0
  124. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/eye_l.png +0 -0
  125. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/eye_r.png +0 -0
  126. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/face.png +0 -0
  127. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/lantern.png +0 -0
  128. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/images/torso.png +0 -0
  129. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/mesh_report.json +15 -0
  130. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/motion.json +137 -0
  131. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/rig.json +536 -0
  132. package/templates/example-chain/checkpoints/3-rig-review/derived/drafts/chain/out/run.json +52 -0
  133. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/config.json +88 -0
  134. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/interview-requirements.json +8 -0
  135. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/run.json +40 -0
  136. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  137. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/skeleton.json +674 -0
  138. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/skeleton.model.json +1072 -0
  139. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/check/build/skeleton.png +0 -0
  140. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/background.png +0 -0
  141. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/eye_l.png +0 -0
  142. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/eye_r.png +0 -0
  143. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/face.png +0 -0
  144. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/lantern.png +0 -0
  145. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts/torso.png +0 -0
  146. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/parts.json +188 -0
  147. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/background.png +0 -0
  148. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/eye_l.png +0 -0
  149. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/eye_r.png +0 -0
  150. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/face.png +0 -0
  151. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/lantern.png +0 -0
  152. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/images/torso.png +0 -0
  153. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/mesh_report.json +15 -0
  154. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/motion.json +137 -0
  155. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/rig.json +536 -0
  156. package/templates/example-chain/checkpoints/3-rig-review/derived/review/v1/out/rig/run.json +52 -0
  157. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/run.json +40 -0
  158. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/skeleton.atlas +28 -0
  159. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/skeleton.json +674 -0
  160. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/skeleton.model.json +1072 -0
  161. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/check/build/skeleton.png +0 -0
  162. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/painting_in_rig.png +0 -0
  163. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/background.png +0 -0
  164. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/eye_l.png +0 -0
  165. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/eye_r.png +0 -0
  166. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/face.png +0 -0
  167. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/lantern.png +0 -0
  168. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts/torso.png +0 -0
  169. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/parts.json +188 -0
  170. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/background.png +0 -0
  171. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/eye_l.png +0 -0
  172. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/eye_r.png +0 -0
  173. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/face.png +0 -0
  174. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/lantern.png +0 -0
  175. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/images/torso.png +0 -0
  176. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/mesh_report.json +15 -0
  177. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/motion.json +137 -0
  178. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/rig.json +536 -0
  179. package/templates/example-chain/checkpoints/3-rig-review/outputs/v1/out/rig/run.json +52 -0
  180. package/templates/example-chain/checkpoints/3-rig-review/project.json +4 -4
  181. package/templates/example-chain/checkpoints/3-rig-review.json +9 -9
  182. package/templates/example-chain/checkpoints/4-direction-post/.gitignore +6 -0
  183. package/templates/example-chain/checkpoints/4-direction-post/.npmignore +1 -0
  184. package/templates/example-chain/checkpoints/4-direction-post/AGENTS.md +41 -43
  185. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/config.json +88 -0
  186. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/painting_in_rig.png +0 -0
  187. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/background.png +0 -0
  188. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/eye_l.png +0 -0
  189. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/eye_r.png +0 -0
  190. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/face.png +0 -0
  191. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/lantern.png +0 -0
  192. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts/torso.png +0 -0
  193. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/parts.json +188 -0
  194. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/input/recomposite_rig.png +0 -0
  195. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/interview-requirements.json +8 -0
  196. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/run.json +40 -0
  197. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  198. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  199. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  200. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  201. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/background.png +0 -0
  202. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/eye_l.png +0 -0
  203. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/eye_r.png +0 -0
  204. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/face.png +0 -0
  205. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/lantern.png +0 -0
  206. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/images/torso.png +0 -0
  207. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/mesh_report.json +15 -0
  208. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/motion.json +137 -0
  209. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/rig.json +536 -0
  210. package/templates/example-chain/checkpoints/4-direction-post/derived/drafts/chain/out/run.json +52 -0
  211. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/config.json +88 -0
  212. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/interview-requirements.json +8 -0
  213. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/run.json +40 -0
  214. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  215. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/skeleton.json +674 -0
  216. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/skeleton.model.json +1072 -0
  217. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/check/build/skeleton.png +0 -0
  218. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/background.png +0 -0
  219. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/eye_l.png +0 -0
  220. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/eye_r.png +0 -0
  221. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/face.png +0 -0
  222. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/lantern.png +0 -0
  223. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts/torso.png +0 -0
  224. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/parts.json +188 -0
  225. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/background.png +0 -0
  226. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/eye_l.png +0 -0
  227. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/eye_r.png +0 -0
  228. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/face.png +0 -0
  229. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/lantern.png +0 -0
  230. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/images/torso.png +0 -0
  231. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/mesh_report.json +15 -0
  232. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/motion.json +137 -0
  233. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/rig.json +536 -0
  234. package/templates/example-chain/checkpoints/4-direction-post/derived/review/v1/out/rig/run.json +52 -0
  235. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/run.json +40 -0
  236. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/skeleton.atlas +28 -0
  237. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/skeleton.json +674 -0
  238. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/skeleton.model.json +1072 -0
  239. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/check/build/skeleton.png +0 -0
  240. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/painting_in_rig.png +0 -0
  241. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/background.png +0 -0
  242. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/eye_l.png +0 -0
  243. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/eye_r.png +0 -0
  244. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/face.png +0 -0
  245. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/lantern.png +0 -0
  246. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts/torso.png +0 -0
  247. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/parts.json +188 -0
  248. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/background.png +0 -0
  249. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/eye_l.png +0 -0
  250. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/eye_r.png +0 -0
  251. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/face.png +0 -0
  252. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/lantern.png +0 -0
  253. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/images/torso.png +0 -0
  254. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/mesh_report.json +15 -0
  255. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/motion.json +137 -0
  256. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/rig.json +536 -0
  257. package/templates/example-chain/checkpoints/4-direction-post/outputs/v1/out/rig/run.json +52 -0
  258. package/templates/example-chain/checkpoints/4-direction-post/project.json +5 -5
  259. package/templates/example-chain/checkpoints/4-direction-post.json +9 -9
  260. package/templates/example-chain/derived/drafts/chain/config.json +88 -0
  261. package/templates/example-chain/derived/drafts/chain/input/painting_in_rig.png +0 -0
  262. package/templates/example-chain/derived/drafts/chain/input/parts/background.png +0 -0
  263. package/templates/example-chain/derived/drafts/chain/input/parts/eye_l.png +0 -0
  264. package/templates/example-chain/derived/drafts/chain/input/parts/eye_r.png +0 -0
  265. package/templates/example-chain/derived/drafts/chain/input/parts/face.png +0 -0
  266. package/templates/example-chain/derived/drafts/chain/input/parts/lantern.png +0 -0
  267. package/templates/example-chain/derived/drafts/chain/input/parts/torso.png +0 -0
  268. package/templates/example-chain/derived/drafts/chain/input/parts.json +188 -0
  269. package/templates/example-chain/derived/drafts/chain/input/recomposite_rig.png +0 -0
  270. package/templates/example-chain/derived/drafts/chain/interview-requirements.json +8 -0
  271. package/templates/example-chain/derived/drafts/chain/out/check/build/run.json +40 -0
  272. package/templates/example-chain/derived/drafts/chain/out/check/build/skeleton.atlas +28 -0
  273. package/templates/example-chain/derived/drafts/chain/out/check/build/skeleton.json +674 -0
  274. package/templates/example-chain/derived/drafts/chain/out/check/build/skeleton.model.json +1072 -0
  275. package/templates/example-chain/derived/drafts/chain/out/check/build/skeleton.png +0 -0
  276. package/templates/example-chain/derived/drafts/chain/out/images/background.png +0 -0
  277. package/templates/example-chain/derived/drafts/chain/out/images/eye_l.png +0 -0
  278. package/templates/example-chain/derived/drafts/chain/out/images/eye_r.png +0 -0
  279. package/templates/example-chain/derived/drafts/chain/out/images/face.png +0 -0
  280. package/templates/example-chain/derived/drafts/chain/out/images/lantern.png +0 -0
  281. package/templates/example-chain/derived/drafts/chain/out/images/torso.png +0 -0
  282. package/templates/example-chain/derived/drafts/chain/out/mesh_report.json +15 -0
  283. package/templates/example-chain/derived/drafts/chain/out/motion.json +137 -0
  284. package/templates/example-chain/derived/drafts/chain/out/rig.json +536 -0
  285. package/templates/example-chain/derived/drafts/chain/out/run.json +52 -0
  286. package/templates/example-chain/derived/review/v1/config.json +88 -0
  287. package/templates/example-chain/derived/review/v1/interview-requirements.json +8 -0
  288. package/templates/example-chain/derived/review/v1/out/check/build/run.json +40 -0
  289. package/templates/example-chain/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  290. package/templates/example-chain/derived/review/v1/out/check/build/skeleton.json +674 -0
  291. package/templates/example-chain/derived/review/v1/out/check/build/skeleton.model.json +1072 -0
  292. package/templates/example-chain/derived/review/v1/out/check/build/skeleton.png +0 -0
  293. package/templates/example-chain/derived/review/v1/out/parts/background.png +0 -0
  294. package/templates/example-chain/derived/review/v1/out/parts/eye_l.png +0 -0
  295. package/templates/example-chain/derived/review/v1/out/parts/eye_r.png +0 -0
  296. package/templates/example-chain/derived/review/v1/out/parts/face.png +0 -0
  297. package/templates/example-chain/derived/review/v1/out/parts/lantern.png +0 -0
  298. package/templates/example-chain/derived/review/v1/out/parts/torso.png +0 -0
  299. package/templates/example-chain/derived/review/v1/out/parts.json +188 -0
  300. package/templates/example-chain/derived/review/v1/out/rig/images/background.png +0 -0
  301. package/templates/example-chain/derived/review/v1/out/rig/images/eye_l.png +0 -0
  302. package/templates/example-chain/derived/review/v1/out/rig/images/eye_r.png +0 -0
  303. package/templates/example-chain/derived/review/v1/out/rig/images/face.png +0 -0
  304. package/templates/example-chain/derived/review/v1/out/rig/images/lantern.png +0 -0
  305. package/templates/example-chain/derived/review/v1/out/rig/images/torso.png +0 -0
  306. package/templates/example-chain/derived/review/v1/out/rig/mesh_report.json +15 -0
  307. package/templates/example-chain/derived/review/v1/out/rig/motion.json +137 -0
  308. package/templates/example-chain/derived/review/v1/out/rig/rig.json +536 -0
  309. package/templates/example-chain/derived/review/v1/out/rig/run.json +52 -0
  310. package/templates/example-chain/evidence/captions.json +1 -1
  311. package/templates/example-chain/evidence/direction/v2.json +1 -1
  312. package/templates/example-chain/evidence/direction-input.json +1 -1
  313. package/templates/example-chain/evidence/scene/s1.json +1 -1
  314. package/templates/example-chain/outputs/v1/out/check/build/run.json +40 -0
  315. package/templates/example-chain/outputs/v1/out/check/build/skeleton.atlas +28 -0
  316. package/templates/example-chain/outputs/v1/out/check/build/skeleton.json +674 -0
  317. package/templates/example-chain/outputs/v1/out/check/build/skeleton.model.json +1072 -0
  318. package/templates/example-chain/outputs/v1/out/check/build/skeleton.png +0 -0
  319. package/templates/example-chain/outputs/v1/out/painting_in_rig.png +0 -0
  320. package/templates/example-chain/outputs/v1/out/parts/background.png +0 -0
  321. package/templates/example-chain/outputs/v1/out/parts/eye_l.png +0 -0
  322. package/templates/example-chain/outputs/v1/out/parts/eye_r.png +0 -0
  323. package/templates/example-chain/outputs/v1/out/parts/face.png +0 -0
  324. package/templates/example-chain/outputs/v1/out/parts/lantern.png +0 -0
  325. package/templates/example-chain/outputs/v1/out/parts/torso.png +0 -0
  326. package/templates/example-chain/outputs/v1/out/parts.json +188 -0
  327. package/templates/example-chain/outputs/v1/out/rig/images/background.png +0 -0
  328. package/templates/example-chain/outputs/v1/out/rig/images/eye_l.png +0 -0
  329. package/templates/example-chain/outputs/v1/out/rig/images/eye_r.png +0 -0
  330. package/templates/example-chain/outputs/v1/out/rig/images/face.png +0 -0
  331. package/templates/example-chain/outputs/v1/out/rig/images/lantern.png +0 -0
  332. package/templates/example-chain/outputs/v1/out/rig/images/torso.png +0 -0
  333. package/templates/example-chain/outputs/v1/out/rig/mesh_report.json +15 -0
  334. package/templates/example-chain/outputs/v1/out/rig/motion.json +137 -0
  335. package/templates/example-chain/outputs/v1/out/rig/rig.json +536 -0
  336. package/templates/example-chain/outputs/v1/out/rig/run.json +52 -0
  337. package/templates/example-chain/project.json +10 -10
  338. package/templates/example-direction/derived/review/v1/out/check/build/run.json +2 -2
  339. package/templates/example-draft/derived/drafts/lantern/out/check/build/run.json +2 -2
  340. package/templates/example-draft/derived/drafts/lantern/out/run.json +2 -2
  341. package/templates/example-draft/derived/review/v1/out/check/build/run.json +2 -2
  342. package/templates/example-draft/derived/review/v1/out/rig/run.json +2 -2
  343. package/templates/example-draft/derived/review/v2/out/check/build/run.json +2 -2
  344. package/templates/example-draft/derived/review/v2/out/rig/run.json +2 -2
  345. package/templates/example-draft/evidence/direction/v4.json +3 -3
  346. package/templates/example-draft/evidence/direction-input-v4.json +3 -3
  347. package/templates/example-draft/evidence/parts-review.json +1 -1
  348. package/templates/example-draft/evidence/review-reads/{4ed0507381809746443021554e012032be5b5f8417da0f2e525e9b6df16e9f05.json → 52673b635b9cbc92da1a9e3d4c023a249bbacf79cd21b59724f03f18f8caf09b.json} +2 -2
  349. package/templates/example-draft/evidence/scene/s1.json +3 -3
  350. package/templates/example-draft/evidence/scene-citations.json +1 -1
  351. package/templates/example-draft/out/check/build/run.json +2 -2
  352. package/templates/example-draft/out/run.json +2 -2
  353. package/templates/example-draft/outputs/v1/out/check/build/run.json +2 -2
  354. package/templates/example-draft/outputs/v1/out/rig/run.json +2 -2
  355. package/templates/example-draft/outputs/v2/out/check/build/run.json +2 -2
  356. package/templates/example-draft/outputs/v2/out/rig/run.json +2 -2
  357. package/templates/example-interview-choice.json +68 -68
  358. package/templates/example-interview-options/constraint.json +2 -2
  359. package/templates/example-interview-options/example-assemble.json +2 -2
  360. package/templates/example-interview-options/example-bones.json +5 -5
  361. package/templates/example-interview-options/example-camera-depth.json +3 -3
  362. package/templates/example-interview-options/example-constraints.json +5 -5
  363. package/templates/example-interview-options/example-meshes.json +5 -5
  364. package/templates/example-interview-options/example-motion.json +5 -5
  365. package/templates/example-interview-options/example-picks.json +2 -2
  366. package/templates/example-interview-options/example-post-composition.json +3 -3
  367. package/templates/example-interview-options/example-post-timing.json +3 -3
  368. package/templates/example-interview-options/example-reference.json +2 -2
  369. package/templates/example-interview-options/example-rig-type.json +2 -2
  370. package/templates/example-interview-options/example-seethrough.json +2 -2
  371. package/templates/example-interview-options/fullscreen.json +2 -2
  372. package/templates/example-interview-options/other-explicit.json +2 -2
  373. package/templates/example-interview-options/other-pending.json +2 -2
  374. package/templates/example-interview-options/other-picks.json +2 -2
  375. package/templates/example-invariants/invariants.json +164 -164
  376. package/templates/example-project.json +249 -249
  377. package/templates/example-remesh/.gitignore +6 -0
  378. package/templates/example-remesh/.npmignore +1 -0
  379. package/templates/example-remesh/AGENTS.md +41 -43
  380. package/templates/example-remesh/derived/drafts/remesh/config.json +88 -0
  381. package/templates/example-remesh/derived/drafts/remesh/input/painting_in_rig.png +0 -0
  382. package/templates/example-remesh/derived/drafts/remesh/input/parts/background.png +0 -0
  383. package/templates/example-remesh/derived/drafts/remesh/input/parts/eye_l.png +0 -0
  384. package/templates/example-remesh/derived/drafts/remesh/input/parts/eye_r.png +0 -0
  385. package/templates/example-remesh/derived/drafts/remesh/input/parts/face.png +0 -0
  386. package/templates/example-remesh/derived/drafts/remesh/input/parts/lantern.png +0 -0
  387. package/templates/example-remesh/derived/drafts/remesh/input/parts/torso.png +0 -0
  388. package/templates/example-remesh/derived/drafts/remesh/input/parts.json +188 -0
  389. package/templates/example-remesh/derived/drafts/remesh/input/recomposite_rig.png +0 -0
  390. package/templates/example-remesh/derived/drafts/remesh/interview-requirements.json +8 -0
  391. package/templates/example-remesh/derived/drafts/remesh/out/check/build/run.json +40 -0
  392. package/templates/example-remesh/derived/drafts/remesh/out/check/build/skeleton.atlas +28 -0
  393. package/templates/example-remesh/derived/drafts/remesh/out/check/build/skeleton.json +674 -0
  394. package/templates/example-remesh/derived/drafts/remesh/out/check/build/skeleton.model.json +1072 -0
  395. package/templates/example-remesh/derived/drafts/remesh/out/check/build/skeleton.png +0 -0
  396. package/templates/example-remesh/derived/drafts/remesh/out/images/background.png +0 -0
  397. package/templates/example-remesh/derived/drafts/remesh/out/images/eye_l.png +0 -0
  398. package/templates/example-remesh/derived/drafts/remesh/out/images/eye_r.png +0 -0
  399. package/templates/example-remesh/derived/drafts/remesh/out/images/face.png +0 -0
  400. package/templates/example-remesh/derived/drafts/remesh/out/images/lantern.png +0 -0
  401. package/templates/example-remesh/derived/drafts/remesh/out/images/torso.png +0 -0
  402. package/templates/example-remesh/derived/drafts/remesh/out/mesh_report.json +15 -0
  403. package/templates/example-remesh/derived/drafts/remesh/out/motion.json +137 -0
  404. package/templates/example-remesh/derived/drafts/remesh/out/rig.json +536 -0
  405. package/templates/example-remesh/derived/drafts/remesh/out/run.json +52 -0
  406. package/templates/example-remesh/derived/review/v1/config.json +88 -0
  407. package/templates/example-remesh/derived/review/v1/interview-requirements.json +8 -0
  408. package/templates/example-remesh/derived/review/v1/out/check/build/run.json +44 -0
  409. package/templates/example-remesh/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  410. package/templates/example-remesh/derived/review/v1/out/check/build/skeleton.json +674 -0
  411. package/templates/example-remesh/derived/review/v1/out/check/build/skeleton.model.json +1072 -0
  412. package/templates/example-remesh/derived/review/v1/out/check/build/skeleton.png +0 -0
  413. package/templates/example-remesh/derived/review/v1/out/painting_in_rig.png +0 -0
  414. package/templates/example-remesh/derived/review/v1/out/parts/background.png +0 -0
  415. package/templates/example-remesh/derived/review/v1/out/parts/eye_l.png +0 -0
  416. package/templates/example-remesh/derived/review/v1/out/parts/eye_r.png +0 -0
  417. package/templates/example-remesh/derived/review/v1/out/parts/face.png +0 -0
  418. package/templates/example-remesh/derived/review/v1/out/parts/lantern.png +0 -0
  419. package/templates/example-remesh/derived/review/v1/out/parts/torso.png +0 -0
  420. package/templates/example-remesh/derived/review/v1/out/parts.json +188 -0
  421. package/templates/example-remesh/derived/review/v1/out/rig/images/background.png +0 -0
  422. package/templates/example-remesh/derived/review/v1/out/rig/images/eye_l.png +0 -0
  423. package/templates/example-remesh/derived/review/v1/out/rig/images/eye_r.png +0 -0
  424. package/templates/example-remesh/derived/review/v1/out/rig/images/face.png +0 -0
  425. package/templates/example-remesh/derived/review/v1/out/rig/images/lantern.png +0 -0
  426. package/templates/example-remesh/derived/review/v1/out/rig/images/torso.png +0 -0
  427. package/templates/example-remesh/derived/review/v1/out/rig/mesh_report.json +15 -0
  428. package/templates/example-remesh/derived/review/v1/out/rig/motion.json +137 -0
  429. package/templates/example-remesh/derived/review/v1/out/rig/rig.json +536 -0
  430. package/templates/example-remesh/derived/review/v1/out/rig/run.json +52 -0
  431. package/templates/example-remesh/derived/review/v2/config.json +88 -0
  432. package/templates/example-remesh/derived/review/v2/interview-requirements.json +8 -0
  433. package/templates/example-remesh/derived/review/v2/out/check/build/run.json +44 -0
  434. package/templates/example-remesh/derived/review/v2/out/check/build/skeleton.atlas +28 -0
  435. package/templates/example-remesh/derived/review/v2/out/check/build/skeleton.json +674 -0
  436. package/templates/example-remesh/derived/review/v2/out/check/build/skeleton.model.json +1072 -0
  437. package/templates/example-remesh/derived/review/v2/out/check/build/skeleton.png +0 -0
  438. package/templates/example-remesh/derived/review/v2/out/painting_in_rig.png +0 -0
  439. package/templates/example-remesh/derived/review/v2/out/parts/background.png +0 -0
  440. package/templates/example-remesh/derived/review/v2/out/parts/eye_l.png +0 -0
  441. package/templates/example-remesh/derived/review/v2/out/parts/eye_r.png +0 -0
  442. package/templates/example-remesh/derived/review/v2/out/parts/face.png +0 -0
  443. package/templates/example-remesh/derived/review/v2/out/parts/lantern.png +0 -0
  444. package/templates/example-remesh/derived/review/v2/out/parts/torso.png +0 -0
  445. package/templates/example-remesh/derived/review/v2/out/parts.json +188 -0
  446. package/templates/example-remesh/derived/review/v2/out/rig/images/background.png +0 -0
  447. package/templates/example-remesh/derived/review/v2/out/rig/images/eye_l.png +0 -0
  448. package/templates/example-remesh/derived/review/v2/out/rig/images/eye_r.png +0 -0
  449. package/templates/example-remesh/derived/review/v2/out/rig/images/face.png +0 -0
  450. package/templates/example-remesh/derived/review/v2/out/rig/images/lantern.png +0 -0
  451. package/templates/example-remesh/derived/review/v2/out/rig/images/torso.png +0 -0
  452. package/templates/example-remesh/derived/review/v2/out/rig/mesh_report.json +15 -0
  453. package/templates/example-remesh/derived/review/v2/out/rig/motion.json +137 -0
  454. package/templates/example-remesh/derived/review/v2/out/rig/rig.json +536 -0
  455. package/templates/example-remesh/derived/review/v2/out/rig/run.json +52 -0
  456. package/templates/example-remesh/derived/review/v3/config.json +88 -0
  457. package/templates/example-remesh/derived/review/v3/interview-requirements.json +8 -0
  458. package/templates/example-remesh/derived/review/v3/out/check/build/run.json +44 -0
  459. package/templates/example-remesh/derived/review/v3/out/check/build/skeleton.atlas +28 -0
  460. package/templates/example-remesh/derived/review/v3/out/check/build/skeleton.json +674 -0
  461. package/templates/example-remesh/derived/review/v3/out/check/build/skeleton.model.json +1072 -0
  462. package/templates/example-remesh/derived/review/v3/out/check/build/skeleton.png +0 -0
  463. package/templates/example-remesh/derived/review/v3/out/painting_in_rig.png +0 -0
  464. package/templates/example-remesh/derived/review/v3/out/parts/background.png +0 -0
  465. package/templates/example-remesh/derived/review/v3/out/parts/eye_l.png +0 -0
  466. package/templates/example-remesh/derived/review/v3/out/parts/eye_r.png +0 -0
  467. package/templates/example-remesh/derived/review/v3/out/parts/face.png +0 -0
  468. package/templates/example-remesh/derived/review/v3/out/parts/lantern.png +0 -0
  469. package/templates/example-remesh/derived/review/v3/out/parts/torso.png +0 -0
  470. package/templates/example-remesh/derived/review/v3/out/parts.json +188 -0
  471. package/templates/example-remesh/derived/review/v3/out/rig/images/background.png +0 -0
  472. package/templates/example-remesh/derived/review/v3/out/rig/images/eye_l.png +0 -0
  473. package/templates/example-remesh/derived/review/v3/out/rig/images/eye_r.png +0 -0
  474. package/templates/example-remesh/derived/review/v3/out/rig/images/face.png +0 -0
  475. package/templates/example-remesh/derived/review/v3/out/rig/images/lantern.png +0 -0
  476. package/templates/example-remesh/derived/review/v3/out/rig/images/torso.png +0 -0
  477. package/templates/example-remesh/derived/review/v3/out/rig/mesh_report.json +15 -0
  478. package/templates/example-remesh/derived/review/v3/out/rig/motion.json +137 -0
  479. package/templates/example-remesh/derived/review/v3/out/rig/rig.json +536 -0
  480. package/templates/example-remesh/derived/review/v3/out/rig/run.json +52 -0
  481. package/templates/example-remesh/evidence/captions.json +1 -1
  482. package/templates/example-remesh/evidence/direction/v4.json +1 -1
  483. package/templates/example-remesh/evidence/direction/v5.json +1 -1
  484. package/templates/example-remesh/evidence/direction-input-v4.json +1 -1
  485. package/templates/example-remesh/evidence/direction-input-v5.json +1 -1
  486. package/templates/example-remesh/evidence/interview/assemble.json +1 -1
  487. package/templates/example-remesh/evidence/interview/bones.json +4 -4
  488. package/templates/example-remesh/evidence/interview/camera_depth.json +2 -2
  489. package/templates/example-remesh/evidence/interview/constraints.json +4 -4
  490. package/templates/example-remesh/evidence/interview/meshes.json +4 -4
  491. package/templates/example-remesh/evidence/interview/motion.json +4 -4
  492. package/templates/example-remesh/evidence/interview/post_composition.json +2 -2
  493. package/templates/example-remesh/evidence/interview/post_timing.json +2 -2
  494. package/templates/example-remesh/evidence/interview/reference.json +1 -1
  495. package/templates/example-remesh/evidence/interview/rig_type.json +1 -1
  496. package/templates/example-remesh/evidence/interview/seethrough.json +1 -1
  497. package/templates/example-remesh/evidence/parts-review.json +1 -1
  498. package/templates/example-remesh/evidence/review-reads/{6a17db694db96f1b6049a61a017e0c8e66757b982b8851e0187e561cfcf9af68.json → afe2522be4087f7f2fa7e97746d5f8574b0aedb474245ce2dbce0455e662f041.json} +2 -2
  499. package/templates/example-remesh/evidence/scene/s1.json +2 -2
  500. package/templates/example-remesh/evidence/v1/registration/at-source.json +2 -2
  501. package/templates/example-remesh/evidence/v1/registration/rigc-run-1.json +2 -2
  502. package/templates/example-remesh/evidence/v2/registration/at-source.json +2 -2
  503. package/templates/example-remesh/evidence/v2/registration/rigc-run-1.json +2 -2
  504. package/templates/example-remesh/evidence/v3/registration/at-source.json +2 -2
  505. package/templates/example-remesh/evidence/v3/registration/rigc-run-1.json +2 -2
  506. package/templates/example-remesh/outputs/v1/idle/frames.json +29 -0
  507. package/templates/example-remesh/outputs/v1/idle/idle@1fps/contact.png +0 -0
  508. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0000.png +0 -0
  509. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0001.png +0 -0
  510. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0002.png +0 -0
  511. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0003.png +0 -0
  512. package/templates/example-remesh/outputs/v1/idle/idle@1fps/f0004.png +0 -0
  513. package/templates/example-remesh/outputs/v1/out/check/build/run.json +44 -0
  514. package/templates/example-remesh/outputs/v1/out/check/build/skeleton.atlas +28 -0
  515. package/templates/example-remesh/outputs/v1/out/check/build/skeleton.json +674 -0
  516. package/templates/example-remesh/outputs/v1/out/check/build/skeleton.model.json +1072 -0
  517. package/templates/example-remesh/outputs/v1/out/check/build/skeleton.png +0 -0
  518. package/templates/example-remesh/outputs/v1/out/painting_in_rig.png +0 -0
  519. package/templates/example-remesh/outputs/v1/out/parts/background.png +0 -0
  520. package/templates/example-remesh/outputs/v1/out/parts/eye_l.png +0 -0
  521. package/templates/example-remesh/outputs/v1/out/parts/eye_r.png +0 -0
  522. package/templates/example-remesh/outputs/v1/out/parts/face.png +0 -0
  523. package/templates/example-remesh/outputs/v1/out/parts/lantern.png +0 -0
  524. package/templates/example-remesh/outputs/v1/out/parts/torso.png +0 -0
  525. package/templates/example-remesh/outputs/v1/out/parts.json +188 -0
  526. package/templates/example-remesh/outputs/v1/out/rig/images/background.png +0 -0
  527. package/templates/example-remesh/outputs/v1/out/rig/images/eye_l.png +0 -0
  528. package/templates/example-remesh/outputs/v1/out/rig/images/eye_r.png +0 -0
  529. package/templates/example-remesh/outputs/v1/out/rig/images/face.png +0 -0
  530. package/templates/example-remesh/outputs/v1/out/rig/images/lantern.png +0 -0
  531. package/templates/example-remesh/outputs/v1/out/rig/images/torso.png +0 -0
  532. package/templates/example-remesh/outputs/v1/out/rig/mesh_report.json +15 -0
  533. package/templates/example-remesh/outputs/v1/out/rig/motion.json +137 -0
  534. package/templates/example-remesh/outputs/v1/out/rig/rig.json +536 -0
  535. package/templates/example-remesh/outputs/v1/out/rig/run.json +52 -0
  536. package/templates/example-remesh/outputs/v2/idle/frames.json +29 -0
  537. package/templates/example-remesh/outputs/v2/idle/idle@1fps/contact.png +0 -0
  538. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0000.png +0 -0
  539. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0001.png +0 -0
  540. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0002.png +0 -0
  541. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0003.png +0 -0
  542. package/templates/example-remesh/outputs/v2/idle/idle@1fps/f0004.png +0 -0
  543. package/templates/example-remesh/outputs/v2/out/check/build/run.json +44 -0
  544. package/templates/example-remesh/outputs/v2/out/check/build/skeleton.atlas +28 -0
  545. package/templates/example-remesh/outputs/v2/out/check/build/skeleton.json +674 -0
  546. package/templates/example-remesh/outputs/v2/out/check/build/skeleton.model.json +1072 -0
  547. package/templates/example-remesh/outputs/v2/out/check/build/skeleton.png +0 -0
  548. package/templates/example-remesh/outputs/v2/out/painting_in_rig.png +0 -0
  549. package/templates/example-remesh/outputs/v2/out/parts/background.png +0 -0
  550. package/templates/example-remesh/outputs/v2/out/parts/eye_l.png +0 -0
  551. package/templates/example-remesh/outputs/v2/out/parts/eye_r.png +0 -0
  552. package/templates/example-remesh/outputs/v2/out/parts/face.png +0 -0
  553. package/templates/example-remesh/outputs/v2/out/parts/lantern.png +0 -0
  554. package/templates/example-remesh/outputs/v2/out/parts/torso.png +0 -0
  555. package/templates/example-remesh/outputs/v2/out/parts.json +188 -0
  556. package/templates/example-remesh/outputs/v2/out/rig/images/background.png +0 -0
  557. package/templates/example-remesh/outputs/v2/out/rig/images/eye_l.png +0 -0
  558. package/templates/example-remesh/outputs/v2/out/rig/images/eye_r.png +0 -0
  559. package/templates/example-remesh/outputs/v2/out/rig/images/face.png +0 -0
  560. package/templates/example-remesh/outputs/v2/out/rig/images/lantern.png +0 -0
  561. package/templates/example-remesh/outputs/v2/out/rig/images/torso.png +0 -0
  562. package/templates/example-remesh/outputs/v2/out/rig/mesh_report.json +15 -0
  563. package/templates/example-remesh/outputs/v2/out/rig/motion.json +137 -0
  564. package/templates/example-remesh/outputs/v2/out/rig/rig.json +536 -0
  565. package/templates/example-remesh/outputs/v2/out/rig/run.json +52 -0
  566. package/templates/example-remesh/outputs/v3/idle/frames.json +29 -0
  567. package/templates/example-remesh/outputs/v3/idle/idle@1fps/contact.png +0 -0
  568. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0000.png +0 -0
  569. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0001.png +0 -0
  570. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0002.png +0 -0
  571. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0003.png +0 -0
  572. package/templates/example-remesh/outputs/v3/idle/idle@1fps/f0004.png +0 -0
  573. package/templates/example-remesh/outputs/v3/out/check/build/run.json +44 -0
  574. package/templates/example-remesh/outputs/v3/out/check/build/skeleton.atlas +28 -0
  575. package/templates/example-remesh/outputs/v3/out/check/build/skeleton.json +674 -0
  576. package/templates/example-remesh/outputs/v3/out/check/build/skeleton.model.json +1072 -0
  577. package/templates/example-remesh/outputs/v3/out/check/build/skeleton.png +0 -0
  578. package/templates/example-remesh/outputs/v3/out/painting_in_rig.png +0 -0
  579. package/templates/example-remesh/outputs/v3/out/parts/background.png +0 -0
  580. package/templates/example-remesh/outputs/v3/out/parts/eye_l.png +0 -0
  581. package/templates/example-remesh/outputs/v3/out/parts/eye_r.png +0 -0
  582. package/templates/example-remesh/outputs/v3/out/parts/face.png +0 -0
  583. package/templates/example-remesh/outputs/v3/out/parts/lantern.png +0 -0
  584. package/templates/example-remesh/outputs/v3/out/parts/torso.png +0 -0
  585. package/templates/example-remesh/outputs/v3/out/parts.json +188 -0
  586. package/templates/example-remesh/outputs/v3/out/rig/images/background.png +0 -0
  587. package/templates/example-remesh/outputs/v3/out/rig/images/eye_l.png +0 -0
  588. package/templates/example-remesh/outputs/v3/out/rig/images/eye_r.png +0 -0
  589. package/templates/example-remesh/outputs/v3/out/rig/images/face.png +0 -0
  590. package/templates/example-remesh/outputs/v3/out/rig/images/lantern.png +0 -0
  591. package/templates/example-remesh/outputs/v3/out/rig/images/torso.png +0 -0
  592. package/templates/example-remesh/outputs/v3/out/rig/mesh_report.json +15 -0
  593. package/templates/example-remesh/outputs/v3/out/rig/motion.json +137 -0
  594. package/templates/example-remesh/outputs/v3/out/rig/rig.json +536 -0
  595. package/templates/example-remesh/outputs/v3/out/rig/run.json +52 -0
  596. package/templates/example-remesh/project.json +225 -225
  597. package/templates/example-reopened/project.json +289 -289
  598. package/templates/example-split/captions.json +1 -1
package/src/next.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  resolveDiffMapPartsFile,
25
25
  validateDiffMapRecord,
26
26
  } from './diff-map.ts';
27
+ import { partsStructureSnapshot } from './job-acts.ts';
27
28
  import { JOB_BINDING_FILE, type WriterBinding } from './job-outbox.ts';
28
29
  import { isPartsCheckMove, partsCheckRecord } from './parts-check.ts';
29
30
  import { recordedPartsVerdict } from './parts-verdict-record.ts';
@@ -50,9 +51,10 @@ import {
50
51
  STAGE_VALUES,
51
52
  stageIndex,
52
53
  stageOfStep,
53
- stepCoveredByApproval,
54
54
  } from './stages.ts';
55
55
  import type { Json, JsonObject } from './templates.ts';
56
+ import { sceneCurrentAt, sceneRig, SceneError } from './scene.ts';
57
+ import { resolveAgentCitationSpec } from './scene-authority.ts';
56
58
 
57
59
  export const NEXT_SCHEMA = 'rig-create/next@1';
58
60
 
@@ -109,6 +111,8 @@ export interface NextReport {
109
111
  accepted: boolean;
110
112
  refusals: NextRefusal[];
111
113
  warnings?: Finding[];
114
+ /** A view of existing answers, never a new project record. */
115
+ answers?: { question_id: string; field: string; by: Json; at: Json; picks: { ask: Json; option_id: Json; label: Json }[]; command?: string }[];
112
116
  awaits: string[];
113
117
  moves: NextMove[];
114
118
  }
@@ -191,6 +195,81 @@ function isOpenInterviewTodo(finding: Finding, effectiveStage: string): boolean
191
195
  return isOpenInterviewStage(effectiveStage) && finding.code === 'INTERVIEW_INCOMPLETE';
192
196
  }
193
197
 
198
+ function shellWord(value: string): string {
199
+ return /^[A-Za-z0-9_./:-]+$/.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`;
200
+ }
201
+
202
+ function optionCommand(id: string, dir: string): string {
203
+ return `rig-create interview-options ${shellWord(id)} ${shellWord(dir)} --file '<option-set.json>'`;
204
+ }
205
+
206
+ /** The person acts in Review; the agent only hosts and ingests its exported act. */
207
+ function reviewCommands(dir: string, project: JsonObject, move: NextMove): NextMove[] {
208
+ const act = move.review_act;
209
+ if (move.role !== 'human' || move.unanswered_by_record || move.field === 'pauses' || !act) return [move];
210
+ let selector: string;
211
+ let writer: string;
212
+ if (act.kind === 'interview-picks' && act.question_id) {
213
+ selector = `--question ${shellWord(act.question_id)}`;
214
+ writer = `interview-answer ${shellWord(act.question_id)}`;
215
+ } else if (act.kind === 'signoff' && ['interview', 'plan-approved', 'rigging-interview', 'post-interview', 'direction-review'].includes(act.stage)) {
216
+ selector = '--plan';
217
+ writer = `signoff ${act.stage}`;
218
+ } else if (act.kind === 'parts-verdict' && act.draft_id) {
219
+ selector = `--draft ${shellWord(act.draft_id)}`;
220
+ writer = 'parts-review';
221
+ } else if (act.kind === 'signoff' && act.stage === 'parts-review' && act.draft_id) {
222
+ selector = `--draft ${shellWord(act.draft_id)}`;
223
+ const structure = partsStructureSnapshot(dir, project, act.draft_id);
224
+ writer = `signoff parts-review --draft ${shellWord(act.draft_id)} --structure-file ${shellWord(structure.path)}`;
225
+ } else if (act.kind === 'signoff' && act.stage === 'rig-review' && act.version_id) {
226
+ selector = `--rig ${shellWord(act.version_id.slice(1))}`;
227
+ writer = 'signoff rig-review';
228
+ } else if (['rig-review', 'direction-review'].includes(act.stage) && act.kind === 'review-verdict' && act.version_id) {
229
+ const n = act.version_id.slice(1);
230
+ selector = `--rig ${shellWord(n)}`;
231
+ writer = `review ${shellWord(n)}`;
232
+ } else return [move];
233
+ const agent = (command: string, description: string): NextMove => ({
234
+ role: 'agent', field: move.field, awaits: move.awaits, command, act: description,
235
+ });
236
+ const root = shellWord(dir);
237
+ return [
238
+ 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'),
239
+ move,
240
+ 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)' : ''}`),
241
+ agent(`rig-create ${writer} ${root} --from-review '<actId>'`, 'ingest the matching exported Review act; never supply the human answer or words'),
242
+ agent(`rig-create job close ${root}`, 'after successful ingestion, close this job before opening the next Review page'),
243
+ ];
244
+ }
245
+
246
+ function sceneWriteCommand(dir: string, project: JsonObject, rigN: string): string {
247
+ let flags = ` --background '<background.png>'`;
248
+ const item = collectItems(project, { collection: loadCollection(dir) }).find(item => item.id === 'post_composition');
249
+ if (item && (item.state.state === 'user' || item.state.state === 'delegated')) {
250
+ const answer = item.state.answer;
251
+ const citation = { guide: 'post_composition', asks: ['post_composition'],
252
+ ...(item.state.state === 'delegated' ? { delegated: true } : { quote: answer.verbatim! }) };
253
+ try {
254
+ const spec = resolveAgentCitationSpec(dir, project, citation);
255
+ const stage = sceneRig(dir, project, Number(rigN)).stage;
256
+ for (const role of ['background', 'foreground'] as const) {
257
+ const plate = spec[role];
258
+ if (!plate) continue;
259
+ if (role === 'foreground') flags += ` --foreground '<foreground.png>'`;
260
+ const { x, y, width, height } = plate.rect;
261
+ if (x !== stage.x || y !== stage.y || width !== stage.width || height !== stage.height) {
262
+ flags += ` --${role}-rect ${shellWord([x, y, width, height].join(','))}`;
263
+ }
264
+ }
265
+ } catch (error) {
266
+ if (!(error instanceof SceneError)) throw error;
267
+ // The scene writer reports the existing named refusal for an unresolved choice.
268
+ }
269
+ }
270
+ return `rig-create scene write ${shellWord(dir)} --rig ${shellWord(rigN)}${flags} --citations-file '<scene-citations.json>'`;
271
+ }
272
+
194
273
  function candidateAdvance(
195
274
  dir: string,
196
275
  project: JsonObject,
@@ -264,8 +343,8 @@ function candidateAdvance(
264
343
  const checked = checkProject(dir, clone, { now, forwardWrite: true, readOnly: true });
265
344
  if (newFindings(allowed, checked.refusals).length > 0) return null;
266
345
  return partsCheck
267
- ? `rig-create advance ${targetStage} --parts-check ${partsCheck.report} --parts ${partsCheck.root}`
268
- : `rig-create advance ${targetStage}`;
346
+ ? `rig-create advance ${targetStage} ${shellWord(dir)} --parts-check ${shellWord(partsCheck.report)} --parts ${shellWord(partsCheck.root)}`
347
+ : `rig-create advance ${targetStage} ${shellWord(dir)}`;
269
348
  }
270
349
 
271
350
  function candidateStepStatus(
@@ -327,7 +406,7 @@ function candidateStepStatus(
327
406
  const allowed = carriedRefusals(dir, before, { now, forwardWrite: false });
328
407
  const checked = checkProject(dir, clone, { now, forwardWrite: false, readOnly: true });
329
408
  if (newFindings(allowed, checked.refusals).length > 0) return null;
330
- return `rig-create step-status ${stepId} ${nextStatus} --by agent`;
409
+ return `rig-create step-status ${shellWord(stepId)} ${nextStatus} ${shellWord(dir)} --by agent`;
331
410
  }
332
411
 
333
412
  function nextStageInOrder(project: JsonObject, currentStage: string): string | null {
@@ -362,6 +441,7 @@ function resolveLaggingAdvance(
362
441
  }
363
442
  return null;
364
443
  }
444
+ if (stage === 'post' && (!asArray(project.scenes).length || !asArray(project.versions).some(v => isObject(v) && v.kind === 'post'))) return null;
365
445
  const cmd = candidateAdvance(dir, project, nextStage, now);
366
446
  return cmd !== null ? { targetStage: nextStage, command: cmd } : null;
367
447
  }
@@ -473,7 +553,7 @@ function resolveDiffComponentsMove(
473
553
  const recordedPaintingSha = (draftReport.painting as { sha256: string }).sha256;
474
554
  if (stackSha === recordedStackSha && paintingSha === recordedPaintingSha) {
475
555
  return {
476
- command: `cp ${draftReportPath} evidence/diff-components.json`,
556
+ command: `cp ${shellWord(resolve(dir, draftReportPath))} ${shellWord(resolve(dir, 'evidence/diff-components.json'))}`,
477
557
  act: `copy ${draftReportPath} for drafts[${draftId}] to evidence/diff-components.json`,
478
558
  };
479
559
  }
@@ -483,9 +563,9 @@ function resolveDiffComponentsMove(
483
563
  }
484
564
  }
485
565
 
486
- const figureFlag = figureMaskPath !== undefined ? ` --figure ${figureMaskPath}` : '';
566
+ const figureFlag = figureMaskPath !== undefined ? ` --figure ${shellWord(resolve(dir, figureMaskPath))}` : '';
487
567
  return {
488
- command: `rig-parts diff-components --stack ${stackPath} --painting ${paintingPath} --parts ${partsRoot}/parts.json${figureFlag} --floor 2 --threshold 40 --out evidence/diff-components.json`,
568
+ command: `rig-parts diff-components --stack ${shellWord(resolve(dir, stackPath))} --painting ${shellWord(resolve(dir, paintingPath))} --parts ${shellWord(resolve(dir, partsRoot, 'parts.json'))}${figureFlag} --floor 2 --threshold 40 --out ${shellWord(resolve(dir, 'evidence/diff-components.json'))}`,
489
569
  act: `run rig-parts diff-components for drafts[${draftId}]`,
490
570
  };
491
571
  }
@@ -524,13 +604,13 @@ function resolveDiffClassesCommand(dir: string): string {
524
604
  const bytes = diffReportBytes(dir, 'evidence/diff-components.json');
525
605
  const parsed = JSON.parse(bytes.toString('utf8')) as Json;
526
606
  if (isObject(parsed) && reportShape(parsed) && (parsed.components as unknown[]).length === 0) {
527
- return 'rig-create diff-classes --diff-report evidence/diff-components.json --by agent';
607
+ return `rig-create diff-classes ${shellWord(dir)} --diff-report evidence/diff-components.json --by agent`;
528
608
  }
529
609
  } catch {
530
610
  // Fall through to default command with --triage-file.
531
611
  }
532
612
  }
533
- return 'rig-create diff-classes --diff-report evidence/diff-components.json --triage-file evidence/diff-triage.json --by agent';
613
+ return `rig-create diff-classes ${shellWord(dir)} --diff-report evidence/diff-components.json --triage-file evidence/diff-triage.json --by agent`;
534
614
  }
535
615
 
536
616
  export function nextProject(projectDirArg: string, now: number = Date.now()): NextReport {
@@ -543,7 +623,18 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
543
623
  const stage = String(project.stage ?? '');
544
624
  const effectiveStage = String(report.effective_stage ?? stage);
545
625
  const structureWarnings = report.warnings.filter(w => w.code === 'STRUCTURE_DELTA_REVIEW');
546
- const warningFields = structureWarnings.length ? { warnings: structureWarnings } : {};
626
+ const answers = collectItems(project, { collection: loadCollection(dir) }).flatMap(item => {
627
+ const answer = item.state.state === 'user' || item.state.state === 'delegated' || item.state.state === 'not_applicable'
628
+ ? item.state.answer : isObject(item.raw) ? item.raw : null;
629
+ if (!answer) return [];
630
+ return [{ question_id: item.id, field: item.path, by: answer.by ?? null, at: answer.at ?? null,
631
+ picks: asArray(isObject(answer.choice) ? answer.choice.picks : undefined).filter(isObject).map(pick => ({
632
+ ask: pick.ask ?? null, option_id: pick.option_id ?? null, label: isObject(pick.shown) ? pick.shown.label ?? null : null,
633
+ })),
634
+ ...(interviewStageOfGuide(item.id, item.kind === 'post', hasStageOrder(project)) === effectiveStage
635
+ ? { command: optionCommand(item.id, dir) } : {}) }];
636
+ });
637
+ const warningFields = { ...(structureWarnings.length ? { warnings: structureWarnings } : {}), answers };
547
638
  const jobId = readOptionalJobId(dir);
548
639
  const holes = report.holes ?? [];
549
640
 
@@ -559,7 +650,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
559
650
  ? resolveLaggingAdvance(dir, project, stage, now)
560
651
  : null;
561
652
  const isResolvableLagging = (finding: Finding): boolean =>
562
- finding.code === 'STAGE_LAGGING' && laggingAdvance !== null;
653
+ finding.code === 'STAGE_LAGGING' && (laggingAdvance !== null || stage === 'post' && (!asArray(project.scenes).length || !asArray(project.versions).some(v => isObject(v) && v.kind === 'post')));
563
654
 
564
655
  const hasBlockingRefusal =
565
656
  holes.length > 0 ||
@@ -597,14 +688,32 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
597
688
  groups.set(kind, [...(groups.get(kind) ?? []), { version: summary.version, verdict: summary.index }]);
598
689
  }
599
690
  for (const [kind, refs] of groups) {
691
+ if (kind === 'post') {
692
+ // Match the direction writer's authoring gate, including earlier
693
+ // accepted verdicts that a later bounce does not itself reopen.
694
+ const reopens = collectReopens(project, []);
695
+ const closed = collectSignoffs(project, []).some(s => s.stage === 'direction-review'
696
+ && s.checkpoint === null && liveSignoff(reopens, s.stage, s.at))
697
+ || versions.some(v => v.kind === 'post' && asArray(v.verdicts).filter(isObject).some(d =>
698
+ d.review === 'direction-review' && d.verdict === 'accepted'
699
+ && liveSignoff(reopens, 'direction-review', Date.parse(String(d.at)))));
700
+ if (closed) {
701
+ const target = 'reopens[stage=direction-review]';
702
+ addAwait(target);
703
+ moves.push({ role: 'human', field: 'reopens', awaits: target,
704
+ command: `rig-create reopen direction-review ${shellWord(dir)} --by '<human>' --verbatim-file '<absolute-human-words-file>' --source '<reopen-act-id>'`,
705
+ 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.' });
706
+ continue;
707
+ }
708
+ }
600
709
  const field = `versions[n=${n}]`;
601
710
  addAwait(field);
602
711
  const writer = kind === 'rig' ? `rig-version ${n}` : `direction write ${n}`;
603
712
  const inputs = kind === 'rig'
604
- ? '--parts <dir> --rig <dir> --build <dir> --idle <dir> --config <file> --path-adapter <file> --compile-report <file> --toolchain-lock <file> --at-source <file> --at-pointer <pointer> --by <agent>'
713
+ ? '--parts <dir> --rig <dir> --build <dir> --idle <dir> --config <file> --path-adapter <file> --compile-report <file> --toolchain-lock <file> --run-record <run.json> --at-source <file> --at-pointer <pointer> --by <agent>'
605
714
  : '--file <direction.json> --rig <rig-version>';
606
715
  moves.push({ role: 'agent', field: 'versions', awaits: field,
607
- command: `rig-create ${writer} ${inputs} ${refs.map(r => `--answers ${r.version}:${r.verdict}`).join(' ')}`,
716
+ command: `rig-create ${writer} ${shellWord(dir)} ${inputs.replace(/<[^>]+>/g, shellWord)} ${refs.map(r => `--answers ${r.version}:${r.verdict}`).join(' ')}`,
608
717
  act: `build the next ${kind} version with ${writer}, recording answers_feedback ${JSON.stringify(refs)}` });
609
718
  }
610
719
  if (moves.length > 0) return { schema: NEXT_SCHEMA, project_id: String(project.name ?? ''), stage, effective_stage: effectiveStage, accepted: false, refusals, ...warningFields, awaits: awaitsList, moves };
@@ -816,17 +925,11 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
816
925
  });
817
926
  } else {
818
927
  moves.push({
819
- role: 'human',
928
+ role: 'agent',
820
929
  field: answerField,
821
930
  awaits: answerField,
822
- command: null,
823
- act: `review-tool act interview-picks for ${questionPath} (unanswered by record: ${questionPath}.pending_options is not recorded in project.json)`,
824
- review_act: {
825
- kind: 'interview-picks',
826
- stage: effectiveStage,
827
- question_id: item.id,
828
- ...(jobId ? { job_id: jobId } : {}),
829
- },
931
+ command: optionCommand(item.id, dir),
932
+ act: `draft an option-set file for ${item.id}, then register it for a Review pick`,
830
933
  unanswered_by_record: `${questionPath}.pending_options`,
831
934
  });
832
935
  }
@@ -844,28 +947,33 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
844
947
  }
845
948
  }
846
949
 
847
- const needsPlanSteps =
848
- (effectiveStage === 'interview' && steps.length === 0) ||
849
- (effectiveStage === 'post-interview' && !steps.some(s => s.phase === 'post')) ||
850
- (effectiveStage === 'rigging-interview' && !steps.some(step => stepCoveredByApproval(project, step, effectiveStage)));
950
+ const planIds = effectiveStage === 'rigging-interview' ? ['bones', 'meshes', 'constraints', 'motion']
951
+ : effectiveStage === 'post-interview' ? ['camera', 'timing', 'composition'] : ['seethrough', 'assemble'];
952
+ const missingPlanIds = planIds.filter(id => {
953
+ const guide = id === 'camera' ? 'camera_depth' : id === 'timing' ? 'post_timing' : id === 'composition' ? 'post_composition' : id;
954
+ const phase = effectiveStage === 'post-interview' ? 'post' : 'rig';
955
+ return !steps.some(step => step.phase === phase && (step.id === id
956
+ || phase === 'post' && asArray(step.rests_on).includes(guide)));
957
+ });
958
+ const needsPlanSteps = missingPlanIds.length > 0;
851
959
  if (needsPlanSteps) {
852
960
  addAwait('plan.steps');
853
- if (effectiveStage === 'rigging-interview') {
854
- for (const id of ['bones', 'meshes', 'constraints', 'motion']) {
855
- const item = stageItems.find(item => item.id === id);
856
- if (!item || item.state.state === 'silent' || (item.state.state === 'delegated' && !item.state.decided) || steps.some(step => step.id === id)) continue;
857
- moves.push({
858
- role: 'agent',
859
- field: 'plan.steps',
860
- awaits: 'plan.steps',
861
- command: `rig-create plan add ${id} '${dir.replaceAll("'", "'\\''")}' --by agent --phase rig …`,
862
- act: `author the ${id} plan step for approval at rigging-interview; supply order, does, produces, rests-on, bar and checkpoint-proposed`,
863
- unanswered_by_record: 'plan.steps',
864
- });
865
- }
961
+ for (const [index, id] of missingPlanIds.entries()) {
962
+ const guideId = id === 'camera' ? 'camera_depth' : id === 'timing' ? 'post_timing' : id === 'composition' ? 'post_composition' : id;
963
+ const item = stageItems.find(item => item.id === guideId);
964
+ if (!item || item.state.state === 'silent' || (item.state.state === 'delegated' && !item.state.decided)) continue;
965
+ const order = Math.max(0, ...steps.map(step => Number(step.order) || 0)) + index + 1;
966
+ moves.push({ role: 'agent', field: 'plan.steps', awaits: 'plan.steps',
967
+ command: `rig-create plan add ${id} ${shellWord(dir)} --by agent --phase ${effectiveStage === 'post-interview' ? 'post' : 'rig'} --order ${order} --does '<work>' --produces '<result>' --rests-on ${guideId} --bar '<acceptance bar>' --checkpoint-proposed false`,
968
+ act: `author the ${id} plan step for approval at ${effectiveStage}; replace the work, result and acceptance bar placeholders`,
969
+ unanswered_by_record: 'plan.steps' });
866
970
  }
867
971
  }
868
972
 
973
+ const missingStepNames = missingPlanIds.length === planIds.length ? '' : `${missingPlanIds.join(', ')} `;
974
+ const missingStepKind = effectiveStage === 'post-interview' ? 'post' : 'rig';
975
+ const missingPlanReason = `plan.steps has no ${missingStepNames}${missingStepKind} step${missingPlanIds.length === 1 ? '' : 's'}`;
976
+
869
977
  const signoffAwait = `signoffs[stage=${effectiveStage}]`;
870
978
  if (!hasLiveStageSignoff(effectiveStage) && !recordedLapseTargets.has(signoffAwait)) {
871
979
  addAwait(signoffAwait);
@@ -876,10 +984,10 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
876
984
  command: null,
877
985
  act: needsPlanSteps
878
986
  ? effectiveStage === 'rigging-interview'
879
- ? 'review-tool act signoff for stage rigging-interview (unanswered by record: plan.steps has no rig steps approved at rigging-interview)'
880
- : `review-tool act signoff for stage ${effectiveStage} (unanswered by record: plan.steps is empty in project.json)`
987
+ ? `review-tool act signoff for stage rigging-interview (unanswered by record: ${missingPlanReason} approved at rigging-interview)`
988
+ : `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)`
881
989
  : effectiveStage === 'interview'
882
- ? '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'
990
+ ? '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'
883
991
  : `review-tool act signoff for stage ${effectiveStage}`,
884
992
  review_act: {
885
993
  kind: 'signoff',
@@ -992,6 +1100,14 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
992
1100
  : undefined;
993
1101
  const hasApprovedPartsVerdict = hasApprovedPartsVerdictReceipt(dir, project, draftId);
994
1102
 
1103
+ if (effectiveStage === 'parts' && partsRoot !== undefined
1104
+ && candidateAdvance(dir, project, 'parts-review', now, { report: 'evidence/parts-check.json', root: partsRoot }) === null) {
1105
+ addAwait('evidence/parts-check.json');
1106
+ moves.push({ role: 'producer', field: 'drafts', awaits: 'evidence/parts-check.json',
1107
+ command: `rig-parts check-parts --parts ${shellWord(resolve(dir, partsRoot))} --out ${shellWord(resolve(dir, 'evidence'))}`,
1108
+ act: 'produce and retain evidence/parts-check.json before advance parts-review' });
1109
+ }
1110
+
995
1111
  if (effectiveStage === 'parts' && partsRoot !== undefined && existsSync(join(dir, 'evidence/parts-check.json'))) {
996
1112
  const advCmd = candidateAdvance(dir, project, 'parts-review', now, {
997
1113
  report: 'evidence/parts-check.json',
@@ -1026,17 +1142,15 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1026
1142
  });
1027
1143
  }
1028
1144
 
1029
- const hasStructureFile =
1030
- existsSync(join(dir, 'evidence/structure.json')) ||
1031
- existsSync(join(dir, 'evidence/structure-decisions.json'));
1032
- if (draftId !== undefined && hasApprovedPartsVerdict && !hasStructureFile) {
1033
- addAwait('evidence/structure.json');
1145
+ const structure = draftId === undefined ? undefined : partsStructureSnapshot(dir, project, draftId);
1146
+ if (draftId !== undefined && hasApprovedPartsVerdict && structure !== undefined && !structure.valid) {
1147
+ addAwait(structure.path);
1034
1148
  moves.push({
1035
1149
  role: 'agent',
1036
1150
  field: `drafts[${draftId}]`,
1037
- awaits: 'evidence/structure.json',
1038
- command: `rig-create structure-snapshot --draft ${draftId} --out evidence/structure.json`,
1039
- act: `write structure-snapshot for drafts[${draftId}] to evidence/structure.json`,
1151
+ awaits: structure.path,
1152
+ command: `rig-create structure-snapshot ${shellWord(dir)} --draft ${shellWord(draftId)} --out ${shellWord(structure.path)}`,
1153
+ act: `write structure-snapshot for drafts[${draftId}] to ${structure.path}`,
1040
1154
  });
1041
1155
  }
1042
1156
 
@@ -1085,7 +1199,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1085
1199
  awaits: signoffAwait,
1086
1200
  command: null,
1087
1201
  act: hasApprovedPartsVerdict
1088
- ? 'review-tool act signoff for stage parts-review'
1202
+ ? `review-tool act signoff for stage parts-review; after structure-snapshot, ingest rig-create signoff parts-review ${shellWord(dir)} --draft ${shellWord(draftId!)} --structure-file ${shellWord(structure!.path)} --from-review '<actId>'`
1089
1203
  : `review-tool act signoff for stage parts-review (unanswered by record: review_acts[kind=parts-verdict,draft_id=${draftId ?? 'unknown'}] is absent)`,
1090
1204
  review_act: {
1091
1205
  kind: 'signoff',
@@ -1095,7 +1209,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1095
1209
  },
1096
1210
  ...(!hasApprovedPartsVerdict
1097
1211
  ? {
1098
- unanswered_by_record: `review_acts[kind=parts-verdict,draft_id=${draftId ?? 'unknown'}], evidence/structure.json`,
1212
+ unanswered_by_record: `review_acts[kind=parts-verdict,draft_id=${draftId ?? 'unknown'}], ${structure?.path ?? 'structure snapshot'}`,
1099
1213
  }
1100
1214
  : {}),
1101
1215
  });
@@ -1323,7 +1437,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1323
1437
  );
1324
1438
  const nextPostN = postN ?? maxVersionN + 1;
1325
1439
 
1326
- if (effectiveStage === 'post') {
1440
+ if (effectiveStage === 'post' && postN !== null && scenes.length > 0) {
1327
1441
  const advCmd = candidateAdvance(dir, project, 'direction-review', now);
1328
1442
  if (advCmd !== null) {
1329
1443
  moves.push({
@@ -1336,9 +1450,27 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1336
1450
  }
1337
1451
  }
1338
1452
 
1339
- if (scenes.length === 0) {
1340
- addAwait('scenes[n=1]');
1453
+ if (postN === null) {
1454
+ const rig = versions.filter(v => v.kind === 'rig').at(-1);
1455
+ const rigN = typeof rig?.n === 'number' ? String(rig.n) : '<rig-version>';
1456
+ const currentScene = sceneCurrentAt(dir, project, now);
1457
+ if (!isObject(project.direction_contract)) {
1458
+ addAwait('direction_contract');
1459
+ moves.push({ role: 'agent', field: 'direction_contract', awaits: 'direction_contract',
1460
+ command: `rig-create direction --adopt ${shellWord(dir)}`, act: 'adopt direction before authoring the post' });
1461
+ } else if (currentScene === undefined) {
1462
+ addAwait('scenes[n=1]');
1463
+ moves.push({ role: 'agent', field: 'scenes', awaits: 'scenes[n=1]',
1464
+ command: sceneWriteCommand(dir, project, rigN),
1465
+ act: 'author scene inputs matching the current post_composition Review choice, then write the scene' });
1466
+ } else {
1467
+ addAwait(`versions[n=${nextPostN}]`);
1468
+ moves.push({ role: 'agent', field: 'versions', awaits: `versions[n=${nextPostN}]`,
1469
+ command: `rig-create direction write ${nextPostN} ${shellWord(dir)} --file '<direction.json>' --rig ${shellWord(rigN)}`,
1470
+ act: 'author a direction document binding the current scene, then record the post version' });
1471
+ }
1341
1472
  }
1473
+ if (scenes.length === 0) addAwait('scenes[n=1]');
1342
1474
  if (postN === null) {
1343
1475
  addAwait(`versions[n=${nextPostN}]`);
1344
1476
  const verdictAwait = `versions[n=${nextPostN}].verdicts[review=direction-review]`;
@@ -1372,7 +1504,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1372
1504
  field: `versions[v${postN}].verdicts`,
1373
1505
  awaits: verdictAwait,
1374
1506
  command: null,
1375
- 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)`,
1507
+ 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`,
1376
1508
  review_act: {
1377
1509
  kind: 'review-verdict',
1378
1510
  stage: 'direction-review',
@@ -1394,8 +1526,8 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1394
1526
  command: null,
1395
1527
  act:
1396
1528
  postN === null
1397
- ? `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)`
1398
- : `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`,
1529
+ ? `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)`
1530
+ : `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`,
1399
1531
  review_act: {
1400
1532
  kind: 'signoff',
1401
1533
  stage: 'direction-review',
@@ -1443,6 +1575,12 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1443
1575
  });
1444
1576
  }
1445
1577
 
1578
+ const runnableMoves = moves.flatMap(move => {
1579
+ if (move.review_act?.stage === 'direction-review' && move.review_act.kind === 'signoff'
1580
+ && moves.some(other => other.review_act?.stage === 'direction-review' && other.review_act.kind === 'review-verdict')) return [move];
1581
+ return reviewCommands(dir, project, move);
1582
+ });
1583
+
1446
1584
  return {
1447
1585
  schema: NEXT_SCHEMA,
1448
1586
  project_id: String(project.name ?? ''),
@@ -1452,7 +1590,7 @@ export function nextProject(projectDirArg: string, now: number = Date.now()): Ne
1452
1590
  refusals,
1453
1591
  ...warningFields,
1454
1592
  awaits: awaitsList,
1455
- moves,
1593
+ moves: runnableMoves,
1456
1594
  };
1457
1595
  }
1458
1596
 
@@ -8,7 +8,7 @@ export function readVerbatim(file: string): string {
8
8
  try {
9
9
  bytes = readFileSync(file === '-' ? 0 : file);
10
10
  } catch (error) {
11
- refuse('VERBATIM_UNREADABLE', `${file}: ${error instanceof Error ? error.message : String(error)}`);
11
+ refuse('VERBATIM_UNREADABLE', `${file}: ${error instanceof Error ? error.message : String(error)}; --verbatim-file paths resolve against the current working directory, not the project folder; supply an absolute path or run from the folder containing the file`);
12
12
  }
13
13
  try {
14
14
  return new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
package/src/reopen.ts CHANGED
@@ -95,7 +95,7 @@ export function liveSignoff(reopens: readonly Reopen[], stage: string, at: numbe
95
95
  export const REOPEN_HELP = `reopen:
96
96
  <stage> [<project dir>] record a human backward move and set project.stage
97
97
  --by <who> human signer (agent is refused)
98
- --verbatim-file <file> unchanged UTF-8 words, or - for stdin (default)
98
+ --verbatim-file <file> unchanged UTF-8 words; relative to the current working directory, not the project; or - for stdin (default)
99
99
  --source <text> optional origin of the words, separate from verbatim
100
100
  --json print the reopen record
101
101
  The clock supplies at; sign-offs and versions remain history.`;
@@ -1,4 +1,5 @@
1
1
  import { recordedPartsVerdict, recordedPartsFinding } from './parts-verdict-record.ts';
2
+ import reviewPackage from '@rig-c/review/package.json';
2
3
  import { configInputReferences, configInputsLegacy, DIRECTORY_INPUT_RECEIPT, plateReceiptSpec, receiptSpec, type ConfigInputsWarning } from './config-inputs.ts';
3
4
  import { DirectionError, objects as directionObjects, readDirection } from './direction.ts';
4
5
  /** Frozen producer inputs in review's fixed discovery layout (create#38). */
@@ -40,7 +41,7 @@ function checkBuildIdentity(ctx: Pick<Ctx, 'dir' | 'project' | 'refusals' | 'war
40
41
  if (finding.code === 'PARTS_VERDICT_FILE_LEGACY') {
41
42
  if (!ctx.warnings.some(existing => existing.code === finding.code && existing.path === finding.path)) ctx.warnings.push(finding);
42
43
  } else findings.push({ code: 'REVIEW_PACKAGE_PARTS_UNREAD', path: `${path}.files[out/parts.json]`,
43
- message: `${path}.files[out/parts.json]: accepted parts receipt is unavailable (${finding.code}); restore its recorded API response and selected draft before packaging this version` });
44
+ message: `${path}.files[out/parts.json]: accepted parts receipt cannot be read (${finding.code}: ${finding.message}); compare the Review version that recorded the act (not carried by API act receipts) with the current @rig-c/review ${reviewPackage.version} reader. For an act parsing failure, register with a Review version that parses that act, or wait until support lands; preserve the retained bytes. For missing or changed evidence, restore its recorded API response and selected draft before packaging this version` });
44
45
  return;
45
46
  }
46
47
  recordedPartsVerdict(ctx.dir, ctx.project, approval.draft_id, approval.evidence, { requireAvailable: false });
@@ -12,7 +12,8 @@ import type { JsonObject } from './templates.ts';
12
12
 
13
13
  export const SCENE_HELP = `scene write --rig <R> --background <path> [--foreground <path>]
14
14
  [--background-rect x,y,w,h] [--foreground-rect x,y,w,h]
15
- --citations-file <file> [<dir>]
15
+ --citations-file <retained project-relative JSON> [<dir>]
16
+ Retain citations inside the project, for example evidence/scene-src/citations.json; absolute paths are refused.
16
17
  Citations are a role map {background: citation, foreground?: citation}.
17
18
  Each citation names post_composition, asks:["post_composition"], and quote or delegated:true.
18
19
  Paths and rects must match the current ingested post_composition choice.
package/src/scene.ts CHANGED
@@ -9,6 +9,7 @@ import { collectReopens, liveSignoff } from './reopen.ts';
9
9
  import { humanReviewVerdicts, latestAccepted, readVersions } from './review.ts';
10
10
  import { SCENE_CHOICE_MISMATCH, SCENE_CHOICE_MISSING, sceneAuthor, validateAgentSceneAuthority } from './scene-authority.ts';
11
11
  import { reviewPackageHash } from './signoff-target.ts';
12
+ import { samePublicationReviewPair } from './signoff-pair.ts';
12
13
  import type { Json, JsonObject } from './templates.ts';
13
14
 
14
15
  export { SCENE_CHOICE_MISMATCH, SCENE_CHOICE_MISSING, sceneAuthor };
@@ -197,7 +198,8 @@ function validateSceneAcceptance(project: JsonObject, rig: JsonObject): JsonObje
197
198
  const signature = collectSignoffs(project, []).find(value => value.stage === identity.stage && value.checkpoint === identity.checkpoint && value.record.at === identity.at)?.record;
198
199
  const match = /^versions\[(\d+)\]\.verdicts\[(\d+)\]$/.exec(String(acceptance.verdict));
199
200
  const verdict = match && Number(match[1]) === index ? humanReviewVerdicts(version.verdicts, 'rig-review').find(value => value.index === Number(match[2]) && value.record.verdict === 'accepted') : undefined;
200
- if (!verdict || !Number.isFinite(Date.parse(String(verdict.record.at))) || Date.parse(String(verdict.record.at)) > Date.parse(String(identity.at))) sceneFail('SCENE_RIG_STALE', 'scene.rig.acceptance.verdict', 'the cited rig must have been human-accepted before this signoff');
201
+ if (!verdict || !Number.isFinite(Date.parse(String(verdict.record.at))) || Date.parse(String(verdict.record.at)) > Date.parse(String(identity.at))
202
+ && (!signature || !samePublicationReviewPair(project, signature, version, verdict.index))) sceneFail('SCENE_RIG_STALE', 'scene.rig.acceptance.verdict', 'the cited rig needs human acceptance before signing or a same-publication, same-version human accepted pair');
201
203
  const pkg = version.review_package;
202
204
  const target = { version: version.n!, verdict: acceptance.verdict!, review_package: { path: `versions[${index}].review_package`, sha256: isObject(pkg) ? reviewPackageHash(pkg) : '' } };
203
205
  if (!signature || !equal(signature.target, target) || !equal(acceptance.review_package, target.review_package)) sceneFail('SCENE_ACCEPTANCE_STALE', 'scene.rig.acceptance.review_package', 'restore the recorded acceptance target and its matching package sha256');
@@ -0,0 +1,60 @@
1
+ /** Review act order is immaterial only within one human-reviewed publication. */
2
+ import { isDeepStrictEqual } from 'node:util';
3
+ import { asArray, isObject, type Finding } from './check.ts';
4
+ import { decodeReviewAct, isRecordDirectionSignoff, reviewActFindings, reviewActSignoff, SIGNOFF_TARGET_KINDS, signoffActVersion } from './review-act.ts';
5
+ import type { JsonObject } from './templates.ts';
6
+
7
+ export const SIGNOFF_PAIR_SINCE = '2026-11-13T00:00:00Z';
8
+
9
+ /** Trust decoded immutable acts and their unique ledger mappings, never copied identity fields. */
10
+ export function samePublicationReviewPair(project: JsonObject, signoff: JsonObject, version: JsonObject, verdictIndex: number): boolean {
11
+ if (reviewActFindings(project).length) return false;
12
+ try {
13
+ const receipts = asArray(project.review_acts).filter(isObject);
14
+ const signatures = receipts.filter(entry => entry.kind === 'signoff' && typeof entry.bytes === 'string'
15
+ && reviewActSignoff(decodeReviewAct(entry.bytes, 'signoff')).source === signoff.source);
16
+ const verdicts = receipts.filter(entry => entry.version === version.n && entry.verdict === verdictIndex);
17
+ if (signatures.length !== 1 || verdicts.length !== 1) return false;
18
+ const signed = decodeReviewAct(String(signatures[0]!.bytes), 'signoff');
19
+ // The validated compact record receipt binds the post, record hash and exact verdict;
20
+ // record-source acts deliberately have no model selector.
21
+ const signedVersion = isRecordDirectionSignoff(signed) ? Number(signatures[0]!.target_version) : signoffActVersion(signed);
22
+ const accepted = decodeReviewAct(String(verdicts[0]!.bytes));
23
+ const selector = accepted.source.selector;
24
+ const verdict = asArray(version.verdicts)[verdictIndex];
25
+ return isObject(verdict) && verdict.verdict === 'accepted'
26
+ && Object.entries(reviewActSignoff(signed)).every(([key, value]) => isDeepStrictEqual(signoff[key], value))
27
+ && signed.value.stage === signoff.stage && accepted.value.stage === signoff.stage
28
+ && signedVersion === version.n && selector !== null && 'version' in selector && selector.version === version.n
29
+ && selector.kind === SIGNOFF_TARGET_KINDS[String(signoff.stage)]
30
+ && signed.jobId === accepted.jobId && signed.publicationId === accepted.publicationId;
31
+ } catch { return false; }
32
+ }
33
+
34
+ /** A newly ingested verdict must not complete an invalid pair, including a historical signature. */
35
+ export function ingestedVerdictPairFinding(project: JsonObject, version: number, verdict: number): Finding | undefined {
36
+ const index = asArray(project.versions).findIndex(raw => isObject(raw) && raw.n === version);
37
+ for (const [i, signoff] of asArray(project.signoffs).entries()) {
38
+ if (!isObject(signoff) || !isObject(signoff.target) || signoff.target.version !== version
39
+ || signoff.target.verdict !== `versions[${index}].verdicts[${verdict}]`) continue;
40
+ const finding = signoffPairFinding(project, signoff, `signoffs[${i}]`, true);
41
+ if (finding) return finding;
42
+ }
43
+ }
44
+
45
+ /** Check gates history by the signature's date; ingest always enforces the current contract. */
46
+ export function signoffPairFinding(project: JsonObject, signoff: JsonObject, path: string, ingest = false): Finding | undefined {
47
+ if (!(String(signoff.stage) in SIGNOFF_TARGET_KINDS) || !isObject(signoff.target)) return;
48
+ const target = signoff.target;
49
+ const match = /^versions\[(\d+)\]\.verdicts\[(\d+)\]$/.exec(String(target.verdict));
50
+ const version = match ? asArray(project.versions)[Number(match[1])] : undefined;
51
+ if (!match || !isObject(version) || version.n !== target.version) return;
52
+ const verdictIndex = Number(match[2]);
53
+ const verdict = asArray(version.verdicts)[verdictIndex];
54
+ if (!isObject(verdict) || !(Date.parse(String(verdict.at)) > Date.parse(String(signoff.at)))
55
+ || samePublicationReviewPair(project, signoff, version, verdictIndex)) return;
56
+ const legacy = !ingest && Date.parse(String(signoff.at)) < Date.parse(SIGNOFF_PAIR_SINCE);
57
+ const at = `${path}.target.verdict`;
58
+ return { code: `SIGNOFF_PAIR_MISMATCH${legacy ? '_LEGACY' : ''}`, path: at,
59
+ message: `${at}: the verdict follows this signoff without a same-publication, same-version human accepted pair; accept the intended version and sign it again in Review, then ingest both acts` };
60
+ }
@@ -10,6 +10,7 @@ import { checkReviewPackages } from './review-package.ts';
10
10
  import { refuse } from './refusal.ts';
11
11
  import { SIGNOFF_TARGET_KINDS } from './review-act.ts';
12
12
  import { sorted } from './step-hash.ts';
13
+ import { signoffPairFinding } from './signoff-pair.ts';
13
14
  import type { Json, JsonObject } from './templates.ts';
14
15
 
15
16
  export const SIGNOFF_TARGET_SINCE = '2026-11-06T00:00:00Z';
@@ -75,7 +76,11 @@ export function checkSignoffTarget(dir: string, project: JsonObject, signoff: Js
75
76
  if (!isDeepStrictEqual(target, expected)) throw Error(expected.outputs ? 'outputs changed since signing' : stage === 'rig-review' ? 'review_package changed since signing' : expected.direction ? 'direction changed since signing' : 'post config changed since signing');
76
77
  } catch (error) { reason = error instanceof Error ? error.message : String(error); }
77
78
  }
78
- if (!reason) return;
79
+ if (!reason) {
80
+ const pair = signoffPairFinding(project, signoff, path);
81
+ if (pair) (pair.code.endsWith('_LEGACY') ? warnings : refusals).push(pair);
82
+ return;
83
+ }
79
84
  const legacy = Date.parse(String(signoff.at)) < Date.parse(SIGNOFF_TARGET_SINCE);
80
85
  const code = `SIGNOFF_TARGET_${missing ? 'MISSING' : 'STALE'}${legacy ? '_LEGACY' : ''}`;
81
86
  const at = `${path}.target`;
@@ -120,8 +125,6 @@ export function selectSignoffTarget(dir: string, project: JsonObject, stage: str
120
125
  if (mask) refuse(mask.code, mask.message);
121
126
  if (ctx.refusals.length || ctx.warnings.some(w => w.code === 'REVIEW_PACKAGE_MISSING')) fail('review package is missing or differs from its recorded binding');
122
127
  }
123
- const errors: Finding[] = [];
124
- checkSignoffTarget(dir, project, { stage, target, at: SIGNOFF_TARGET_SINCE }, `signoffs[${asArray(project.signoffs).length}]`, errors, []);
125
- if (errors[0]) refuse(errors[0].code, errors[0].message);
128
+ // The writer validates the actual dated signature after attaching its immutable receipt.
126
129
  return target;
127
130
  }