devrites 7.2.8 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +1 -1
  3. package/docs/candidate-integrity.md +10 -0
  4. package/docs/cli.md +7 -1
  5. package/docs/command-map.md +5 -2
  6. package/docs/engine/commands.md +28 -4
  7. package/docs/orchestration.md +26 -13
  8. package/docs/skills.md +5 -0
  9. package/engine/internal/acceptance/cli.go +27 -26
  10. package/engine/internal/acceptance/preconditions.go +1 -1
  11. package/engine/internal/acceptance/run.go +42 -16
  12. package/engine/internal/acceptance/transcript.go +236 -45
  13. package/engine/internal/devritespaths/paths.go +16 -3
  14. package/engine/internal/gate/gate.go +6 -0
  15. package/engine/internal/lib/candidate.go +20 -7
  16. package/engine/internal/lib/candidate_coverage.go +2 -19
  17. package/engine/internal/lib/closeout.go +16 -4
  18. package/engine/internal/lib/context.go +64 -45
  19. package/engine/internal/lib/context_io.go +171 -0
  20. package/engine/internal/lib/detect.go +8 -8
  21. package/engine/internal/lib/dispatch.go +2 -0
  22. package/engine/internal/lib/packet.go +37 -7
  23. package/engine/internal/lib/packet_freeze.go +60 -12
  24. package/engine/internal/lib/packet_integrity.go +179 -0
  25. package/engine/internal/lib/perturb.go +3 -3
  26. package/engine/internal/lib/slicecheck.go +7 -1
  27. package/engine/internal/lib/taskgraph.go +20 -36
  28. package/engine/internal/lib/triggers.go +28 -29
  29. package/engine/internal/lib/workspace_pool.go +330 -0
  30. package/engine/internal/parallel/cli.go +190 -49
  31. package/engine/internal/parallel/git.go +47 -14
  32. package/engine/internal/parallel/landing.go +232 -0
  33. package/engine/internal/parallel/lease.go +97 -18
  34. package/engine/internal/parallel/ops.go +312 -155
  35. package/engine/internal/parallel/pathdisjoint.go +48 -4
  36. package/engine/internal/parallel/prune.go +133 -0
  37. package/engine/internal/parallel/repository.go +239 -0
  38. package/engine/internal/parallel/select.go +64 -42
  39. package/engine/main.go +2 -1
  40. package/pack/.claude/agents/devrites-proof-runner.md +16 -9
  41. package/pack/.claude/skills/devrites-lib/SKILL.md +2 -0
  42. package/pack/.claude/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  43. package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  44. package/pack/.claude/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  45. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  46. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +1 -1
  47. package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  48. package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +18 -9
  49. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  50. package/pack/.claude/skills/rite-autocomplete/SKILL.md +13 -10
  51. package/pack/.claude/skills/rite-autocomplete/reference/lookahead.md +4 -4
  52. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +13 -9
  53. package/pack/.claude/skills/rite-build/SKILL.md +13 -10
  54. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +1 -1
  55. package/pack/.claude/skills/rite-build/reference/checkpoint.md +1 -1
  56. package/pack/.claude/skills/rite-build/reference/parallel-batch.md +57 -36
  57. package/pack/.claude/skills/rite-build/reference/phase-contract.md +8 -5
  58. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +7 -7
  59. package/pack/.claude/skills/rite-clarify/SKILL.md +2 -2
  60. package/pack/.claude/skills/rite-converge/SKILL.md +4 -4
  61. package/pack/.claude/skills/rite-define/SKILL.md +7 -3
  62. package/pack/.claude/skills/rite-define/reference/plan-template.md +4 -2
  63. package/pack/.claude/skills/rite-plan/SKILL.md +11 -8
  64. package/pack/.claude/skills/rite-plan/reference/dependency-graph.md +9 -2
  65. package/pack/.claude/skills/rite-plan/reference/slicing.md +2 -0
  66. package/pack/.claude/skills/rite-polish/SKILL.md +3 -3
  67. package/pack/.claude/skills/rite-prove/SKILL.md +9 -5
  68. package/pack/.claude/skills/rite-resolve/SKILL.md +3 -3
  69. package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +2 -0
  70. package/pack/.claude/skills/rite-review/SKILL.md +4 -3
  71. package/pack/.claude/skills/rite-review/reference/feature-scoped-review.md +2 -2
  72. package/pack/.claude/skills/rite-seal/SKILL.md +1 -1
  73. package/pack/.claude/skills/rite-seal/reference/phase-contract.md +1 -1
  74. package/pack/.claude/skills/rite-ship/SKILL.md +2 -2
  75. package/pack/.claude/skills/rite-ship/reference/git-ship.md +2 -2
  76. package/pack/.claude/skills/rite-spec/SKILL.md +8 -5
  77. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +5 -0
  78. package/pack/.claude/skills/rite-temper/SKILL.md +3 -3
  79. package/pack/.claude/skills/rite-vet/SKILL.md +9 -5
  80. package/pack/.claude/skills/rite-vet/reference/review-axes.md +12 -5
  81. package/pack/generated/claude/agents/devrites-proof-runner.md +16 -9
  82. package/pack/generated/claude/skills/devrites-lib/SKILL.md +2 -0
  83. package/pack/generated/claude/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  84. package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  85. package/pack/generated/claude/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  86. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  87. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +1 -1
  88. package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  89. package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +18 -9
  90. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  91. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +13 -10
  92. package/pack/generated/claude/skills/rite-autocomplete/reference/lookahead.md +4 -4
  93. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +13 -9
  94. package/pack/generated/claude/skills/rite-build/SKILL.md +13 -10
  95. package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +1 -1
  96. package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +1 -1
  97. package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +57 -36
  98. package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +8 -5
  99. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +7 -7
  100. package/pack/generated/claude/skills/rite-clarify/SKILL.md +2 -2
  101. package/pack/generated/claude/skills/rite-converge/SKILL.md +4 -4
  102. package/pack/generated/claude/skills/rite-define/SKILL.md +7 -3
  103. package/pack/generated/claude/skills/rite-define/reference/plan-template.md +4 -2
  104. package/pack/generated/claude/skills/rite-plan/SKILL.md +11 -8
  105. package/pack/generated/claude/skills/rite-plan/reference/dependency-graph.md +9 -2
  106. package/pack/generated/claude/skills/rite-plan/reference/slicing.md +2 -0
  107. package/pack/generated/claude/skills/rite-polish/SKILL.md +3 -3
  108. package/pack/generated/claude/skills/rite-prove/SKILL.md +9 -5
  109. package/pack/generated/claude/skills/rite-resolve/SKILL.md +3 -3
  110. package/pack/generated/claude/skills/rite-resolve/reference/answer-protocol.md +2 -0
  111. package/pack/generated/claude/skills/rite-review/SKILL.md +4 -3
  112. package/pack/generated/claude/skills/rite-review/reference/feature-scoped-review.md +2 -2
  113. package/pack/generated/claude/skills/rite-seal/SKILL.md +1 -1
  114. package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +1 -1
  115. package/pack/generated/claude/skills/rite-ship/SKILL.md +2 -2
  116. package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +2 -2
  117. package/pack/generated/claude/skills/rite-spec/SKILL.md +8 -5
  118. package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +5 -0
  119. package/pack/generated/claude/skills/rite-temper/SKILL.md +3 -3
  120. package/pack/generated/claude/skills/rite-vet/SKILL.md +9 -5
  121. package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +12 -5
  122. package/pack/generated/codex/agents/devrites-proof-runner.toml +16 -9
  123. package/pack/generated/codex/skills/devrites-lib/SKILL.md +2 -0
  124. package/pack/generated/codex/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  125. package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  126. package/pack/generated/codex/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  127. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  128. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +1 -1
  129. package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  130. package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +18 -9
  131. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  132. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +13 -10
  133. package/pack/generated/codex/skills/rite-autocomplete/reference/lookahead.md +4 -4
  134. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +13 -9
  135. package/pack/generated/codex/skills/rite-build/SKILL.md +13 -10
  136. package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +1 -1
  137. package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +1 -1
  138. package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +57 -36
  139. package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +8 -5
  140. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +7 -7
  141. package/pack/generated/codex/skills/rite-clarify/SKILL.md +2 -2
  142. package/pack/generated/codex/skills/rite-converge/SKILL.md +4 -4
  143. package/pack/generated/codex/skills/rite-define/SKILL.md +7 -3
  144. package/pack/generated/codex/skills/rite-define/reference/plan-template.md +4 -2
  145. package/pack/generated/codex/skills/rite-plan/SKILL.md +11 -8
  146. package/pack/generated/codex/skills/rite-plan/reference/dependency-graph.md +9 -2
  147. package/pack/generated/codex/skills/rite-plan/reference/slicing.md +2 -0
  148. package/pack/generated/codex/skills/rite-polish/SKILL.md +3 -3
  149. package/pack/generated/codex/skills/rite-prove/SKILL.md +9 -5
  150. package/pack/generated/codex/skills/rite-resolve/SKILL.md +3 -3
  151. package/pack/generated/codex/skills/rite-resolve/reference/answer-protocol.md +2 -0
  152. package/pack/generated/codex/skills/rite-review/SKILL.md +4 -3
  153. package/pack/generated/codex/skills/rite-review/reference/feature-scoped-review.md +2 -2
  154. package/pack/generated/codex/skills/rite-seal/SKILL.md +1 -1
  155. package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +1 -1
  156. package/pack/generated/codex/skills/rite-ship/SKILL.md +2 -2
  157. package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +2 -2
  158. package/pack/generated/codex/skills/rite-spec/SKILL.md +8 -5
  159. package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +5 -0
  160. package/pack/generated/codex/skills/rite-temper/SKILL.md +3 -3
  161. package/pack/generated/codex/skills/rite-vet/SKILL.md +9 -5
  162. package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +12 -5
  163. package/pack/generated/devin/agents/devrites-proof-runner.md +16 -9
  164. package/pack/generated/devin/skills/devrites-lib/SKILL.md +2 -0
  165. package/pack/generated/devin/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  166. package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  167. package/pack/generated/devin/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  168. package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  169. package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +1 -1
  170. package/pack/generated/devin/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  171. package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +18 -9
  172. package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  173. package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +13 -10
  174. package/pack/generated/devin/skills/rite-autocomplete/reference/lookahead.md +4 -4
  175. package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +13 -9
  176. package/pack/generated/devin/skills/rite-build/SKILL.md +13 -10
  177. package/pack/generated/devin/skills/rite-build/reference/afk-discipline.md +1 -1
  178. package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +1 -1
  179. package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +57 -36
  180. package/pack/generated/devin/skills/rite-build/reference/phase-contract.md +8 -5
  181. package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +7 -7
  182. package/pack/generated/devin/skills/rite-clarify/SKILL.md +2 -2
  183. package/pack/generated/devin/skills/rite-converge/SKILL.md +4 -4
  184. package/pack/generated/devin/skills/rite-define/SKILL.md +7 -3
  185. package/pack/generated/devin/skills/rite-define/reference/plan-template.md +4 -2
  186. package/pack/generated/devin/skills/rite-plan/SKILL.md +11 -8
  187. package/pack/generated/devin/skills/rite-plan/reference/dependency-graph.md +9 -2
  188. package/pack/generated/devin/skills/rite-plan/reference/slicing.md +2 -0
  189. package/pack/generated/devin/skills/rite-polish/SKILL.md +3 -3
  190. package/pack/generated/devin/skills/rite-prove/SKILL.md +9 -5
  191. package/pack/generated/devin/skills/rite-resolve/SKILL.md +3 -3
  192. package/pack/generated/devin/skills/rite-resolve/reference/answer-protocol.md +2 -0
  193. package/pack/generated/devin/skills/rite-review/SKILL.md +4 -3
  194. package/pack/generated/devin/skills/rite-review/reference/feature-scoped-review.md +2 -2
  195. package/pack/generated/devin/skills/rite-seal/SKILL.md +1 -1
  196. package/pack/generated/devin/skills/rite-seal/reference/phase-contract.md +1 -1
  197. package/pack/generated/devin/skills/rite-ship/SKILL.md +2 -2
  198. package/pack/generated/devin/skills/rite-ship/reference/git-ship.md +2 -2
  199. package/pack/generated/devin/skills/rite-spec/SKILL.md +8 -5
  200. package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +5 -0
  201. package/pack/generated/devin/skills/rite-temper/SKILL.md +3 -3
  202. package/pack/generated/devin/skills/rite-vet/SKILL.md +9 -5
  203. package/pack/generated/devin/skills/rite-vet/reference/review-axes.md +12 -5
  204. package/pack/generated/dsh/agents/devrites-proof-runner.md +16 -9
  205. package/pack/generated/dsh/runtime/cordis.patch.yml +1 -1
  206. package/pack/generated/dsh/skills/devrites-lib/SKILL.md +2 -0
  207. package/pack/generated/dsh/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  208. package/pack/generated/dsh/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  209. package/pack/generated/dsh/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  210. package/pack/generated/dsh/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  211. package/pack/generated/dsh/skills/devrites-lib/reference/standards/agents.md +1 -1
  212. package/pack/generated/dsh/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  213. package/pack/generated/dsh/skills/devrites-lib/reference/standards/gates.md +18 -9
  214. package/pack/generated/dsh/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  215. package/pack/generated/dsh/skills/rite-autocomplete/SKILL.md +13 -10
  216. package/pack/generated/dsh/skills/rite-autocomplete/reference/lookahead.md +4 -4
  217. package/pack/generated/dsh/skills/rite-autocomplete/reference/loop.md +13 -9
  218. package/pack/generated/dsh/skills/rite-build/SKILL.md +13 -10
  219. package/pack/generated/dsh/skills/rite-build/reference/afk-discipline.md +1 -1
  220. package/pack/generated/dsh/skills/rite-build/reference/checkpoint.md +1 -1
  221. package/pack/generated/dsh/skills/rite-build/reference/parallel-batch.md +57 -36
  222. package/pack/generated/dsh/skills/rite-build/reference/phase-contract.md +8 -5
  223. package/pack/generated/dsh/skills/rite-build/reference/wright-dispatch.md +7 -7
  224. package/pack/generated/dsh/skills/rite-clarify/SKILL.md +2 -2
  225. package/pack/generated/dsh/skills/rite-converge/SKILL.md +4 -4
  226. package/pack/generated/dsh/skills/rite-define/SKILL.md +7 -3
  227. package/pack/generated/dsh/skills/rite-define/reference/plan-template.md +4 -2
  228. package/pack/generated/dsh/skills/rite-plan/SKILL.md +11 -8
  229. package/pack/generated/dsh/skills/rite-plan/reference/dependency-graph.md +9 -2
  230. package/pack/generated/dsh/skills/rite-plan/reference/slicing.md +2 -0
  231. package/pack/generated/dsh/skills/rite-polish/SKILL.md +3 -3
  232. package/pack/generated/dsh/skills/rite-prove/SKILL.md +9 -5
  233. package/pack/generated/dsh/skills/rite-resolve/SKILL.md +3 -3
  234. package/pack/generated/dsh/skills/rite-resolve/reference/answer-protocol.md +2 -0
  235. package/pack/generated/dsh/skills/rite-review/SKILL.md +4 -3
  236. package/pack/generated/dsh/skills/rite-review/reference/feature-scoped-review.md +2 -2
  237. package/pack/generated/dsh/skills/rite-seal/SKILL.md +1 -1
  238. package/pack/generated/dsh/skills/rite-seal/reference/phase-contract.md +1 -1
  239. package/pack/generated/dsh/skills/rite-ship/SKILL.md +2 -2
  240. package/pack/generated/dsh/skills/rite-ship/reference/git-ship.md +2 -2
  241. package/pack/generated/dsh/skills/rite-spec/SKILL.md +8 -5
  242. package/pack/generated/dsh/skills/rite-spec/reference/state-workspace.md +5 -0
  243. package/pack/generated/dsh/skills/rite-temper/SKILL.md +3 -3
  244. package/pack/generated/dsh/skills/rite-vet/SKILL.md +9 -5
  245. package/pack/generated/dsh/skills/rite-vet/reference/review-axes.md +12 -5
  246. package/pack/generated/omp/agents/devrites-proof-runner.md +16 -9
  247. package/pack/generated/omp/commands/rite-build.md +1 -1
  248. package/pack/generated/omp/skills/devrites-lib/SKILL.md +2 -0
  249. package/pack/generated/omp/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  250. package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  251. package/pack/generated/omp/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  252. package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  253. package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +1 -1
  254. package/pack/generated/omp/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  255. package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +18 -9
  256. package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  257. package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +13 -10
  258. package/pack/generated/omp/skills/rite-autocomplete/reference/lookahead.md +4 -4
  259. package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +13 -9
  260. package/pack/generated/omp/skills/rite-build/SKILL.md +13 -10
  261. package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +1 -1
  262. package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +1 -1
  263. package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +57 -36
  264. package/pack/generated/omp/skills/rite-build/reference/phase-contract.md +8 -5
  265. package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +7 -7
  266. package/pack/generated/omp/skills/rite-clarify/SKILL.md +2 -2
  267. package/pack/generated/omp/skills/rite-converge/SKILL.md +4 -4
  268. package/pack/generated/omp/skills/rite-define/SKILL.md +7 -3
  269. package/pack/generated/omp/skills/rite-define/reference/plan-template.md +4 -2
  270. package/pack/generated/omp/skills/rite-plan/SKILL.md +11 -8
  271. package/pack/generated/omp/skills/rite-plan/reference/dependency-graph.md +9 -2
  272. package/pack/generated/omp/skills/rite-plan/reference/slicing.md +2 -0
  273. package/pack/generated/omp/skills/rite-polish/SKILL.md +3 -3
  274. package/pack/generated/omp/skills/rite-prove/SKILL.md +9 -5
  275. package/pack/generated/omp/skills/rite-resolve/SKILL.md +3 -3
  276. package/pack/generated/omp/skills/rite-resolve/reference/answer-protocol.md +2 -0
  277. package/pack/generated/omp/skills/rite-review/SKILL.md +4 -3
  278. package/pack/generated/omp/skills/rite-review/reference/feature-scoped-review.md +2 -2
  279. package/pack/generated/omp/skills/rite-seal/SKILL.md +1 -1
  280. package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +1 -1
  281. package/pack/generated/omp/skills/rite-ship/SKILL.md +2 -2
  282. package/pack/generated/omp/skills/rite-ship/reference/git-ship.md +2 -2
  283. package/pack/generated/omp/skills/rite-spec/SKILL.md +8 -5
  284. package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +5 -0
  285. package/pack/generated/omp/skills/rite-temper/SKILL.md +3 -3
  286. package/pack/generated/omp/skills/rite-vet/SKILL.md +9 -5
  287. package/pack/generated/omp/skills/rite-vet/reference/review-axes.md +12 -5
  288. package/pack/generated/pi/agents/devrites-proof-runner.md +16 -9
  289. package/pack/generated/pi/prompts/rite-build.md +1 -1
  290. package/pack/generated/pi/skills/devrites-lib/SKILL.md +2 -0
  291. package/pack/generated/pi/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  292. package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  293. package/pack/generated/pi/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  294. package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  295. package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +1 -1
  296. package/pack/generated/pi/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  297. package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +18 -9
  298. package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  299. package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +13 -10
  300. package/pack/generated/pi/skills/rite-autocomplete/reference/lookahead.md +4 -4
  301. package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +13 -9
  302. package/pack/generated/pi/skills/rite-build/SKILL.md +13 -10
  303. package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +1 -1
  304. package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +1 -1
  305. package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +57 -36
  306. package/pack/generated/pi/skills/rite-build/reference/phase-contract.md +8 -5
  307. package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +7 -7
  308. package/pack/generated/pi/skills/rite-clarify/SKILL.md +2 -2
  309. package/pack/generated/pi/skills/rite-converge/SKILL.md +4 -4
  310. package/pack/generated/pi/skills/rite-define/SKILL.md +7 -3
  311. package/pack/generated/pi/skills/rite-define/reference/plan-template.md +4 -2
  312. package/pack/generated/pi/skills/rite-plan/SKILL.md +11 -8
  313. package/pack/generated/pi/skills/rite-plan/reference/dependency-graph.md +9 -2
  314. package/pack/generated/pi/skills/rite-plan/reference/slicing.md +2 -0
  315. package/pack/generated/pi/skills/rite-polish/SKILL.md +3 -3
  316. package/pack/generated/pi/skills/rite-prove/SKILL.md +9 -5
  317. package/pack/generated/pi/skills/rite-resolve/SKILL.md +3 -3
  318. package/pack/generated/pi/skills/rite-resolve/reference/answer-protocol.md +2 -0
  319. package/pack/generated/pi/skills/rite-review/SKILL.md +4 -3
  320. package/pack/generated/pi/skills/rite-review/reference/feature-scoped-review.md +2 -2
  321. package/pack/generated/pi/skills/rite-seal/SKILL.md +1 -1
  322. package/pack/generated/pi/skills/rite-seal/reference/phase-contract.md +1 -1
  323. package/pack/generated/pi/skills/rite-ship/SKILL.md +2 -2
  324. package/pack/generated/pi/skills/rite-ship/reference/git-ship.md +2 -2
  325. package/pack/generated/pi/skills/rite-spec/SKILL.md +8 -5
  326. package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +5 -0
  327. package/pack/generated/pi/skills/rite-temper/SKILL.md +3 -3
  328. package/pack/generated/pi/skills/rite-vet/SKILL.md +9 -5
  329. package/pack/generated/pi/skills/rite-vet/reference/review-axes.md +12 -5
  330. package/package.json +1 -1
@@ -20,8 +20,47 @@ var winAbsRE = regexp.MustCompile(`(?i)^[A-Za-z]:[/\\]`)
20
20
 
21
21
  // SlicePaths is one path-disjoint eligibility unit.
22
22
  type SlicePaths struct {
23
- ID string `json:"id"`
24
- Paths []string `json:"paths"`
23
+ ID string `json:"id"`
24
+ Workspace string `json:"workspace,omitempty"`
25
+ Paths []string `json:"paths"`
26
+ }
27
+
28
+ // SliceKey identifies a slice in its source workspace; empty means controller.
29
+ func SliceKey(workspace, id string) string {
30
+ if workspace == "" {
31
+ return id
32
+ }
33
+ return workspace + "/" + id
34
+ }
35
+
36
+ func normalizeSlices(controller string, slices []SlicePaths, root string) ([]SlicePaths, error) {
37
+ normalized := make([]SlicePaths, 0, len(slices))
38
+ seen := make(map[string]bool, len(slices))
39
+ for _, item := range slices {
40
+ if err := validateSliceID(item.ID); err != nil {
41
+ return nil, err
42
+ }
43
+ if item.Workspace != "" {
44
+ if err := validateSlug(item.Workspace); err != nil {
45
+ return nil, err
46
+ }
47
+ if item.Workspace == controller {
48
+ item.Workspace = ""
49
+ }
50
+ }
51
+ key := SliceKey(item.Workspace, item.ID)
52
+ if seen[key] {
53
+ return nil, fmt.Errorf("duplicate slice id %q", key)
54
+ }
55
+ seen[key] = true
56
+ paths, err := validateSlicePaths(item.Paths, fmt.Sprintf("slice %q", key), root)
57
+ if err != nil {
58
+ return nil, err
59
+ }
60
+ item.Paths = paths
61
+ normalized = append(normalized, item)
62
+ }
63
+ return normalized, nil
25
64
  }
26
65
 
27
66
  // NormalizePath mirrors scripts/check-path-disjoint.py: slash-normalize, reject
@@ -116,11 +155,16 @@ func CheckPathDisjoint(slices []SlicePaths, root string) ([]string, error) {
116
155
  for index, item := range slices {
117
156
  label := fmt.Sprintf("slice %d", index)
118
157
  if item.ID != "" {
119
- label = fmt.Sprintf("slice %q", item.ID)
120
- ids = append(ids, item.ID)
158
+ label = fmt.Sprintf("slice %q", SliceKey(item.Workspace, item.ID))
159
+ ids = append(ids, SliceKey(item.Workspace, item.ID))
121
160
  } else {
122
161
  ids = append(ids, fmt.Sprintf("%d", index))
123
162
  }
163
+ if item.Workspace != "" {
164
+ if err := validateSlug(item.Workspace); err != nil {
165
+ return nil, err
166
+ }
167
+ }
124
168
  paths, err := validateSlicePaths(item.Paths, label, root)
125
169
  if err != nil {
126
170
  return nil, err
@@ -0,0 +1,133 @@
1
+ package parallel
2
+
3
+ import (
4
+ "errors"
5
+ "fmt"
6
+ "os"
7
+ )
8
+
9
+ func fullyClean(worktree string) error {
10
+ out, err := git(worktree, "status", "--porcelain", "--untracked-files=all", "--ignored=matching")
11
+ if err != nil {
12
+ return err
13
+ }
14
+ if out != "" {
15
+ return fmt.Errorf("worktree has tracked, untracked, or ignored data: %s", worktree)
16
+ }
17
+ return nil
18
+ }
19
+
20
+ // acceptedWorker checks the ref even when its checkout has already disappeared.
21
+ // Control rewrites WIP commits, so exact transfer identity replaces ancestry.
22
+ func acceptedWorker(root, slug string, lease *Lease, sl LeaseSlice, registered map[string]bool) error {
23
+ if sl.Branch != workerBranch(slug, lease.BatchID, sl.Workspace, sl.ID) || !ownedWorktreePath(root, lease.BatchID, sl) {
24
+ return fmt.Errorf("worker identity is not owned: %s (%s)", sl.WorktreePath, sl.Branch)
25
+ }
26
+ accepted, err := revParse(root, sl.TransferCommit)
27
+ if err != nil || sl.TransferCommit == "" {
28
+ return fmt.Errorf("worker has no usable accepted transfer: %s", sl.Branch)
29
+ }
30
+ tip, err := revParse(root, "refs/heads/"+sl.Branch)
31
+ if err != nil || tip != accepted {
32
+ return fmt.Errorf("worker branch differs from accepted transfer %s: %s", accepted, sl.Branch)
33
+ }
34
+ if _, err := os.Lstat(sl.WorktreePath); os.IsNotExist(err) {
35
+ if registered[resolvedPath(sl.WorktreePath)] {
36
+ return fmt.Errorf("missing worker checkout remains registered; preserve its index and recovery metadata: %s", sl.WorktreePath)
37
+ }
38
+ return nil
39
+ } else if err != nil {
40
+ return err
41
+ }
42
+ if !registered[resolvedPath(sl.WorktreePath)] {
43
+ return fmt.Errorf("worker path is not registered; leaving replacement untouched: %s", sl.WorktreePath)
44
+ }
45
+ ref, err := git(sl.WorktreePath, "symbolic-ref", "--quiet", "HEAD")
46
+ if err != nil || ref != "refs/heads/"+sl.Branch {
47
+ return fmt.Errorf("worker checkout switched branch: %s", sl.WorktreePath)
48
+ }
49
+ head, err := headSHA(sl.WorktreePath)
50
+ if err != nil || head != accepted {
51
+ return fmt.Errorf("worker checkout differs from accepted transfer: %s", sl.WorktreePath)
52
+ }
53
+ return fullyClean(sl.WorktreePath)
54
+ }
55
+
56
+ // Prune removes only unchanged integrated checkouts, not refs or lease rows.
57
+ // Worker-bound review/proof and source bookkeeping must finish before callers prune.
58
+ func Prune(root, slug string) (removed []string, err error) {
59
+ err = withLeaseLock(root, slug, func() error {
60
+ path, err := LeasePath(root, slug)
61
+ if err != nil {
62
+ return err
63
+ }
64
+ lease, err := ReadLease(path)
65
+ if err != nil {
66
+ return err
67
+ }
68
+ if err := normalizeLease(lease, slug); err != nil {
69
+ return err
70
+ }
71
+ if _, err := controllerLease(root, slug); err != nil {
72
+ return err
73
+ }
74
+ if _, err := recoverLanding(root, slug, path, lease, false, false); err != nil {
75
+ return err
76
+ }
77
+ registered, err := registeredWorktrees(root)
78
+ if err != nil {
79
+ return err
80
+ }
81
+ var failures []error
82
+ for _, sl := range lease.Slices {
83
+ if sl.WrightStatus != WrightIntegrated {
84
+ continue
85
+ }
86
+ if err := acceptedWorker(root, slug, lease, sl, registered); err != nil {
87
+ failures = append(failures, fmt.Errorf("%s: %w", SliceKey(sl.Workspace, sl.ID), err))
88
+ continue
89
+ }
90
+ if _, err := os.Lstat(sl.WorktreePath); os.IsNotExist(err) {
91
+ continue
92
+ }
93
+ if err := removeWorktree(root, sl.WorktreePath); err != nil {
94
+ failures = append(failures, fmt.Errorf("kept recovery path %s and ref %s: %w", sl.WorktreePath, sl.Branch, err))
95
+ continue
96
+ }
97
+ removed = append(removed, sl.WorktreePath)
98
+ }
99
+ return errors.Join(failures...)
100
+ })
101
+ return removed, err
102
+ }
103
+
104
+ func prepareStaging(root, slug string, lease *Lease, path, branch string) error {
105
+ claim := LeaseSlice{ID: "integrate", WorktreePath: path}
106
+ if !ownedWorktreePath(root, lease.BatchID, claim) {
107
+ return fmt.Errorf("staging path is not owned: %s", path)
108
+ }
109
+ registered, err := registeredWorktrees(root)
110
+ if err != nil {
111
+ return err
112
+ }
113
+ if _, err := os.Lstat(path); err == nil {
114
+ if !registered[resolvedPath(path)] {
115
+ return fmt.Errorf("staging path is not registered; leaving replacement untouched: %s", path)
116
+ }
117
+ ref, err := git(path, "symbolic-ref", "--quiet", "HEAD")
118
+ if err != nil || ref != "refs/heads/"+branch {
119
+ return fmt.Errorf("staging checkout changed branch: %s", path)
120
+ }
121
+ if err := fullyClean(path); err != nil {
122
+ return err
123
+ }
124
+ if err := removeWorktree(root, path); err != nil {
125
+ return fmt.Errorf("staging checkout kept at %s: %w", path, err)
126
+ }
127
+ } else if !os.IsNotExist(err) {
128
+ return err
129
+ } else if registered[resolvedPath(path)] {
130
+ return fmt.Errorf("missing staging checkout remains registered; preserve its metadata and recover explicitly: %s", path)
131
+ }
132
+ return deleteBranch(root, branch)
133
+ }
@@ -0,0 +1,239 @@
1
+ package parallel
2
+
3
+ import (
4
+ "fmt"
5
+ "os"
6
+ "path/filepath"
7
+ "sort"
8
+
9
+ "github.com/devrites/devrites/internal/state"
10
+ )
11
+
12
+ // WithControlLock serializes controller admission and control-tip mutations.
13
+ // devritesRoot is explicit; callers take this lock before any feature lock.
14
+ func WithControlLock(devritesRoot string, fn func() error) error {
15
+ devritesRoot = filepath.Clean(devritesRoot)
16
+ if err := validateControlRoot(devritesRoot); err != nil {
17
+ return err
18
+ }
19
+ dir := devritesRoot
20
+ root := filepath.Dir(devritesRoot)
21
+ common, err := commonGitDir(root)
22
+ if err != nil {
23
+ return err
24
+ }
25
+ if common != "" {
26
+ dir = common
27
+ }
28
+ if err := os.MkdirAll(dir, 0o755); err != nil {
29
+ return err
30
+ }
31
+ return state.WithLock(filepath.Join(dir, "parallel.lock"), fn)
32
+ }
33
+
34
+ func commonGitDir(root string) (string, error) {
35
+ common, err := git(root, "rev-parse", "--git-common-dir")
36
+ if err == nil {
37
+ if !filepath.IsAbs(common) {
38
+ common = filepath.Join(root, common)
39
+ }
40
+ return resolvedPath(common), nil
41
+ }
42
+ dir, absErr := filepath.Abs(root)
43
+ if absErr != nil {
44
+ return "", absErr
45
+ }
46
+ for {
47
+ if _, statErr := os.Lstat(filepath.Join(dir, ".git")); !os.IsNotExist(statErr) {
48
+ return "", fmt.Errorf("parallel repository discovery: %w", err)
49
+ }
50
+ parent := filepath.Dir(dir)
51
+ if parent == dir {
52
+ return "", nil
53
+ }
54
+ dir = parent
55
+ }
56
+ }
57
+
58
+ func validateControlRoot(root string) error {
59
+ info, err := os.Lstat(root)
60
+ if os.IsNotExist(err) {
61
+ return nil
62
+ }
63
+ if err != nil {
64
+ return err
65
+ }
66
+ if !info.IsDir() {
67
+ return fmt.Errorf("parallel control root is not a safe directory: %s", root)
68
+ }
69
+ return nil
70
+ }
71
+
72
+ type repositoryLease struct {
73
+ root string
74
+ controller string
75
+ lease *Lease
76
+ }
77
+
78
+ // controlLeases reads explicit paths, never the ambient workspace override.
79
+ func controlLeases(devritesRoot string) ([]repositoryLease, error) {
80
+ devritesRoot = filepath.Clean(devritesRoot)
81
+ if err := validateControlRoot(devritesRoot); err != nil {
82
+ return nil, err
83
+ }
84
+ root := filepath.Dir(devritesRoot)
85
+ roots := map[string]bool{resolvedPath(devritesRoot): true}
86
+ common, err := commonGitDir(root)
87
+ if err != nil {
88
+ return nil, err
89
+ }
90
+ if common != "" {
91
+ registered, err := registeredWorktrees(root)
92
+ if err != nil {
93
+ return nil, err
94
+ }
95
+ for path := range registered {
96
+ roots[filepath.Join(path, ".devrites")] = true
97
+ }
98
+ }
99
+ ordered := make([]string, 0, len(roots))
100
+ for path := range roots {
101
+ ordered = append(ordered, path)
102
+ }
103
+ sort.Strings(ordered)
104
+ var leases []repositoryLease
105
+ for _, control := range ordered {
106
+ work := filepath.Join(control, "work")
107
+ for _, path := range []string{control, work} {
108
+ if info, err := os.Lstat(path); err == nil && info.Mode()&os.ModeSymlink != 0 {
109
+ return nil, fmt.Errorf("parallel workspace path is a symlink: %s", path)
110
+ } else if err != nil && !os.IsNotExist(err) {
111
+ return nil, err
112
+ }
113
+ }
114
+ entries, err := os.ReadDir(work)
115
+ if os.IsNotExist(err) {
116
+ continue
117
+ }
118
+ if err != nil {
119
+ return nil, err
120
+ }
121
+ for _, entry := range entries {
122
+ if !entry.IsDir() && entry.Type()&os.ModeSymlink == 0 {
123
+ continue
124
+ }
125
+ path := filepath.Join(work, entry.Name(), "parallel-lease.md")
126
+ info, err := os.Lstat(path)
127
+ if os.IsNotExist(err) {
128
+ continue
129
+ }
130
+ if err != nil {
131
+ return nil, err
132
+ }
133
+ if err := validateSlug(entry.Name()); err != nil {
134
+ return nil, err
135
+ }
136
+ if entry.Type()&os.ModeSymlink != 0 || !info.Mode().IsRegular() {
137
+ return nil, fmt.Errorf("parallel lease path is not an owned regular file: %s", path)
138
+ }
139
+ lease, err := ReadLease(path)
140
+ if err != nil {
141
+ return nil, fmt.Errorf("controller %s: %w", entry.Name(), err)
142
+ }
143
+ if err := normalizeLease(lease, entry.Name()); err != nil {
144
+ return nil, err
145
+ }
146
+ leases = append(leases, repositoryLease{filepath.Dir(control), entry.Name(), lease})
147
+ }
148
+ }
149
+ return leases, nil
150
+ }
151
+
152
+ func controllerLease(root, controller string) (*repositoryLease, error) {
153
+ leases, err := controlLeases(filepath.Join(root, ".devrites"))
154
+ if err != nil {
155
+ return nil, err
156
+ }
157
+ if len(leases) > 1 {
158
+ return nil, fmt.Errorf("multiple retained repository controller leases; cleanup explicitly before admission")
159
+ }
160
+ if len(leases) == 0 {
161
+ return nil, nil
162
+ }
163
+ found := &leases[0]
164
+ if controller != "" && (found.controller != controller || found.root != resolvedPath(root)) {
165
+ return nil, fmt.Errorf("repository controller lease retained by %s at %s; use its explicit root and --slug for mutations", found.controller, found.root)
166
+ }
167
+ return found, nil
168
+ }
169
+
170
+ // WorkspaceLeased protects both controller and source workspaces until cleanup.
171
+ // devritesRoot is explicit; closeout holds WithControlLock through its rename.
172
+ func WorkspaceLeased(devritesRoot, workspace string) (bool, error) {
173
+ if err := validateSlug(workspace); err != nil {
174
+ return false, err
175
+ }
176
+ leases, err := controlLeases(devritesRoot)
177
+ if err != nil {
178
+ return false, err
179
+ }
180
+ for _, found := range leases {
181
+ if found.controller == workspace {
182
+ return true, nil
183
+ }
184
+ for _, sl := range found.lease.Slices {
185
+ if sl.Workspace == workspace {
186
+ return true, nil
187
+ }
188
+ }
189
+ }
190
+ return false, nil
191
+ }
192
+
193
+ func validateSources(devritesRoot string, slices []SlicePaths) error {
194
+ seen := make(map[string]bool)
195
+ for _, sp := range slices {
196
+ if sp.Workspace == "" || seen[sp.Workspace] {
197
+ continue
198
+ }
199
+ seen[sp.Workspace] = true
200
+ if err := validateSource(devritesRoot, sp.Workspace); err != nil {
201
+ return err
202
+ }
203
+ }
204
+ return nil
205
+ }
206
+
207
+ func validateSource(devritesRoot, workspace string) error {
208
+ if workspace == "" {
209
+ return nil
210
+ }
211
+ path := devritesRoot
212
+ for index, component := range []string{"", "work", workspace, state.LedgerFile} {
213
+ if component != "" {
214
+ path = filepath.Join(path, component)
215
+ }
216
+ info, err := os.Lstat(path)
217
+ if err != nil {
218
+ return fmt.Errorf("source workspace %s is not live: %w", workspace, err)
219
+ }
220
+ if (index == 3 && !info.Mode().IsRegular()) || (index != 3 && !info.IsDir()) {
221
+ return fmt.Errorf("source workspace %s has an unsafe live path: %s", workspace, path)
222
+ }
223
+ }
224
+ return nil
225
+ }
226
+
227
+ func validateLeaseSources(devritesRoot string, lease *Lease) error {
228
+ seen := make(map[string]bool)
229
+ for _, sl := range lease.Slices {
230
+ if seen[sl.Workspace] {
231
+ continue
232
+ }
233
+ if err := validateSource(devritesRoot, sl.Workspace); err != nil {
234
+ return err
235
+ }
236
+ seen[sl.Workspace] = true
237
+ }
238
+ return nil
239
+ }
@@ -23,39 +23,25 @@ func SelectGreedySeeded(cap int, seed, ready []SlicePaths, root string) ([]Slice
23
23
  if cap < 1 || cap > MaxParallelSlices {
24
24
  return nil, fmt.Errorf("cap must be 1-%d (got %d)", MaxParallelSlices, cap)
25
25
  }
26
- normalized := make([]SlicePaths, 0, len(ready))
27
- seen := make(map[string]struct{}, len(ready))
28
- for i, item := range ready {
29
- label := fmt.Sprintf("slice %d", i)
30
- if item.ID != "" {
31
- if err := validateSliceID(item.ID); err != nil {
32
- return nil, fmt.Errorf("%s: %w", label, err)
33
- }
34
- label = fmt.Sprintf("slice %q", item.ID)
35
- } else {
36
- return nil, fmt.Errorf("%s: missing id", label)
37
- }
38
- if _, ok := seen[item.ID]; ok {
39
- return nil, fmt.Errorf("duplicate slice id %q", item.ID)
40
- }
41
- seen[item.ID] = struct{}{}
42
- paths, err := validateSlicePaths(item.Paths, label, root)
43
- if err != nil {
44
- return nil, err
45
- }
46
- normalized = append(normalized, SlicePaths{ID: item.ID, Paths: paths})
26
+ normalized, err := normalizeSlices("", ready, root)
27
+ if err != nil {
28
+ return nil, err
29
+ }
30
+ seed, err = normalizeSlices("", seed, root)
31
+ if err != nil {
32
+ return nil, err
47
33
  }
48
34
 
49
35
  running := make(map[string]bool, len(seed))
50
36
  for _, s := range seed {
51
- running[s.ID] = true
37
+ running[SliceKey(s.Workspace, s.ID)] = true
52
38
  }
53
39
  selected := append([]SlicePaths{}, seed...)
54
40
  for _, cand := range normalized {
55
41
  if len(selected) >= cap {
56
42
  break
57
43
  }
58
- if running[cand.ID] {
44
+ if running[SliceKey(cand.Workspace, cand.ID)] {
59
45
  continue
60
46
  }
61
47
  if len(selected) == 0 {
@@ -79,32 +65,68 @@ func SelectGreedySeeded(cap int, seed, ready []SlicePaths, root string) ([]Slice
79
65
  // imports this package.
80
66
  var PlanReady func(root, slug string) ([]SlicePaths, error)
81
67
 
82
- // SelectForSlug is SelectGreedySeeded seeded from slug's running lease: its
83
- // active slices keep their slots and paths, and nothing it names (active or
84
- // landed) is picked again. eligible is ready minus those names; running is -1
85
- // when no lease seeded the selection. An empty slug skips the lease.
68
+ // WorkspaceReady supplies native-authorized candidates and per-workspace notices.
69
+ // main wires this hook from lib, which owns planning and dependency readiness.
70
+ var WorkspaceReady func(root, controller, target string) ([]SlicePaths, []string, error)
71
+
72
+ // SelectForSlug seeds every retained repository slot, regardless of source.
73
+ // Bare candidates belong to slug; returned foreign identities stay qualified
74
+ // relative to the retained controller. An omitted slug means controller-local.
86
75
  func SelectForSlug(root, slug string, capN int, ready []SlicePaths) (eligible, picks []SlicePaths, running int, err error) {
87
- eligible, running = ready, -1
88
- var seed []SlicePaths
76
+ if capN < 1 || capN > MaxParallelSlices {
77
+ return nil, nil, -1, fmt.Errorf("cap must be 1-%d (got %d)", MaxParallelSlices, capN)
78
+ }
89
79
  if slug != "" {
90
- lease, err := runningLease(root, slug)
80
+ if err := validateSlug(slug); err != nil {
81
+ return nil, nil, -1, err
82
+ }
83
+ }
84
+ running = -1
85
+ var seed []SlicePaths
86
+ controller := slug
87
+ var found *repositoryLease
88
+ if root != "" || slug != "" {
89
+ found, err = controllerLease(root, "")
91
90
  if err != nil {
92
91
  return nil, nil, -1, err
93
92
  }
94
- if lease != nil {
95
- seed = activeSlices(lease)
96
- running = len(seed)
97
- named := make(map[string]bool, len(lease.Slices))
98
- for _, sl := range lease.Slices {
99
- named[sl.ID] = true
100
- }
101
- eligible = nil
102
- for _, s := range ready {
103
- if !named[s.ID] {
104
- eligible = append(eligible, s)
93
+ }
94
+ candidates := make([]SlicePaths, len(ready))
95
+ copy(candidates, ready)
96
+ if found != nil {
97
+ if found.lease.PendingLanding != nil {
98
+ return nil, nil, -1, fmt.Errorf("pending landing blocks admission; recover controller %s at %s with integrate --apply-to-control or abort", found.controller, found.root)
99
+ }
100
+ controller = found.controller
101
+ if slug != "" && slug != controller {
102
+ for i := range candidates {
103
+ if candidates[i].Workspace == "" {
104
+ candidates[i].Workspace = slug
105
105
  }
106
106
  }
107
107
  }
108
+ seed = activeSlices(found.lease)
109
+ running = len(seed)
110
+ if capacity := leaseCapacity(found.lease); capN > capacity {
111
+ capN = capacity
112
+ }
113
+ }
114
+ eligible, err = normalizeSlices(controller, candidates, root)
115
+ if err != nil {
116
+ return nil, nil, -1, err
117
+ }
118
+ if found != nil {
119
+ named := make(map[string]bool, len(found.lease.Slices))
120
+ for _, sl := range found.lease.Slices {
121
+ named[SliceKey(sl.Workspace, sl.ID)] = true
122
+ }
123
+ filtered := eligible[:0]
124
+ for _, sp := range eligible {
125
+ if !named[SliceKey(sp.Workspace, sp.ID)] {
126
+ filtered = append(filtered, sp)
127
+ }
128
+ }
129
+ eligible = filtered
108
130
  }
109
131
  picks, err = SelectGreedySeeded(capN, seed, eligible, root)
110
132
  return eligible, picks, running, err
@@ -127,7 +149,7 @@ func selectMode(n int) string {
127
149
  func formatSelect(picks []SlicePaths, running int) string {
128
150
  ids := make([]string, len(picks))
129
151
  for i, item := range picks {
130
- ids[i] = item.ID
152
+ ids[i] = SliceKey(item.Workspace, item.ID)
131
153
  }
132
154
  mode := selectMode(len(picks))
133
155
  if running > 0 && len(picks) > 0 {
package/engine/main.go CHANGED
@@ -74,7 +74,7 @@ Usage:
74
74
  devrites-engine check indexes [--root <dir>] Report manifest and code-index presence as JSON
75
75
  devrites-engine detect commands [--root <dir>] [--json]
76
76
  Resolve test/lint/vet/build commands from the repository's own wiring
77
- devrites-engine parallel <subcommand> Deterministic parallel worktree lease/create/integrate/cleanup
77
+ devrites-engine parallel <subcommand> Deterministic parallel worktree lease/create/integrate/prune/cleanup
78
78
  devrites-engine gates <subcommand> <slug> Machine-checked gates.md ledger: scaffold/status/run/reverify/lint/precheck/attest/abandon
79
79
  devrites-engine state resolve <qid> "<ans>" Resolve an open question and update state atomically
80
80
  devrites-engine state merge-manifest <slug> [pred...] Fold the recorded predecessor chain's manifests into the release candidate manifest
@@ -125,6 +125,7 @@ func init() {
125
125
  }
126
126
  // parallel cannot import lib (lib imports it), so `parallel select --from-plan` gets the plan-derived ready set through this hook.
127
127
  parallel.PlanReady = lib.PlanReady
128
+ parallel.WorkspaceReady = lib.WorkspaceReady
128
129
  // `gates precheck` runs `check windows` through this hook for the same reason.
129
130
  acceptance.WindowsCheck = lib.RunCheckWindows
130
131
  // ...and `gates precheck --slice` learns which writer gates to skip.
@@ -26,8 +26,8 @@ and only the orchestrator-supplied changed paths.
26
26
  contradictory, whose output and exit come from different executions, whose
27
27
  command masks status, or whose exit and output disagree. A pass after a failed
28
28
  attempt on an unchanged digest is `flaky`: `fail` for its AC.
29
- 2. Confirm every log, screenshot, trace, and result belongs to the supplied
30
- candidate.
29
+ 2. Confirm proof belongs to the supplied candidate, except explicitly scoped
30
+ reuse backed by unchanged declared inputs and a valid executed origin.
31
31
  3. Map real REQ/AC/scenario/link IDs **and meaning** to observed proof. Invented/
32
32
  label-only maps or internal proof of an external outcome fail. Behavior MUST
33
33
  be positive, discriminating; reject skipped/focused/filtered/pending, zero-test,
@@ -49,13 +49,20 @@ and only the orchestrator-supplied changed paths.
49
49
  named blocker, never a pass. Otherwise use `cannot_verify`.
50
50
  8. A manual gate whose `gates.md` note lacks the human's own words or source, is a
51
51
  placeholder, or was runnable at Vet is `cannot_verify` ([`gates.md`](../skills/devrites-lib/reference/standards/gates.md)).
52
- 9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v1` under `references/gates/`)
53
- is immutable proof of its COMMAND, CWD, ATTEMPT, EXIT and output for the
54
- candidate in CANDIDATE_BEFORE/AFTER. A `-reused.log` proves a gate for the
55
- current candidate only when its INPUTS_SHA256 equals that of the gate's latest
56
- executed, passing transcript.
57
- 10. Recheck supplied before/after candidate identities. A mismatch or unexpected
58
- repository mutation fails the side-effect boundary.
52
+ 9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v2` under `references/gates/`)
53
+ records one execution, not an assertion that proof is sufficient. Verify its
54
+ `TRANSCRIPT_SHA256` over all bytes before that footer; match the definition,
55
+ original output identity/byte count, declared inputs, EXIT and EXPECT verdict
56
+ against current ledger evidence and approved commands. Metadata and output may
57
+ be redacted; never hash the redacted body as the original output.
58
+ Reuse cites the unchanged executed origin path and its historical candidate
59
+ labels, with matching current `INPUTS_SHA256` and bounded dependency closure.
60
+ A legacy v1 or `-reused.log` alone cannot authorize reuse; request engine
61
+ `gates run`/`reverify --transcripts` to recover approved missing origins.
62
+ 10. Before/after identities must match within the recorded execution.
63
+ Historical/current candidate differences need the scoped reuse justification
64
+ above; never relabel an old observation. Unexpected repository mutation fails
65
+ the side-effect boundary.
59
66
 
60
67
  ## Rules
61
68
 
@@ -37,6 +37,8 @@ lifecycle state from chat or optional `README.md`.
37
37
  ([`workspace-artifact-schema.md`](reference/workspace-artifact-schema.md)).
38
38
  - [`reference/reply-contract.md`](reference/reply-contract.md): compact user-facing
39
39
  completion states. The host renders the response normally.
40
+ - [`reference/parallel-workspaces.md`](reference/parallel-workspaces.md): explicit
41
+ phase targets, one isolated global controller, and source-owned proof.
40
42
  - [`reference/visual-playbooks/index.md`](reference/visual-playbooks/index.md): progressive
41
43
  visual HTML playbook router (load matching ids only; dual-read outline).
42
44
 
@@ -29,9 +29,13 @@ Same-candidate accounts may be cited when permitted. Corrections require
29
29
  new candidate checks, affected real proof and fresh affected exact reviewers for
30
30
  all open findings and dependency/regression closure, including newly triggered roles.
31
31
  After an all-met acceptance ledger has been executed, any candidate digest change
32
- requires `devrites-engine gates reverify <slug>` against the corrected frozen
33
- candidate before refreshed evidence or review bindings are written; ordinary
34
- `gates run` skips already-met rows and cannot refresh them.
32
+ requires `devrites-engine gates reverify <slug> --transcripts` against the corrected
33
+ frozen candidate before refreshed evidence or review bindings are written.
34
+ Unchanged declared `INPUTS` may reuse complete passing originating transcripts;
35
+ missing origins rerun only affected approved checks. Reuse is not execution.
36
+ If non-file prerequisites changed or prior proof is doubtful, invalidate affected
37
+ automatic evidence through the workspace's single-writer protocol before rerun.
38
+ Ordinary `gates run` skips already-met rows and cannot refresh them.
35
39
  Changed contracts or uncertain closure require a full applicable pass.
36
40
  Unchanged sub-scope needs explicit unchanged-input/dependency justification and a
37
41
  link to original evidence. Never relabel an old candidate-bound account.
@@ -45,6 +45,9 @@ If the candidate diff has no matching surfaces, record
45
45
  `proof-runner`, keep their own) with `devrites-engine packet <slug> --wave <w> --phase <p>
46
46
  --role <role> [--slice <SLICE-ID>] [--focus <file>]`: it names the bundle and frozen
47
47
  diff by reference, copies the digests, and runs the `open` lints. Build roles add `--slice <SLICE-ID>` (slice-scoped, slice-named bundle).
48
+ Packet rendering and dispatch verify each named diff's recorded SHA-256.
49
+ Manually authored `.diff`/`.patch` packets need explicit
50
+ `diff <64hex> <path>` binding rows too; an unbound diff is refused.
48
51
  Evaluate the skill's trigger conditions and pass each that fires — a role's
49
52
  Trigger column maps to the phase manifest's names: `security-auditor` →
50
53
  `security`; at Review, `frontend-reviewer` → `ui` and `performance-reviewer` →