devrites 7.2.7 → 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 (340) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +6 -1
  3. package/docs/candidate-integrity.md +10 -0
  4. package/docs/cli.md +7 -1
  5. package/docs/command-map.md +9 -2
  6. package/docs/engine/commands.md +50 -4
  7. package/docs/orchestration.md +35 -13
  8. package/docs/skills.md +5 -0
  9. package/engine/internal/acceptance/cli.go +35 -30
  10. package/engine/internal/acceptance/preconditions.go +1 -1
  11. package/engine/internal/acceptance/run.go +138 -53
  12. package/engine/internal/acceptance/transcript.go +236 -45
  13. package/engine/internal/devritespaths/paths.go +23 -5
  14. package/engine/internal/gate/gate.go +6 -0
  15. package/engine/internal/install/apply.go +5 -0
  16. package/engine/internal/install/merge.go +48 -6
  17. package/engine/internal/install/preflight.go +21 -3
  18. package/engine/internal/install/uninstall.go +9 -10
  19. package/engine/internal/lib/apply_bundle.go +7 -1
  20. package/engine/internal/lib/candidate.go +20 -7
  21. package/engine/internal/lib/candidate_coverage.go +2 -19
  22. package/engine/internal/lib/closeout.go +22 -10
  23. package/engine/internal/lib/context.go +67 -47
  24. package/engine/internal/lib/context_io.go +171 -0
  25. package/engine/internal/lib/detect.go +8 -8
  26. package/engine/internal/lib/dispatch.go +6 -0
  27. package/engine/internal/lib/packet.go +37 -7
  28. package/engine/internal/lib/packet_freeze.go +60 -12
  29. package/engine/internal/lib/packet_integrity.go +179 -0
  30. package/engine/internal/lib/perturb.go +3 -3
  31. package/engine/internal/lib/resolve.go +10 -5
  32. package/engine/internal/lib/slicecheck.go +7 -1
  33. package/engine/internal/lib/state_edit.go +9 -2
  34. package/engine/internal/lib/taskgraph.go +20 -36
  35. package/engine/internal/lib/triggers.go +30 -31
  36. package/engine/internal/lib/workspace_pool.go +330 -0
  37. package/engine/internal/parallel/cli.go +190 -49
  38. package/engine/internal/parallel/git.go +47 -14
  39. package/engine/internal/parallel/landing.go +232 -0
  40. package/engine/internal/parallel/lease.go +97 -18
  41. package/engine/internal/parallel/ops.go +312 -155
  42. package/engine/internal/parallel/pathdisjoint.go +48 -4
  43. package/engine/internal/parallel/prune.go +133 -0
  44. package/engine/internal/parallel/repository.go +239 -0
  45. package/engine/internal/parallel/select.go +64 -42
  46. package/engine/internal/state/cursor.go +5 -5
  47. package/engine/main.go +2 -1
  48. package/pack/.claude/agents/devrites-proof-runner.md +16 -9
  49. package/pack/.claude/skills/devrites-lib/SKILL.md +2 -0
  50. package/pack/.claude/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  51. package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  52. package/pack/.claude/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  53. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  54. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +7 -3
  55. package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  56. package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +18 -9
  57. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  58. package/pack/.claude/skills/rite-autocomplete/SKILL.md +13 -10
  59. package/pack/.claude/skills/rite-autocomplete/reference/lookahead.md +4 -4
  60. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +13 -9
  61. package/pack/.claude/skills/rite-build/SKILL.md +13 -10
  62. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +1 -1
  63. package/pack/.claude/skills/rite-build/reference/checkpoint.md +1 -1
  64. package/pack/.claude/skills/rite-build/reference/parallel-batch.md +60 -39
  65. package/pack/.claude/skills/rite-build/reference/phase-contract.md +8 -5
  66. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +7 -7
  67. package/pack/.claude/skills/rite-clarify/SKILL.md +2 -2
  68. package/pack/.claude/skills/rite-converge/SKILL.md +4 -4
  69. package/pack/.claude/skills/rite-define/SKILL.md +7 -3
  70. package/pack/.claude/skills/rite-define/reference/plan-template.md +4 -2
  71. package/pack/.claude/skills/rite-plan/SKILL.md +11 -8
  72. package/pack/.claude/skills/rite-plan/reference/dependency-graph.md +9 -2
  73. package/pack/.claude/skills/rite-plan/reference/slicing.md +2 -0
  74. package/pack/.claude/skills/rite-polish/SKILL.md +3 -3
  75. package/pack/.claude/skills/rite-prove/SKILL.md +9 -5
  76. package/pack/.claude/skills/rite-resolve/SKILL.md +3 -3
  77. package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +2 -0
  78. package/pack/.claude/skills/rite-review/SKILL.md +4 -3
  79. package/pack/.claude/skills/rite-review/reference/feature-scoped-review.md +2 -2
  80. package/pack/.claude/skills/rite-seal/SKILL.md +1 -1
  81. package/pack/.claude/skills/rite-seal/reference/phase-contract.md +1 -1
  82. package/pack/.claude/skills/rite-ship/SKILL.md +2 -2
  83. package/pack/.claude/skills/rite-ship/reference/git-ship.md +2 -2
  84. package/pack/.claude/skills/rite-spec/SKILL.md +8 -5
  85. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +5 -0
  86. package/pack/.claude/skills/rite-temper/SKILL.md +3 -3
  87. package/pack/.claude/skills/rite-vet/SKILL.md +9 -5
  88. package/pack/.claude/skills/rite-vet/reference/review-axes.md +12 -5
  89. package/pack/generated/claude/agents/devrites-proof-runner.md +16 -9
  90. package/pack/generated/claude/skills/devrites-lib/SKILL.md +2 -0
  91. package/pack/generated/claude/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  92. package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  93. package/pack/generated/claude/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  94. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  95. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +7 -3
  96. package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  97. package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +18 -9
  98. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  99. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +13 -10
  100. package/pack/generated/claude/skills/rite-autocomplete/reference/lookahead.md +4 -4
  101. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +13 -9
  102. package/pack/generated/claude/skills/rite-build/SKILL.md +13 -10
  103. package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +1 -1
  104. package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +1 -1
  105. package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +60 -39
  106. package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +8 -5
  107. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +7 -7
  108. package/pack/generated/claude/skills/rite-clarify/SKILL.md +2 -2
  109. package/pack/generated/claude/skills/rite-converge/SKILL.md +4 -4
  110. package/pack/generated/claude/skills/rite-define/SKILL.md +7 -3
  111. package/pack/generated/claude/skills/rite-define/reference/plan-template.md +4 -2
  112. package/pack/generated/claude/skills/rite-plan/SKILL.md +11 -8
  113. package/pack/generated/claude/skills/rite-plan/reference/dependency-graph.md +9 -2
  114. package/pack/generated/claude/skills/rite-plan/reference/slicing.md +2 -0
  115. package/pack/generated/claude/skills/rite-polish/SKILL.md +3 -3
  116. package/pack/generated/claude/skills/rite-prove/SKILL.md +9 -5
  117. package/pack/generated/claude/skills/rite-resolve/SKILL.md +3 -3
  118. package/pack/generated/claude/skills/rite-resolve/reference/answer-protocol.md +2 -0
  119. package/pack/generated/claude/skills/rite-review/SKILL.md +4 -3
  120. package/pack/generated/claude/skills/rite-review/reference/feature-scoped-review.md +2 -2
  121. package/pack/generated/claude/skills/rite-seal/SKILL.md +1 -1
  122. package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +1 -1
  123. package/pack/generated/claude/skills/rite-ship/SKILL.md +2 -2
  124. package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +2 -2
  125. package/pack/generated/claude/skills/rite-spec/SKILL.md +8 -5
  126. package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +5 -0
  127. package/pack/generated/claude/skills/rite-temper/SKILL.md +3 -3
  128. package/pack/generated/claude/skills/rite-vet/SKILL.md +9 -5
  129. package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +12 -5
  130. package/pack/generated/codex/agents/devrites-proof-runner.toml +16 -9
  131. package/pack/generated/codex/skills/devrites-lib/SKILL.md +2 -0
  132. package/pack/generated/codex/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  133. package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  134. package/pack/generated/codex/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  135. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  136. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +7 -3
  137. package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  138. package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +18 -9
  139. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  140. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +13 -10
  141. package/pack/generated/codex/skills/rite-autocomplete/reference/lookahead.md +4 -4
  142. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +13 -9
  143. package/pack/generated/codex/skills/rite-build/SKILL.md +13 -10
  144. package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +1 -1
  145. package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +1 -1
  146. package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +60 -39
  147. package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +8 -5
  148. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +7 -7
  149. package/pack/generated/codex/skills/rite-clarify/SKILL.md +2 -2
  150. package/pack/generated/codex/skills/rite-converge/SKILL.md +4 -4
  151. package/pack/generated/codex/skills/rite-define/SKILL.md +7 -3
  152. package/pack/generated/codex/skills/rite-define/reference/plan-template.md +4 -2
  153. package/pack/generated/codex/skills/rite-plan/SKILL.md +11 -8
  154. package/pack/generated/codex/skills/rite-plan/reference/dependency-graph.md +9 -2
  155. package/pack/generated/codex/skills/rite-plan/reference/slicing.md +2 -0
  156. package/pack/generated/codex/skills/rite-polish/SKILL.md +3 -3
  157. package/pack/generated/codex/skills/rite-prove/SKILL.md +9 -5
  158. package/pack/generated/codex/skills/rite-resolve/SKILL.md +3 -3
  159. package/pack/generated/codex/skills/rite-resolve/reference/answer-protocol.md +2 -0
  160. package/pack/generated/codex/skills/rite-review/SKILL.md +4 -3
  161. package/pack/generated/codex/skills/rite-review/reference/feature-scoped-review.md +2 -2
  162. package/pack/generated/codex/skills/rite-seal/SKILL.md +1 -1
  163. package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +1 -1
  164. package/pack/generated/codex/skills/rite-ship/SKILL.md +2 -2
  165. package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +2 -2
  166. package/pack/generated/codex/skills/rite-spec/SKILL.md +8 -5
  167. package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +5 -0
  168. package/pack/generated/codex/skills/rite-temper/SKILL.md +3 -3
  169. package/pack/generated/codex/skills/rite-vet/SKILL.md +9 -5
  170. package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +12 -5
  171. package/pack/generated/devin/agents/devrites-proof-runner.md +16 -9
  172. package/pack/generated/devin/skills/devrites-lib/SKILL.md +2 -0
  173. package/pack/generated/devin/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  174. package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  175. package/pack/generated/devin/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  176. package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  177. package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +7 -3
  178. package/pack/generated/devin/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  179. package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +18 -9
  180. package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  181. package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +13 -10
  182. package/pack/generated/devin/skills/rite-autocomplete/reference/lookahead.md +4 -4
  183. package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +13 -9
  184. package/pack/generated/devin/skills/rite-build/SKILL.md +13 -10
  185. package/pack/generated/devin/skills/rite-build/reference/afk-discipline.md +1 -1
  186. package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +1 -1
  187. package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +60 -39
  188. package/pack/generated/devin/skills/rite-build/reference/phase-contract.md +8 -5
  189. package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +7 -7
  190. package/pack/generated/devin/skills/rite-clarify/SKILL.md +2 -2
  191. package/pack/generated/devin/skills/rite-converge/SKILL.md +4 -4
  192. package/pack/generated/devin/skills/rite-define/SKILL.md +7 -3
  193. package/pack/generated/devin/skills/rite-define/reference/plan-template.md +4 -2
  194. package/pack/generated/devin/skills/rite-plan/SKILL.md +11 -8
  195. package/pack/generated/devin/skills/rite-plan/reference/dependency-graph.md +9 -2
  196. package/pack/generated/devin/skills/rite-plan/reference/slicing.md +2 -0
  197. package/pack/generated/devin/skills/rite-polish/SKILL.md +3 -3
  198. package/pack/generated/devin/skills/rite-prove/SKILL.md +9 -5
  199. package/pack/generated/devin/skills/rite-resolve/SKILL.md +3 -3
  200. package/pack/generated/devin/skills/rite-resolve/reference/answer-protocol.md +2 -0
  201. package/pack/generated/devin/skills/rite-review/SKILL.md +4 -3
  202. package/pack/generated/devin/skills/rite-review/reference/feature-scoped-review.md +2 -2
  203. package/pack/generated/devin/skills/rite-seal/SKILL.md +1 -1
  204. package/pack/generated/devin/skills/rite-seal/reference/phase-contract.md +1 -1
  205. package/pack/generated/devin/skills/rite-ship/SKILL.md +2 -2
  206. package/pack/generated/devin/skills/rite-ship/reference/git-ship.md +2 -2
  207. package/pack/generated/devin/skills/rite-spec/SKILL.md +8 -5
  208. package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +5 -0
  209. package/pack/generated/devin/skills/rite-temper/SKILL.md +3 -3
  210. package/pack/generated/devin/skills/rite-vet/SKILL.md +9 -5
  211. package/pack/generated/devin/skills/rite-vet/reference/review-axes.md +12 -5
  212. package/pack/generated/dsh/agents/devrites-proof-runner.md +16 -9
  213. package/pack/generated/dsh/runtime/cordis.patch.yml +1 -1
  214. package/pack/generated/dsh/skills/devrites-lib/SKILL.md +2 -0
  215. package/pack/generated/dsh/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  216. package/pack/generated/dsh/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  217. package/pack/generated/dsh/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  218. package/pack/generated/dsh/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  219. package/pack/generated/dsh/skills/devrites-lib/reference/standards/agents.md +7 -3
  220. package/pack/generated/dsh/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  221. package/pack/generated/dsh/skills/devrites-lib/reference/standards/gates.md +18 -9
  222. package/pack/generated/dsh/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  223. package/pack/generated/dsh/skills/rite-autocomplete/SKILL.md +13 -10
  224. package/pack/generated/dsh/skills/rite-autocomplete/reference/lookahead.md +4 -4
  225. package/pack/generated/dsh/skills/rite-autocomplete/reference/loop.md +13 -9
  226. package/pack/generated/dsh/skills/rite-build/SKILL.md +13 -10
  227. package/pack/generated/dsh/skills/rite-build/reference/afk-discipline.md +1 -1
  228. package/pack/generated/dsh/skills/rite-build/reference/checkpoint.md +1 -1
  229. package/pack/generated/dsh/skills/rite-build/reference/parallel-batch.md +60 -39
  230. package/pack/generated/dsh/skills/rite-build/reference/phase-contract.md +8 -5
  231. package/pack/generated/dsh/skills/rite-build/reference/wright-dispatch.md +7 -7
  232. package/pack/generated/dsh/skills/rite-clarify/SKILL.md +2 -2
  233. package/pack/generated/dsh/skills/rite-converge/SKILL.md +4 -4
  234. package/pack/generated/dsh/skills/rite-define/SKILL.md +7 -3
  235. package/pack/generated/dsh/skills/rite-define/reference/plan-template.md +4 -2
  236. package/pack/generated/dsh/skills/rite-plan/SKILL.md +11 -8
  237. package/pack/generated/dsh/skills/rite-plan/reference/dependency-graph.md +9 -2
  238. package/pack/generated/dsh/skills/rite-plan/reference/slicing.md +2 -0
  239. package/pack/generated/dsh/skills/rite-polish/SKILL.md +3 -3
  240. package/pack/generated/dsh/skills/rite-prove/SKILL.md +9 -5
  241. package/pack/generated/dsh/skills/rite-resolve/SKILL.md +3 -3
  242. package/pack/generated/dsh/skills/rite-resolve/reference/answer-protocol.md +2 -0
  243. package/pack/generated/dsh/skills/rite-review/SKILL.md +4 -3
  244. package/pack/generated/dsh/skills/rite-review/reference/feature-scoped-review.md +2 -2
  245. package/pack/generated/dsh/skills/rite-seal/SKILL.md +1 -1
  246. package/pack/generated/dsh/skills/rite-seal/reference/phase-contract.md +1 -1
  247. package/pack/generated/dsh/skills/rite-ship/SKILL.md +2 -2
  248. package/pack/generated/dsh/skills/rite-ship/reference/git-ship.md +2 -2
  249. package/pack/generated/dsh/skills/rite-spec/SKILL.md +8 -5
  250. package/pack/generated/dsh/skills/rite-spec/reference/state-workspace.md +5 -0
  251. package/pack/generated/dsh/skills/rite-temper/SKILL.md +3 -3
  252. package/pack/generated/dsh/skills/rite-vet/SKILL.md +9 -5
  253. package/pack/generated/dsh/skills/rite-vet/reference/review-axes.md +12 -5
  254. package/pack/generated/omp/agents/devrites-proof-runner.md +16 -9
  255. package/pack/generated/omp/commands/rite-build.md +1 -1
  256. package/pack/generated/omp/skills/devrites-lib/SKILL.md +2 -0
  257. package/pack/generated/omp/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  258. package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  259. package/pack/generated/omp/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  260. package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  261. package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +11 -3
  262. package/pack/generated/omp/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  263. package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +18 -9
  264. package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  265. package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +13 -10
  266. package/pack/generated/omp/skills/rite-autocomplete/reference/lookahead.md +4 -4
  267. package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +13 -9
  268. package/pack/generated/omp/skills/rite-build/SKILL.md +13 -10
  269. package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +1 -1
  270. package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +1 -1
  271. package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +60 -39
  272. package/pack/generated/omp/skills/rite-build/reference/phase-contract.md +8 -5
  273. package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +7 -7
  274. package/pack/generated/omp/skills/rite-clarify/SKILL.md +2 -2
  275. package/pack/generated/omp/skills/rite-converge/SKILL.md +4 -4
  276. package/pack/generated/omp/skills/rite-define/SKILL.md +7 -3
  277. package/pack/generated/omp/skills/rite-define/reference/plan-template.md +4 -2
  278. package/pack/generated/omp/skills/rite-plan/SKILL.md +11 -8
  279. package/pack/generated/omp/skills/rite-plan/reference/dependency-graph.md +9 -2
  280. package/pack/generated/omp/skills/rite-plan/reference/slicing.md +2 -0
  281. package/pack/generated/omp/skills/rite-polish/SKILL.md +3 -3
  282. package/pack/generated/omp/skills/rite-prove/SKILL.md +9 -5
  283. package/pack/generated/omp/skills/rite-resolve/SKILL.md +3 -3
  284. package/pack/generated/omp/skills/rite-resolve/reference/answer-protocol.md +2 -0
  285. package/pack/generated/omp/skills/rite-review/SKILL.md +4 -3
  286. package/pack/generated/omp/skills/rite-review/reference/feature-scoped-review.md +2 -2
  287. package/pack/generated/omp/skills/rite-seal/SKILL.md +1 -1
  288. package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +1 -1
  289. package/pack/generated/omp/skills/rite-ship/SKILL.md +2 -2
  290. package/pack/generated/omp/skills/rite-ship/reference/git-ship.md +2 -2
  291. package/pack/generated/omp/skills/rite-spec/SKILL.md +8 -5
  292. package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +5 -0
  293. package/pack/generated/omp/skills/rite-temper/SKILL.md +3 -3
  294. package/pack/generated/omp/skills/rite-vet/SKILL.md +9 -5
  295. package/pack/generated/omp/skills/rite-vet/reference/review-axes.md +12 -5
  296. package/pack/generated/pi/agents/devrites-proof-runner.md +16 -9
  297. package/pack/generated/pi/prompts/rite-build.md +1 -1
  298. package/pack/generated/pi/skills/devrites-lib/SKILL.md +2 -0
  299. package/pack/generated/pi/skills/devrites-lib/reference/candidate-integrity.md +7 -3
  300. package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
  301. package/pack/generated/pi/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
  302. package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
  303. package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +7 -3
  304. package/pack/generated/pi/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
  305. package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +18 -9
  306. package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
  307. package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +13 -10
  308. package/pack/generated/pi/skills/rite-autocomplete/reference/lookahead.md +4 -4
  309. package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +13 -9
  310. package/pack/generated/pi/skills/rite-build/SKILL.md +13 -10
  311. package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +1 -1
  312. package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +1 -1
  313. package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +60 -39
  314. package/pack/generated/pi/skills/rite-build/reference/phase-contract.md +8 -5
  315. package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +7 -7
  316. package/pack/generated/pi/skills/rite-clarify/SKILL.md +2 -2
  317. package/pack/generated/pi/skills/rite-converge/SKILL.md +4 -4
  318. package/pack/generated/pi/skills/rite-define/SKILL.md +7 -3
  319. package/pack/generated/pi/skills/rite-define/reference/plan-template.md +4 -2
  320. package/pack/generated/pi/skills/rite-plan/SKILL.md +11 -8
  321. package/pack/generated/pi/skills/rite-plan/reference/dependency-graph.md +9 -2
  322. package/pack/generated/pi/skills/rite-plan/reference/slicing.md +2 -0
  323. package/pack/generated/pi/skills/rite-polish/SKILL.md +3 -3
  324. package/pack/generated/pi/skills/rite-prove/SKILL.md +9 -5
  325. package/pack/generated/pi/skills/rite-resolve/SKILL.md +3 -3
  326. package/pack/generated/pi/skills/rite-resolve/reference/answer-protocol.md +2 -0
  327. package/pack/generated/pi/skills/rite-review/SKILL.md +4 -3
  328. package/pack/generated/pi/skills/rite-review/reference/feature-scoped-review.md +2 -2
  329. package/pack/generated/pi/skills/rite-seal/SKILL.md +1 -1
  330. package/pack/generated/pi/skills/rite-seal/reference/phase-contract.md +1 -1
  331. package/pack/generated/pi/skills/rite-ship/SKILL.md +2 -2
  332. package/pack/generated/pi/skills/rite-ship/reference/git-ship.md +2 -2
  333. package/pack/generated/pi/skills/rite-spec/SKILL.md +8 -5
  334. package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +5 -0
  335. package/pack/generated/pi/skills/rite-temper/SKILL.md +3 -3
  336. package/pack/generated/pi/skills/rite-vet/SKILL.md +9 -5
  337. package/pack/generated/pi/skills/rite-vet/reference/review-axes.md +12 -5
  338. package/package.json +1 -1
  339. package/scripts/build-host-artifacts.sh +5 -6
  340. package/scripts/omp-generate.sh +24 -14
@@ -361,6 +361,10 @@ func clearAwaiting(sfile, qid string) error {
361
361
  return fmt.Errorf("read state %s: %w", sfile, err)
362
362
  }
363
363
  lines := splitLinesNoTrailing(data)
364
+ visible, err := structuralLines(data)
365
+ if err != nil {
366
+ return fmt.Errorf("read state %s: %w", sfile, err)
367
+ }
364
368
  resumePolicy, _ := state.PolicyFor(state.PhaseBuild)
365
369
  if rawPhase, ok := state.CursorField(lines, state.CursorPhase); ok {
366
370
  if fields := strings.Fields(strings.ToLower(rawPhase)); len(fields) > 0 {
@@ -373,7 +377,7 @@ func clearAwaiting(sfile, qid string) error {
373
377
  // First check whether the awaiting block references this question at all.
374
378
  inAw := false
375
379
  var awaitingLines []string
376
- for _, line := range lines {
380
+ for _, line := range visible {
377
381
  switch {
378
382
  case awaitingRe.MatchString(line):
379
383
  inAw = true
@@ -400,7 +404,8 @@ func clearAwaiting(sfile, qid string) error {
400
404
  ts := nowUTC()
401
405
  var out []string
402
406
  inAw, inLog, logAppended := false, false, false
403
- for _, line := range lines {
407
+ for i, original := range lines {
408
+ line := visible[i]
404
409
  if awaitingRe.MatchString(line) {
405
410
  inAw = true
406
411
  continue
@@ -413,7 +418,7 @@ func clearAwaiting(sfile, qid string) error {
413
418
  }
414
419
  switch {
415
420
  case logHdrRe.MatchString(line):
416
- out = append(out, line)
421
+ out = append(out, original)
417
422
  inLog = true
418
423
  continue
419
424
  case inLog && hdrSpaceRe.MatchString(line):
@@ -422,10 +427,10 @@ func clearAwaiting(sfile, qid string) error {
422
427
  logAppended = true
423
428
  }
424
429
  inLog = false
425
- out = append(out, line)
430
+ out = append(out, original)
426
431
  continue
427
432
  }
428
- out = append(out, line)
433
+ out = append(out, original)
429
434
  }
430
435
  if inLog && !logAppended {
431
436
  out = append(out, fmt.Sprintf("- %s %s: resolved %s", ts, resumePolicy.Target, qid))
@@ -7,6 +7,7 @@ import (
7
7
  "regexp"
8
8
  "strings"
9
9
 
10
+ "github.com/devrites/devrites/internal/markdowntext"
10
11
  "github.com/devrites/devrites/internal/state"
11
12
  )
12
13
 
@@ -21,7 +22,7 @@ import (
21
22
  // 0 contract holds 2 usage error 3 blocked: problems listed
22
23
 
23
24
  var (
24
- sliceFieldRe = regexp.MustCompile(`(?m)^([A-Za-z][A-Za-z /_-]*):\s*(.*)$`)
25
+ sliceFieldRe = regexp.MustCompile(`(?m)^([A-Za-z][A-Za-z /_-]*):[ \t]*(.*)$`)
25
26
  sliceACRe = regexp.MustCompile(`\bAC-\d+\b`)
26
27
  pathGlobCharRe = regexp.MustCompile(`[*?\[\]{}]`)
27
28
  pathTraversalRe = regexp.MustCompile(`(^|/)\.\.(/|$)`)
@@ -48,6 +49,11 @@ func sliceSizeAdvisory(block string) (int, bool) {
48
49
  // sliceFields extracts the single-line `Field: value` pairs of a slice block.
49
50
  func sliceFields(block string) map[string]string {
50
51
  fields := map[string]string{}
52
+ structural, err := markdowntext.Structural([]byte(block))
53
+ if err != nil {
54
+ return fields
55
+ }
56
+ block = string(structural)
51
57
  for _, m := range sliceFieldRe.FindAllStringSubmatch(block, -1) {
52
58
  key := strings.ToLower(strings.TrimSpace(m[1]))
53
59
  if _, seen := fields[key]; !seen {
@@ -58,10 +58,17 @@ func RunStateSet(root string, args []string, stdout, stderr io.Writer) int {
58
58
  return fail(stderr, stateSetUsage, 2)
59
59
  }
60
60
  }
61
- if !cursorKeyPattern.MatchString(key) || seen[key] {
61
+ if !cursorKeyPattern.MatchString(key) {
62
62
  return fail(stderr, fmt.Sprintf("state set: key %q is not a snake_case cursor key or repeats", key), 2)
63
63
  }
64
- seen[key] = true
64
+ if canonical, ok := state.CanonicalCursorKey(key); ok {
65
+ key = canonical
66
+ }
67
+ identity := strings.ReplaceAll(key, "_", "")
68
+ if seen[identity] {
69
+ return fail(stderr, fmt.Sprintf("state set: key %q is not a snake_case cursor key or repeats", key), 2)
70
+ }
71
+ seen[identity] = true
65
72
  changes = append(changes, change{key, value})
66
73
  }
67
74
  sfile, code := stateEditWorkspace(root, slug, "state.md", stderr)
@@ -201,34 +201,10 @@ func PrecheckSkips(root, slug, slice string, gateIDs []string) (map[string]strin
201
201
  // manifest and lockfile when it declares external dependencies. root is the
202
202
  // .devrites directory.
203
203
  func planReady(root, slug string) ([]parallel.SlicePaths, error) {
204
- raw, err := readWorkspaceArtifact(root, slug, "tasks.md")
205
- if err != nil {
206
- return nil, err
207
- }
208
- graph := ParseTaskGraph(raw)
209
- if len(graph.Problems) > 0 {
210
- return nil, fmt.Errorf("tasks.md: %s", strings.Join(graph.Problems, "; "))
211
- }
212
- built, err := builtSlices(root, slug)
213
- if err != nil {
214
- return nil, err
215
- }
216
- isBuilt := func(id string) bool { return built[sliceNumber(id)] }
217
- paths, _ := sliceWritePaths(raw, graph)
218
- project := filepath.Dir(root)
219
- var ready []parallel.SlicePaths
220
- for _, s := range graph.Slices {
221
- if isBuilt(s.ID) || slices.ContainsFunc(s.Dependencies, func(dep string) bool { return !isBuilt(dep) }) {
222
- continue
223
- }
224
- if len(paths[s.ID]) == 0 {
225
- return nil, fmt.Errorf("%s has no Writer allowlist or Files likely touched", s.ID)
226
- }
227
- block, _ := state.ExtractTaskSlice(raw, s.ID)
228
- external, _ := fieldValue(sliceFields(block), "external dependencies")
229
- ready = append(ready, parallel.SlicePaths{ID: s.ID, Paths: withManifests(project, paths[s.ID], external)})
230
- }
231
- return ready, nil
204
+ ready, _, err := workspacePlanReady(root, slug, false, func(name string) ([]byte, error) {
205
+ return readWorkspaceArtifact(root, slug, name)
206
+ })
207
+ return ready, err
232
208
  }
233
209
 
234
210
  // builtWordRe marks a checked state.md item as a built checkpoint.
@@ -240,7 +216,13 @@ var builtWordRe = regexp.MustCompile(`(?i)\bbuilt\b`)
240
216
  // was checkpointed and whose section has a `Checkpoint: <sha>` line — a missed
241
217
  // checkbox must not keep dependents out of the ready set.
242
218
  func builtSlices(root, slug string) (map[string]bool, error) {
243
- raw, err := readWorkspaceArtifact(root, slug, "state.md")
219
+ return builtSlicesFrom(func(name string) ([]byte, error) {
220
+ return readWorkspaceArtifact(root, slug, name)
221
+ })
222
+ }
223
+
224
+ func builtSlicesFrom(read func(string) ([]byte, error)) (map[string]bool, error) {
225
+ raw, err := read("state.md")
244
226
  if err != nil {
245
227
  return nil, err
246
228
  }
@@ -257,7 +239,7 @@ func builtSlices(root, slug string) (map[string]bool, error) {
257
239
  built[strings.TrimLeft(m[1], "0")] = true
258
240
  }
259
241
  }
260
- extra, err := evidenceBuilt(root, slug)
242
+ extra, err := evidenceBuiltFrom(read)
261
243
  if err != nil {
262
244
  return nil, err
263
245
  }
@@ -273,9 +255,9 @@ var (
273
255
  checkpointSHARe = regexp.MustCompile(`(?m)^[ \t]*Checkpoint: [0-9a-fA-F]{7,40}\b`)
274
256
  )
275
257
 
276
- // evidenceBuilt reads evidence.md checkpoint sections. A missing file is none.
277
- func evidenceBuilt(root, slug string) (map[string]bool, error) {
278
- raw, err := readWorkspaceArtifact(root, slug, "evidence.md")
258
+ // evidenceBuiltFrom reads evidence.md checkpoint sections. A missing file is none.
259
+ func evidenceBuiltFrom(read func(string) ([]byte, error)) (map[string]bool, error) {
260
+ raw, err := read("evidence.md")
279
261
  if err != nil {
280
262
  if errors.Is(err, os.ErrNotExist) {
281
263
  return map[string]bool{}, nil
@@ -421,9 +403,11 @@ func planBatch(root, slug string, capN int) (eligible, batch []string, err error
421
403
  return nil, nil, err
422
404
  }
423
405
  ids := func(in []parallel.SlicePaths) []string {
424
- out := make([]string, len(in))
425
- for i, s := range in {
426
- out[i] = s.ID
406
+ var out []string
407
+ for _, s := range in {
408
+ if s.Workspace == "" || s.Workspace == slug {
409
+ out = append(out, s.ID)
410
+ }
427
411
  }
428
412
  return out
429
413
  }
@@ -1,9 +1,8 @@
1
1
  package lib
2
2
 
3
3
  import (
4
- "io"
4
+ "errors"
5
5
  "os"
6
- "path/filepath"
7
6
  "regexp"
8
7
  "slices"
9
8
  "sort"
@@ -52,7 +51,7 @@ var (
52
51
  // corpus (minus the template's AI-SPEC annex) names a model, agent, RAG, or
53
52
  // tool surface.
54
53
  func keepModelSurface(role string, facts triggerFacts) bool {
55
- return role == "security-auditor" || facts.aiSpec || strings.TrimSpace(facts.corpus) == "" ||
54
+ return roleBase(role) == "security-auditor" || facts.aiSpec || strings.TrimSpace(facts.corpus) == "" ||
56
55
  aiSignalRe.MatchString(aiAnnexRe.ReplaceAllString(facts.corpus, "$1"))
57
56
  }
58
57
 
@@ -82,8 +81,7 @@ var triggerSignals = []struct {
82
81
 
83
82
  // suggestTriggers returns declared, unselected trigger names whose firing facts
84
83
  // hold in this workspace. Sorted for stable output.
85
- func suggestTriggers(manifest loadsManifest, root, featureDir string, opts contextOpts) []string {
86
- facts := gatherTriggerFacts(root, featureDir, opts.role)
84
+ func suggestTriggers(manifest loadsManifest, opts contextOpts, facts triggerFacts) []string {
87
85
  var suggested []string
88
86
  for name := range manifest.Triggers {
89
87
  if slices.Contains(opts.triggers, name) {
@@ -101,45 +99,46 @@ func suggestTriggers(manifest loadsManifest, root, featureDir string, opts conte
101
99
  return suggested
102
100
  }
103
101
 
104
- func gatherTriggerFacts(root, featureDir, role string) triggerFacts {
105
- facts := triggerFacts{role: role}
102
+ func gatherTriggerFacts(root, role string, sources *contextSources) (triggerFacts, error) {
103
+ facts := triggerFacts{role: roleBase(role)}
106
104
  if root != "" {
107
- afkPath := filepath.Join(root, "AFK")
108
- if info, err := os.Stat(afkPath); err == nil && info.Mode().IsRegular() {
109
- facts.afk = true
110
- if data, err := os.ReadFile(afkPath); err == nil { // #nosec G304 -- .devrites/AFK sentinel
111
- facts.afkParallel = afkAllowsParallel(string(data))
112
- }
105
+ sentinels := contextSources{dir: root}
106
+ data, err := sentinels.read("AFK")
107
+ if err != nil && !errors.Is(err, os.ErrNotExist) {
108
+ return facts, err
113
109
  }
114
- if info, err := os.Stat(filepath.Join(root, "principles.md")); err == nil && info.Mode().IsRegular() {
115
- facts.principles = true
110
+ facts.afk = err == nil
111
+ facts.afkParallel = afkAllowsParallel(string(data))
112
+ _, err = sentinels.read("principles.md")
113
+ if err != nil && !errors.Is(err, os.ErrNotExist) {
114
+ return facts, err
116
115
  }
116
+ facts.principles = err == nil
117
117
  }
118
- if featureDir != "" {
119
- if info, err := os.Stat(filepath.Join(featureDir, "ai-spec.md")); err == nil && info.Mode().IsRegular() {
120
- facts.aiSpec = true
118
+ if sources.dir != "" {
119
+ _, err := sources.read("ai-spec.md")
120
+ if err != nil && !errors.Is(err, os.ErrNotExist) {
121
+ return facts, err
121
122
  }
123
+ facts.aiSpec = err == nil
122
124
  var corpus strings.Builder
123
125
  for _, name := range triggerEvidenceFiles {
124
- path := filepath.Join(featureDir, name)
125
- info, err := os.Stat(path)
126
- if err != nil || !info.Mode().IsRegular() {
127
- continue
128
- }
129
- f, err := os.Open(path) // #nosec G304 -- workspace artifact; read is capped below
126
+ data, err := sources.read(name)
130
127
  if err != nil {
131
- continue
128
+ if errors.Is(err, os.ErrNotExist) {
129
+ continue
130
+ }
131
+ return facts, err
132
132
  }
133
- data, err := io.ReadAll(io.LimitReader(f, triggerEvidenceFileCap))
134
- _ = f.Close()
135
- if err == nil {
136
- corpus.Write(data)
137
- corpus.WriteByte('\n')
133
+ if len(data) > triggerEvidenceFileCap {
134
+ data = data[:triggerEvidenceFileCap]
138
135
  }
136
+ corpus.Write(data)
137
+ corpus.WriteByte('\n')
139
138
  }
140
139
  facts.corpus = strings.ToLower(corpus.String())
141
140
  }
142
- return facts
141
+ return facts, nil
143
142
  }
144
143
 
145
144
  var afkParallelRe = regexp.MustCompile(`(?m)^\s*max_parallel\s*:\s*([0-9]+)\s*$`)
@@ -0,0 +1,330 @@
1
+ package lib
2
+
3
+ import (
4
+ "errors"
5
+ "fmt"
6
+ "os"
7
+ "path/filepath"
8
+ "strings"
9
+
10
+ "github.com/devrites/devrites/internal/devritespaths"
11
+ "github.com/devrites/devrites/internal/gate"
12
+ "github.com/devrites/devrites/internal/markdowntext"
13
+ "github.com/devrites/devrites/internal/parallel"
14
+ "github.com/devrites/devrites/internal/state"
15
+ )
16
+
17
+ // WorkspaceReady admits only the controller or its recorded forward continuation.
18
+ // Notices describe withheld work without removing other workspaces from the pool.
19
+ func WorkspaceReady(repoRoot, controller, target string) ([]parallel.SlicePaths, []string, error) {
20
+ root := filepath.Join(repoRoot, devritespaths.DevritesRootName)
21
+ if !devritespaths.ValidSlug(controller) || !devritespaths.ValidSlug(target) {
22
+ return nil, nil, fmt.Errorf("invalid controller or target workspace slug")
23
+ }
24
+ if _, err := devritespaths.WorkspaceOverrideChecked(root, target); err != nil {
25
+ return nil, []string{fmt.Sprintf("%s: global workspace admission preserves DEVRITES_WORKSPACE scope: %v; unset DEVRITES_WORKSPACE to query the global pool", target, err)}, nil
26
+ }
27
+ if _, err := devritespaths.ExistingFeatureDirChecked(root, controller); err != nil {
28
+ return nil, nil, fmt.Errorf("controller %s: %w", controller, err)
29
+ }
30
+ observation, err := state.ObserveWorkspace(root, target)
31
+ if err != nil {
32
+ return nil, []string{fmt.Sprintf("%s: state unavailable: %v; repair workspace and rerun /rite-vet", target, err)}, nil
33
+ }
34
+ cursor, _ := observation.Fact(state.LedgerFile)
35
+ cursorBytes := cursor.Bytes()
36
+ if target != controller {
37
+ if err := forwardWorkspace(root, controller, target, cursorBytes); err != nil {
38
+ return nil, []string{fmt.Sprintf("%s: %v", target, err)}, nil
39
+ }
40
+ }
41
+ result, err := gate.CheckObserved(gate.Readiness, root, observation)
42
+ if err != nil {
43
+ return nil, []string{fmt.Sprintf("%s: readiness unavailable: %v; repair workspace and rerun /rite-vet", target, err)}, nil
44
+ }
45
+ structuralCursor, _ := markdowntext.Structural(cursorBytes)
46
+ status, _ := state.CursorField(strings.Split(string(structuralCursor), "\n"), state.CursorStatus)
47
+ var notices []string
48
+ if result.Phase != state.PhaseVet && result.Phase != state.PhaseBuild {
49
+ notices = append(notices, fmt.Sprintf("%s: phase %s is not Build entry; native Plan/Vet must prepare this workspace before admission", target, result.Phase))
50
+ }
51
+ if result.Phase == state.PhaseVet && status != "ready" {
52
+ notices = append(notices, fmt.Sprintf("%s: Vet is not ready; native Plan/Vet must complete before admission", target))
53
+ }
54
+ switch status {
55
+ case "awaiting_human", "blocked", "shipped", "done", "archived":
56
+ notices = append(notices, fmt.Sprintf("%s: status %s withholds writer admission; native controller must resolve this state", target, status))
57
+ }
58
+ if result.Blocked {
59
+ for _, line := range strings.Split(strings.TrimSpace(result.Render()), "\n") {
60
+ notices = append(notices, target+": "+line)
61
+ }
62
+ }
63
+ if len(notices) > 0 {
64
+ return nil, notices, nil
65
+ }
66
+ ready, notices, err := workspacePlanReady(root, target, target != controller, func(name string) ([]byte, error) {
67
+ fact, ok := observation.Fact(state.ArtifactPath(name))
68
+ if !ok || fact.State() == state.ArtifactAbsent {
69
+ return nil, os.ErrNotExist
70
+ }
71
+ if fact.State() != state.ArtifactPresent && fact.State() != state.ArtifactEmpty {
72
+ return nil, fmt.Errorf("%s: retained artifact is %s", name, fact.State())
73
+ }
74
+ return fact.Bytes(), nil
75
+ })
76
+ if err != nil {
77
+ return nil, notices, err
78
+ }
79
+ if target != controller {
80
+ for i := range ready {
81
+ ready[i].Workspace = target
82
+ }
83
+ }
84
+ return ready, notices, nil
85
+ }
86
+
87
+ // readSequenceArtifact permits archived predecessors, never an archived writer.
88
+ func readSequenceArtifact(root, slug, name string) ([]byte, error) {
89
+ dir, err := devritespaths.ExistingCanonicalFeatureDirChecked(root, slug)
90
+ if errors.Is(err, os.ErrNotExist) {
91
+ dir, err = devritespaths.ExistingArchivedFeatureDirChecked(root, slug)
92
+ }
93
+ if err != nil {
94
+ return nil, err
95
+ }
96
+ return readBoundedRegularFile(filepath.Join(dir, name), workspaceArtifactLimit)
97
+ }
98
+
99
+ func forwardWorkspace(root, controller, target string, targetState []byte) error {
100
+ seen := map[string]bool{}
101
+ current := target
102
+ found := false
103
+ for range maxSequenceChain {
104
+ if seen[current] {
105
+ return fmt.Errorf("sequence_parent cycle at %s; repair native sequence cursor", current)
106
+ }
107
+ seen[current] = true
108
+ found = found || current == controller
109
+ // Target is already retained from its live workspace observation.
110
+ raw := targetState
111
+ if current != target {
112
+ var err error
113
+ raw, err = readSequenceArtifact(root, current, "state.md")
114
+ if err != nil {
115
+ return fmt.Errorf("sequence_parent %s unavailable: %w", current, err)
116
+ }
117
+ }
118
+ structural, err := markdowntext.Structural(raw)
119
+ if err != nil {
120
+ return fmt.Errorf("sequence_parent %s state.md is invalid Markdown", current)
121
+ }
122
+ parent, _ := state.CursorField(strings.Split(string(structural), "\n"), state.CursorSequenceParent)
123
+ if parent == "" {
124
+ if found {
125
+ return nil
126
+ }
127
+ return fmt.Errorf("not a recorded forward continuation of %s; native sequence authorization required", controller)
128
+ }
129
+ if !devritespaths.ValidSlug(parent) {
130
+ return fmt.Errorf("sequence_parent %q is not a workspace slug", parent)
131
+ }
132
+ current = parent
133
+ }
134
+ return fmt.Errorf("sequence_parent chain exceeds %d workspaces", maxSequenceChain)
135
+ }
136
+
137
+ type workspaceProducer struct {
138
+ workspace string
139
+ id string
140
+ }
141
+
142
+ type workspacePlan struct {
143
+ raw []byte
144
+ graph TaskGraphResult
145
+ built map[string]bool
146
+ }
147
+
148
+ type workspaceDependencies struct {
149
+ root string
150
+ plans map[string]*workspacePlan
151
+ }
152
+
153
+ func (d *workspaceDependencies) load(slug string) (*workspacePlan, error) {
154
+ if plan := d.plans[slug]; plan != nil {
155
+ return plan, nil
156
+ }
157
+ raw, err := readSequenceArtifact(d.root, slug, "tasks.md")
158
+ if err != nil {
159
+ return nil, fmt.Errorf("producer %s tasks.md: %w", slug, err)
160
+ }
161
+ graph := ParseTaskGraph(raw)
162
+ if len(graph.Problems) > 0 {
163
+ return nil, fmt.Errorf("producer %s tasks.md: %s", slug, strings.Join(graph.Problems, "; "))
164
+ }
165
+ built, err := builtSlicesFrom(func(name string) ([]byte, error) {
166
+ return readSequenceArtifact(d.root, slug, name)
167
+ })
168
+ if err != nil {
169
+ return nil, fmt.Errorf("producer %s checkpoints: %w", slug, err)
170
+ }
171
+ plan := &workspacePlan{raw: raw, graph: graph, built: built}
172
+ d.plans[slug] = plan
173
+ return plan, nil
174
+ }
175
+
176
+ func declaredWorkspaceDependencies(block string) ([]workspaceProducer, bool, error) {
177
+ structural, err := markdowntext.Structural([]byte(block))
178
+ if err != nil {
179
+ return nil, false, fmt.Errorf("workspace dependencies cannot be read from invalid Markdown")
180
+ }
181
+ block = string(structural)
182
+ fields := sliceFields(block)
183
+ value, declared := fieldValue(fields, "workspace dependencies")
184
+ count := 0
185
+ for _, field := range sliceFieldRe.FindAllStringSubmatch(block, -1) {
186
+ if strings.EqualFold(strings.TrimSpace(field[1]), "workspace dependencies") {
187
+ count++
188
+ }
189
+ }
190
+ if count > 1 {
191
+ return nil, true, fmt.Errorf("duplicate Workspace dependencies; rerun native Plan/Vet")
192
+ }
193
+ if !declared || value == "none" {
194
+ return nil, declared, nil
195
+ }
196
+ var refs []workspaceProducer
197
+ seen := map[string]bool{}
198
+ for token := range strings.SplitSeq(value, ",") {
199
+ token = strings.TrimSpace(token)
200
+ slug, id, ok := strings.Cut(token, "/")
201
+ if !ok || !devritespaths.ValidSlug(slug) || !state.ValidSliceID(id) {
202
+ return nil, true, fmt.Errorf("malformed Workspace dependencies reference %q; use none or <slug>/SLICE-### and rerun native Plan/Vet", token)
203
+ }
204
+ if seen[token] {
205
+ return nil, true, fmt.Errorf("duplicate Workspace dependencies reference %q", token)
206
+ }
207
+ seen[token] = true
208
+ refs = append(refs, workspaceProducer{workspace: slug, id: id})
209
+ }
210
+ return refs, true, nil
211
+ }
212
+
213
+ // validate follows local and workspace edges even across built nodes: a recorded
214
+ // checkpoint cannot make an unknown reference or a cyclic plan graph valid.
215
+ func (d *workspaceDependencies) validate(ref workspaceProducer, visiting, valid map[string]bool) error {
216
+ key := parallel.SliceKey(ref.workspace, ref.id)
217
+ if visiting[key] {
218
+ return fmt.Errorf("workspace dependencies cycle at %s; repair native Plan/Vet", key)
219
+ }
220
+ if valid[key] {
221
+ return nil
222
+ }
223
+ if len(visiting)+len(valid) >= 4096 {
224
+ return fmt.Errorf("workspace dependencies graph exceeds 4096 slices")
225
+ }
226
+ plan, err := d.load(ref.workspace)
227
+ if err != nil {
228
+ return err
229
+ }
230
+ var node *TaskSlice
231
+ for i := range plan.graph.Slices {
232
+ if plan.graph.Slices[i].ID == ref.id {
233
+ node = &plan.graph.Slices[i]
234
+ break
235
+ }
236
+ }
237
+ if node == nil {
238
+ return fmt.Errorf("unknown Workspace dependencies producer %s", key)
239
+ }
240
+ block, _ := state.ExtractTaskSlice(plan.raw, ref.id)
241
+ refs, _, err := declaredWorkspaceDependencies(block)
242
+ if err != nil {
243
+ return fmt.Errorf("%s: %w", key, err)
244
+ }
245
+ for _, id := range node.Dependencies {
246
+ refs = append(refs, workspaceProducer{workspace: ref.workspace, id: id})
247
+ }
248
+ visiting[key] = true
249
+ defer delete(visiting, key)
250
+ for _, dependency := range refs {
251
+ if err := d.validate(dependency, visiting, valid); err != nil {
252
+ return err
253
+ }
254
+ }
255
+ valid[key] = true
256
+ return nil
257
+ }
258
+
259
+ func workspacePlanReady(root, slug string, requireDeclaration bool, read func(string) ([]byte, error)) ([]parallel.SlicePaths, []string, error) {
260
+ raw, err := read("tasks.md")
261
+ if err != nil {
262
+ return nil, nil, err
263
+ }
264
+ graph := ParseTaskGraph(raw)
265
+ if len(graph.Problems) > 0 {
266
+ return nil, nil, fmt.Errorf("tasks.md: %s", strings.Join(graph.Problems, "; "))
267
+ }
268
+ built, err := builtSlicesFrom(read)
269
+ if err != nil {
270
+ return nil, nil, err
271
+ }
272
+ deps := workspaceDependencies{root: root, plans: map[string]*workspacePlan{
273
+ slug: {raw: raw, graph: graph, built: built},
274
+ }}
275
+ paths, _ := sliceWritePaths(raw, graph)
276
+ var ready []parallel.SlicePaths
277
+ var notices []string
278
+ valid := map[string]bool{}
279
+ for _, node := range graph.Slices {
280
+ block, _ := state.ExtractTaskSlice(raw, node.ID)
281
+ if satisfies, _ := fieldValue(sliceFields(block), "satisfies"); strings.EqualFold(satisfies, "none") {
282
+ continue
283
+ }
284
+ if built[sliceNumber(node.ID)] || slicesUnbuilt(node.Dependencies, built) {
285
+ continue
286
+ }
287
+ key := parallel.SliceKey(slug, node.ID)
288
+ refs, declared, problem := declaredWorkspaceDependencies(block)
289
+ if problem == nil && requireDeclaration && !declared {
290
+ problem = fmt.Errorf("missing Workspace dependencies; native Plan/Vet must bind none or explicit producers before foreign admission")
291
+ }
292
+ if problem == nil {
293
+ problem = deps.validate(workspaceProducer{workspace: slug, id: node.ID}, map[string]bool{}, valid)
294
+ }
295
+ if problem != nil {
296
+ notices = append(notices, key+": "+problem.Error())
297
+ continue
298
+ }
299
+ waiting := false
300
+ for _, ref := range refs {
301
+ producer := deps.plans[ref.workspace] // validate loaded every referenced graph.
302
+ if !producer.built[sliceNumber(ref.id)] {
303
+ notices = append(notices, fmt.Sprintf("%s: waiting for durable BUILT/integrated producer %s", key, parallel.SliceKey(ref.workspace, ref.id)))
304
+ waiting = true
305
+ }
306
+ }
307
+ if waiting {
308
+ continue
309
+ }
310
+ if len(paths[node.ID]) == 0 {
311
+ if requireDeclaration {
312
+ notices = append(notices, key+": no Writer allowlist or Files likely touched; repair native Plan/Vet")
313
+ continue
314
+ }
315
+ return nil, notices, fmt.Errorf("%s has no Writer allowlist or Files likely touched", node.ID)
316
+ }
317
+ external, _ := fieldValue(sliceFields(block), "external dependencies")
318
+ ready = append(ready, parallel.SlicePaths{ID: node.ID, Paths: withManifests(filepath.Dir(root), paths[node.ID], external)})
319
+ }
320
+ return ready, notices, nil
321
+ }
322
+
323
+ func slicesUnbuilt(ids []string, built map[string]bool) bool {
324
+ for _, id := range ids {
325
+ if !built[sliceNumber(id)] {
326
+ return true
327
+ }
328
+ }
329
+ return false
330
+ }