devrites 4.0.12 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +3 -3
  3. package/docs/architecture.md +4 -4
  4. package/docs/command-map.md +4 -3
  5. package/docs/engine/commands.md +65 -6
  6. package/docs/flow.md +2 -1
  7. package/docs/orchestration.md +45 -4
  8. package/docs/skills.md +4 -3
  9. package/engine/go.mod +1 -1
  10. package/engine/internal/devritespaths/paths.go +5 -4
  11. package/engine/internal/gate/gate.go +154 -46
  12. package/engine/internal/gate/gate_test.go +290 -2
  13. package/engine/internal/gate/readiness_binding.go +66 -100
  14. package/engine/internal/gate/readiness_binding_test.go +126 -3
  15. package/engine/internal/hostpack/hostpack.go +9 -4
  16. package/engine/internal/hostpack/hostpack_test.go +16 -7
  17. package/engine/internal/install/install_test.go +5 -0
  18. package/engine/internal/lib/resolve.go +6 -6
  19. package/engine/internal/state/cmd/workflowmanifest/main.go +32 -3
  20. package/engine/internal/state/feature.go +1 -100
  21. package/engine/internal/state/observation.go +584 -0
  22. package/engine/internal/state/observation_open_other.go +9 -0
  23. package/engine/internal/state/observation_open_unix.go +12 -0
  24. package/engine/internal/state/observation_test.go +960 -0
  25. package/engine/internal/state/observation_unix_test.go +68 -0
  26. package/engine/internal/state/schema.go +60 -160
  27. package/engine/internal/state/state_test.go +489 -101
  28. package/engine/internal/state/status.go +67 -48
  29. package/engine/tests/adr_0004_required_by_phase_test.go +16 -13
  30. package/engine/tests/adr_0011_define_plan_test.go +14 -12
  31. package/engine/tests/gate_test.go +403 -28
  32. package/engine/tests/workspace_observation_migration_test.go +1065 -0
  33. package/pack/.claude/agents/devrites-code-reviewer.md +6 -1
  34. package/pack/.claude/agents/devrites-plan-drafter.md +5 -0
  35. package/pack/.claude/agents/devrites-plan-reviewer.md +6 -0
  36. package/pack/.claude/agents/devrites-proof-runner.md +7 -1
  37. package/pack/.claude/agents/devrites-retrospector.md +21 -25
  38. package/pack/.claude/agents/devrites-security-auditor.md +7 -3
  39. package/pack/.claude/agents/devrites-slice-wright.md +30 -4
  40. package/pack/.claude/agents/devrites-spec-reviewer.md +5 -0
  41. package/pack/.claude/agents/devrites-strategy-reviewer.md +3 -4
  42. package/pack/.claude/agents/devrites-test-analyst.md +5 -0
  43. package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +13 -26
  44. package/pack/.claude/skills/devrites-debug-recovery/reference/build-the-loop.md +11 -14
  45. package/pack/.claude/skills/devrites-doubt/SKILL.md +3 -4
  46. package/pack/.claude/skills/devrites-frontend-craft/reference/reuse-first.md +3 -4
  47. package/pack/.claude/skills/devrites-lib/reference/standards/README.md +5 -1
  48. package/pack/.claude/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +30 -0
  49. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +35 -17
  50. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +11 -3
  51. package/pack/.claude/skills/devrites-lib/reference/standards/ci-cd.md +19 -0
  52. package/pack/.claude/skills/devrites-lib/reference/standards/code-review.md +1 -1
  53. package/pack/.claude/skills/devrites-lib/reference/standards/core.md +5 -0
  54. package/pack/.claude/skills/devrites-lib/reference/standards/data-integrity.md +95 -0
  55. package/pack/.claude/skills/devrites-lib/reference/standards/developer-experience.md +5 -5
  56. package/pack/.claude/skills/devrites-lib/reference/standards/documentation.md +28 -29
  57. package/pack/.claude/skills/devrites-lib/reference/standards/edge-case-trace.md +70 -10
  58. package/pack/.claude/skills/devrites-lib/reference/standards/integration-reliability.md +79 -0
  59. package/pack/.claude/skills/devrites-lib/reference/standards/loop-operations.md +85 -0
  60. package/pack/.claude/skills/devrites-lib/reference/standards/observability.md +10 -0
  61. package/pack/.claude/skills/devrites-lib/reference/standards/one-shot-actions.md +1 -6
  62. package/pack/.claude/skills/devrites-lib/reference/standards/patterns.md +20 -0
  63. package/pack/.claude/skills/devrites-lib/reference/standards/repository-topology.md +73 -0
  64. package/pack/.claude/skills/devrites-lib/reference/standards/security-checklist.md +6 -2
  65. package/pack/.claude/skills/devrites-lib/reference/standards/security.md +51 -16
  66. package/pack/.claude/skills/devrites-lib/reference/standards/skill-authoring.md +35 -40
  67. package/pack/.claude/skills/devrites-lib/reference/standards/test-proof-checklist.md +4 -0
  68. package/pack/.claude/skills/devrites-lib/reference/standards/testing.md +51 -6
  69. package/pack/.claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +411 -102
  70. package/pack/.claude/skills/rite/SKILL.md +2 -0
  71. package/pack/.claude/skills/rite-adopt/SKILL.md +8 -10
  72. package/pack/.claude/skills/rite-adopt/reference/adoption.md +13 -15
  73. package/pack/.claude/skills/rite-autocomplete/SKILL.md +98 -139
  74. package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +11 -5
  75. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +99 -114
  76. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +92 -124
  77. package/pack/.claude/skills/rite-build/SKILL.md +51 -73
  78. package/pack/.claude/skills/rite-build/reference/phase-contract.md +9 -18
  79. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +37 -4
  80. package/pack/.claude/skills/rite-clarify/SKILL.md +3 -2
  81. package/pack/.claude/skills/rite-converge/SKILL.md +4 -2
  82. package/pack/.claude/skills/rite-converge/reference/convergence-assessment.md +8 -4
  83. package/pack/.claude/skills/rite-customize/SKILL.md +16 -18
  84. package/pack/.claude/skills/rite-define/SKILL.md +60 -62
  85. package/pack/.claude/skills/rite-define/reference/plan-template.md +88 -71
  86. package/pack/.claude/skills/rite-explain/SKILL.md +2 -1
  87. package/pack/.claude/skills/rite-learn/SKILL.md +28 -32
  88. package/pack/.claude/skills/rite-plan/SKILL.md +53 -56
  89. package/pack/.claude/skills/rite-plan/reference/anti-patterns.md +11 -1
  90. package/pack/.claude/skills/rite-plan/reference/dependency-graph.md +11 -2
  91. package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +10 -3
  92. package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +2 -0
  93. package/pack/.claude/skills/rite-polish/reference/adr-promotion.md +7 -7
  94. package/pack/.claude/skills/rite-pressure-test/SKILL.md +24 -31
  95. package/pack/.claude/skills/rite-prove/SKILL.md +95 -156
  96. package/pack/.claude/skills/rite-prove/reference/acceptance-proof.md +28 -0
  97. package/pack/.claude/skills/rite-review/SKILL.md +5 -4
  98. package/pack/.claude/skills/rite-review/reference/five-axis-review.md +6 -0
  99. package/pack/.claude/skills/rite-review/reference/security-review.md +7 -2
  100. package/pack/.claude/skills/rite-seal/reference/final-evidence.md +3 -0
  101. package/pack/.claude/skills/rite-seal/reference/risk-and-rollback.md +19 -4
  102. package/pack/.claude/skills/rite-ship/reference/rollout.md +62 -43
  103. package/pack/.claude/skills/rite-spec/SKILL.md +8 -1
  104. package/pack/.claude/skills/rite-spec/reference/ai-spec-template.md +13 -6
  105. package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +14 -2
  106. package/pack/.claude/skills/rite-spec/reference/spec-template.md +33 -4
  107. package/pack/.claude/skills/rite-temper/SKILL.md +5 -1
  108. package/pack/.claude/skills/rite-vet/SKILL.md +121 -174
  109. package/pack/.claude/skills/rite-vet/reference/anti-patterns.md +14 -2
  110. package/pack/.claude/skills/rite-vet/reference/artifacts.md +15 -9
  111. package/pack/.claude/skills/rite-vet/reference/depth.md +10 -3
  112. package/pack/.claude/skills/rite-vet/reference/review-axes.md +75 -77
  113. package/pack/.claude/skills/rite-watch-pr/SKILL.md +85 -0
  114. package/pack/.claude/skills/rite-zoom-out/SKILL.md +4 -5
  115. package/pack/.claude/workflows/devrites-readonly-review.js +194 -0
  116. package/pack/generated/README.md +1 -1
  117. package/pack/generated/claude/agents/devrites-code-reviewer.md +6 -1
  118. package/pack/generated/claude/agents/devrites-plan-drafter.md +5 -0
  119. package/pack/generated/claude/agents/devrites-plan-reviewer.md +6 -0
  120. package/pack/generated/claude/agents/devrites-proof-runner.md +7 -1
  121. package/pack/generated/claude/agents/devrites-retrospector.md +21 -25
  122. package/pack/generated/claude/agents/devrites-security-auditor.md +7 -3
  123. package/pack/generated/claude/agents/devrites-slice-wright.md +30 -4
  124. package/pack/generated/claude/agents/devrites-spec-reviewer.md +5 -0
  125. package/pack/generated/claude/agents/devrites-strategy-reviewer.md +3 -4
  126. package/pack/generated/claude/agents/devrites-test-analyst.md +5 -0
  127. package/pack/generated/claude/skills/devrites-debug-recovery/SKILL.md +13 -26
  128. package/pack/generated/claude/skills/devrites-debug-recovery/reference/build-the-loop.md +11 -14
  129. package/pack/generated/claude/skills/devrites-doubt/SKILL.md +3 -4
  130. package/pack/generated/claude/skills/devrites-frontend-craft/reference/reuse-first.md +3 -4
  131. package/pack/generated/claude/skills/devrites-lib/reference/standards/README.md +5 -1
  132. package/pack/generated/claude/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +30 -0
  133. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +35 -17
  134. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +11 -3
  135. package/pack/generated/claude/skills/devrites-lib/reference/standards/ci-cd.md +19 -0
  136. package/pack/generated/claude/skills/devrites-lib/reference/standards/code-review.md +1 -1
  137. package/pack/generated/claude/skills/devrites-lib/reference/standards/core.md +5 -0
  138. package/pack/generated/claude/skills/devrites-lib/reference/standards/data-integrity.md +95 -0
  139. package/pack/generated/claude/skills/devrites-lib/reference/standards/developer-experience.md +5 -5
  140. package/pack/generated/claude/skills/devrites-lib/reference/standards/documentation.md +28 -29
  141. package/pack/generated/claude/skills/devrites-lib/reference/standards/edge-case-trace.md +70 -10
  142. package/pack/generated/claude/skills/devrites-lib/reference/standards/integration-reliability.md +79 -0
  143. package/pack/generated/claude/skills/devrites-lib/reference/standards/loop-operations.md +85 -0
  144. package/pack/generated/claude/skills/devrites-lib/reference/standards/observability.md +10 -0
  145. package/pack/generated/claude/skills/devrites-lib/reference/standards/one-shot-actions.md +1 -6
  146. package/pack/generated/claude/skills/devrites-lib/reference/standards/patterns.md +20 -0
  147. package/pack/generated/claude/skills/devrites-lib/reference/standards/repository-topology.md +73 -0
  148. package/pack/generated/claude/skills/devrites-lib/reference/standards/security-checklist.md +6 -2
  149. package/pack/generated/claude/skills/devrites-lib/reference/standards/security.md +51 -16
  150. package/pack/generated/claude/skills/devrites-lib/reference/standards/skill-authoring.md +35 -40
  151. package/pack/generated/claude/skills/devrites-lib/reference/standards/test-proof-checklist.md +4 -0
  152. package/pack/generated/claude/skills/devrites-lib/reference/standards/testing.md +51 -6
  153. package/pack/generated/claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +411 -102
  154. package/pack/generated/claude/skills/rite/SKILL.md +2 -0
  155. package/pack/generated/claude/skills/rite-adopt/SKILL.md +8 -10
  156. package/pack/generated/claude/skills/rite-adopt/reference/adoption.md +13 -15
  157. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +98 -139
  158. package/pack/generated/claude/skills/rite-autocomplete/reference/decision-policy.md +11 -5
  159. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +99 -114
  160. package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +92 -124
  161. package/pack/generated/claude/skills/rite-build/SKILL.md +51 -73
  162. package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +9 -18
  163. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +37 -4
  164. package/pack/generated/claude/skills/rite-clarify/SKILL.md +3 -2
  165. package/pack/generated/claude/skills/rite-converge/SKILL.md +4 -2
  166. package/pack/generated/claude/skills/rite-converge/reference/convergence-assessment.md +8 -4
  167. package/pack/generated/claude/skills/rite-customize/SKILL.md +16 -18
  168. package/pack/generated/claude/skills/rite-define/SKILL.md +60 -62
  169. package/pack/generated/claude/skills/rite-define/reference/plan-template.md +88 -71
  170. package/pack/generated/claude/skills/rite-explain/SKILL.md +2 -1
  171. package/pack/generated/claude/skills/rite-learn/SKILL.md +28 -32
  172. package/pack/generated/claude/skills/rite-plan/SKILL.md +53 -56
  173. package/pack/generated/claude/skills/rite-plan/reference/anti-patterns.md +11 -1
  174. package/pack/generated/claude/skills/rite-plan/reference/dependency-graph.md +11 -2
  175. package/pack/generated/claude/skills/rite-plan/reference/replan-and-repair.md +10 -3
  176. package/pack/generated/claude/skills/rite-plan/reference/task-breakdown.md +2 -0
  177. package/pack/generated/claude/skills/rite-polish/reference/adr-promotion.md +7 -7
  178. package/pack/generated/claude/skills/rite-pressure-test/SKILL.md +24 -31
  179. package/pack/generated/claude/skills/rite-prove/SKILL.md +95 -156
  180. package/pack/generated/claude/skills/rite-prove/reference/acceptance-proof.md +28 -0
  181. package/pack/generated/claude/skills/rite-review/SKILL.md +5 -4
  182. package/pack/generated/claude/skills/rite-review/reference/five-axis-review.md +6 -0
  183. package/pack/generated/claude/skills/rite-review/reference/security-review.md +7 -2
  184. package/pack/generated/claude/skills/rite-seal/reference/final-evidence.md +3 -0
  185. package/pack/generated/claude/skills/rite-seal/reference/risk-and-rollback.md +19 -4
  186. package/pack/generated/claude/skills/rite-ship/reference/rollout.md +62 -43
  187. package/pack/generated/claude/skills/rite-spec/SKILL.md +8 -1
  188. package/pack/generated/claude/skills/rite-spec/reference/ai-spec-template.md +13 -6
  189. package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +14 -2
  190. package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +33 -4
  191. package/pack/generated/claude/skills/rite-temper/SKILL.md +5 -1
  192. package/pack/generated/claude/skills/rite-vet/SKILL.md +121 -174
  193. package/pack/generated/claude/skills/rite-vet/reference/anti-patterns.md +14 -2
  194. package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +15 -9
  195. package/pack/generated/claude/skills/rite-vet/reference/depth.md +10 -3
  196. package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +75 -77
  197. package/pack/generated/claude/skills/rite-watch-pr/SKILL.md +85 -0
  198. package/pack/generated/claude/skills/rite-zoom-out/SKILL.md +4 -5
  199. package/pack/generated/claude/workflows/devrites-readonly-review.js +194 -0
  200. package/pack/generated/codex/agents/devrites-code-reviewer.toml +6 -1
  201. package/pack/generated/codex/agents/devrites-plan-drafter.toml +5 -0
  202. package/pack/generated/codex/agents/devrites-plan-reviewer.toml +6 -0
  203. package/pack/generated/codex/agents/devrites-proof-runner.toml +7 -1
  204. package/pack/generated/codex/agents/devrites-retrospector.toml +21 -25
  205. package/pack/generated/codex/agents/devrites-security-auditor.toml +7 -3
  206. package/pack/generated/codex/agents/devrites-slice-wright.toml +30 -4
  207. package/pack/generated/codex/agents/devrites-spec-reviewer.toml +5 -0
  208. package/pack/generated/codex/agents/devrites-strategy-reviewer.toml +3 -4
  209. package/pack/generated/codex/agents/devrites-test-analyst.toml +5 -0
  210. package/pack/generated/codex/skills/devrites-debug-recovery/SKILL.md +13 -26
  211. package/pack/generated/codex/skills/devrites-debug-recovery/reference/build-the-loop.md +11 -14
  212. package/pack/generated/codex/skills/devrites-doubt/SKILL.md +3 -4
  213. package/pack/generated/codex/skills/devrites-frontend-craft/reference/reuse-first.md +3 -4
  214. package/pack/generated/codex/skills/devrites-lib/reference/standards/README.md +5 -1
  215. package/pack/generated/codex/skills/devrites-lib/reference/standards/acceptance-preserving-reslice.md +30 -0
  216. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +35 -17
  217. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +11 -3
  218. package/pack/generated/codex/skills/devrites-lib/reference/standards/ci-cd.md +19 -0
  219. package/pack/generated/codex/skills/devrites-lib/reference/standards/code-review.md +1 -1
  220. package/pack/generated/codex/skills/devrites-lib/reference/standards/core.md +5 -0
  221. package/pack/generated/codex/skills/devrites-lib/reference/standards/data-integrity.md +95 -0
  222. package/pack/generated/codex/skills/devrites-lib/reference/standards/developer-experience.md +5 -5
  223. package/pack/generated/codex/skills/devrites-lib/reference/standards/documentation.md +28 -29
  224. package/pack/generated/codex/skills/devrites-lib/reference/standards/edge-case-trace.md +70 -10
  225. package/pack/generated/codex/skills/devrites-lib/reference/standards/integration-reliability.md +79 -0
  226. package/pack/generated/codex/skills/devrites-lib/reference/standards/loop-operations.md +85 -0
  227. package/pack/generated/codex/skills/devrites-lib/reference/standards/observability.md +10 -0
  228. package/pack/generated/codex/skills/devrites-lib/reference/standards/one-shot-actions.md +1 -6
  229. package/pack/generated/codex/skills/devrites-lib/reference/standards/patterns.md +20 -0
  230. package/pack/generated/codex/skills/devrites-lib/reference/standards/repository-topology.md +73 -0
  231. package/pack/generated/codex/skills/devrites-lib/reference/standards/security-checklist.md +6 -2
  232. package/pack/generated/codex/skills/devrites-lib/reference/standards/security.md +51 -16
  233. package/pack/generated/codex/skills/devrites-lib/reference/standards/skill-authoring.md +35 -40
  234. package/pack/generated/codex/skills/devrites-lib/reference/standards/test-proof-checklist.md +4 -0
  235. package/pack/generated/codex/skills/devrites-lib/reference/standards/testing.md +51 -6
  236. package/pack/generated/codex/skills/devrites-lib/reference/standards/workflow-artifacts.md +411 -102
  237. package/pack/generated/codex/skills/rite/SKILL.md +2 -0
  238. package/pack/generated/codex/skills/rite-adopt/SKILL.md +8 -10
  239. package/pack/generated/codex/skills/rite-adopt/reference/adoption.md +13 -15
  240. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +98 -139
  241. package/pack/generated/codex/skills/rite-autocomplete/reference/decision-policy.md +11 -5
  242. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +99 -114
  243. package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +92 -124
  244. package/pack/generated/codex/skills/rite-build/SKILL.md +51 -73
  245. package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +9 -18
  246. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +37 -4
  247. package/pack/generated/codex/skills/rite-clarify/SKILL.md +3 -2
  248. package/pack/generated/codex/skills/rite-converge/SKILL.md +4 -2
  249. package/pack/generated/codex/skills/rite-converge/reference/convergence-assessment.md +8 -4
  250. package/pack/generated/codex/skills/rite-customize/SKILL.md +16 -18
  251. package/pack/generated/codex/skills/rite-define/SKILL.md +60 -62
  252. package/pack/generated/codex/skills/rite-define/reference/plan-template.md +88 -71
  253. package/pack/generated/codex/skills/rite-explain/SKILL.md +2 -1
  254. package/pack/generated/codex/skills/rite-learn/SKILL.md +28 -32
  255. package/pack/generated/codex/skills/rite-plan/SKILL.md +53 -56
  256. package/pack/generated/codex/skills/rite-plan/reference/anti-patterns.md +11 -1
  257. package/pack/generated/codex/skills/rite-plan/reference/dependency-graph.md +11 -2
  258. package/pack/generated/codex/skills/rite-plan/reference/replan-and-repair.md +10 -3
  259. package/pack/generated/codex/skills/rite-plan/reference/task-breakdown.md +2 -0
  260. package/pack/generated/codex/skills/rite-polish/reference/adr-promotion.md +7 -7
  261. package/pack/generated/codex/skills/rite-pressure-test/SKILL.md +24 -31
  262. package/pack/generated/codex/skills/rite-prove/SKILL.md +95 -156
  263. package/pack/generated/codex/skills/rite-prove/reference/acceptance-proof.md +28 -0
  264. package/pack/generated/codex/skills/rite-review/SKILL.md +5 -4
  265. package/pack/generated/codex/skills/rite-review/reference/five-axis-review.md +6 -0
  266. package/pack/generated/codex/skills/rite-review/reference/security-review.md +7 -2
  267. package/pack/generated/codex/skills/rite-seal/reference/final-evidence.md +3 -0
  268. package/pack/generated/codex/skills/rite-seal/reference/risk-and-rollback.md +19 -4
  269. package/pack/generated/codex/skills/rite-ship/reference/rollout.md +62 -43
  270. package/pack/generated/codex/skills/rite-spec/SKILL.md +8 -1
  271. package/pack/generated/codex/skills/rite-spec/reference/ai-spec-template.md +13 -6
  272. package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +14 -2
  273. package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +33 -4
  274. package/pack/generated/codex/skills/rite-temper/SKILL.md +5 -1
  275. package/pack/generated/codex/skills/rite-vet/SKILL.md +121 -174
  276. package/pack/generated/codex/skills/rite-vet/reference/anti-patterns.md +14 -2
  277. package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +15 -9
  278. package/pack/generated/codex/skills/rite-vet/reference/depth.md +10 -3
  279. package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +75 -77
  280. package/pack/generated/codex/skills/rite-watch-pr/SKILL.md +85 -0
  281. package/pack/generated/codex/skills/rite-zoom-out/SKILL.md +4 -5
  282. package/package.json +1 -1
  283. package/scripts/build-host-artifacts.sh +3 -1
@@ -9,37 +9,99 @@ import (
9
9
  "testing"
10
10
  "time"
11
11
 
12
+ internalgate "github.com/devrites/devrites/internal/gate"
12
13
  "github.com/devrites/devrites/internal/lib"
14
+ "github.com/devrites/devrites/internal/state"
13
15
  "github.com/devrites/devrites/internal/testutil"
14
16
  )
15
17
 
16
18
  func TestReadinessBlocksIncompletePhase(t *testing.T) {
17
19
  root := newWorkspace(t)
18
- out, _, code := runDevrites(t, root, "check", "readiness", "auth-tokens") // build phase, tasks empty
19
- if code != 3 {
20
- t.Fatalf("exit = %d, want 3 (blocked)", code)
21
- }
22
- if !strings.Contains(out, `result: blocked (missing to leave "build": tasks.md)`) {
23
- t.Errorf("stdout missing the block line\n%s", out)
24
- }
25
- if !strings.Contains(out, "devrites-engine check readiness auth-tokens") {
26
- t.Errorf("stdout missing the actionable retry step\n%s", out)
20
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "auth-tokens") // build phase, tasks empty
21
+ wantOut := "gate: readiness\n" +
22
+ "feature: auth-tokens\n" +
23
+ "phase: build\n" +
24
+ "result: blocked (missing to leave \"build\": tasks.md)\n" +
25
+ "reason: DRV-GATE-READINESS-MISSING\n" +
26
+ "next: add real content to tasks.md\n" +
27
+ "retry: devrites-engine check readiness auth-tokens\n"
28
+ if code != 3 || out != wantOut || errOut != "" {
29
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=3 stdout=%q stderr empty", code, out, errOut, wantOut)
27
30
  }
28
31
  }
29
32
 
30
33
  func TestReadinessPassesCompletePhase(t *testing.T) {
31
34
  root := newWorkspace(t)
32
- out, _, code := runDevrites(t, root, "check", "readiness", "search-ranking") // spec phase, spec present
33
- if code != 0 {
34
- t.Fatalf("exit = %d, want 0 (pass)", code)
35
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "search-ranking")
36
+ wantOut := "gate: readiness\n" +
37
+ "feature: search-ranking\n" +
38
+ "phase: spec\n" +
39
+ "result: pass\n" +
40
+ "reason: DRV-GATE-READINESS-PASSED\n"
41
+ if code != 0 || out != wantOut || errOut != "" {
42
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=0 stdout=%q stderr empty", code, out, errOut, wantOut)
35
43
  }
36
- if !strings.Contains(out, "result: pass") {
37
- t.Errorf("stdout not a pass\n%s", out)
44
+ }
45
+
46
+ func TestReadinessBlocksAbsentRequiredArtifactExactCLIContract(t *testing.T) {
47
+ root := filepath.Join(t.TempDir(), ".devrites")
48
+ const slug = "absent-required"
49
+ writeCompleteGateCLIWorkspace(t, root, slug, state.PhaseSpec, state.PhaseSpec, "none\n")
50
+ if err := os.Remove(filepath.Join(root, "work", slug, "spec.md")); err != nil {
51
+ t.Fatal(err)
38
52
  }
39
- // A not-yet-required section (proof, empty at the spec phase) must not appear
40
- // as a blocker.
41
- if strings.Contains(out, "blocked") {
42
- t.Errorf("an empty not-yet-required section blocked readiness\n%s", out)
53
+
54
+ out, errOut, code := runDevrites(t, root, "check", "readiness", slug)
55
+ wantOut := "gate: readiness\n" +
56
+ "feature: absent-required\n" +
57
+ "phase: spec\n" +
58
+ "result: blocked (missing to leave \"spec\": spec.md)\n" +
59
+ "reason: DRV-GATE-READINESS-MISSING\n" +
60
+ "next: add real content to spec.md\n" +
61
+ "retry: devrites-engine check readiness absent-required\n"
62
+ if code != 3 || out != wantOut || errOut != "" {
63
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=3 stdout=%q stderr empty", code, out, errOut, wantOut)
64
+ }
65
+ }
66
+
67
+ func TestReadinessEmitBindingPassesExactCLIContract(t *testing.T) {
68
+ root := filepath.Join(t.TempDir(), ".devrites")
69
+ const slug = "binding-success"
70
+ writeCompleteGateCLIWorkspace(t, root, slug, state.PhaseBuild, state.PhaseBuild, "none\n")
71
+
72
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "--emit-binding", slug)
73
+ const wantOut = "Readiness inputs SHA-256: 71c2d192ea09bca1d2c8806cb197e7fa4d1d08e0b331cf25b2e1bcb7ecac34e4\n"
74
+ if code != 0 || out != wantOut || errOut != "" {
75
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=0 stdout=%q stderr empty", code, out, errOut, wantOut)
76
+ }
77
+ }
78
+
79
+ func TestReadinessBlocksStaleBindingExactCLIContract(t *testing.T) {
80
+ root := filepath.Join(t.TempDir(), ".devrites")
81
+ const slug = "stale-readiness"
82
+ writeCompleteGateCLIWorkspace(t, root, slug, state.PhaseBuild, state.PhaseBuild, "none\n")
83
+ workspace := filepath.Join(root, "work", slug)
84
+ binding, err := internalgate.ReadinessBinding(root, slug)
85
+ if err != nil {
86
+ t.Fatal(err)
87
+ }
88
+ testutil.AppendFile(t, filepath.Join(workspace, "eng-review.md"), "\n"+binding+"\n")
89
+ testutil.WriteFile(t, filepath.Join(workspace, "plan.md"), "# Plan\n\nChanged after Vet.\n")
90
+ expected, err := internalgate.ReadinessBinding(root, slug)
91
+ if err != nil {
92
+ t.Fatal(err)
93
+ }
94
+
95
+ out, errOut, code := runDevrites(t, root, "check", "readiness", slug)
96
+ wantOut := "gate: readiness\n" +
97
+ "feature: " + slug + "\n" +
98
+ "phase: build\n" +
99
+ "result: blocked (state invariant)\n" +
100
+ "reason: DRV-GATE-READINESS-STALE\n" +
101
+ "invariant: readiness inputs are stale or the binding is invalid; rerun /rite-vet and record exactly one standalone line: " + expected + "\n" +
102
+ "retry: devrites-engine check readiness " + slug + "\n"
103
+ if code != 3 || out != wantOut || errOut != "" {
104
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=3 stdout=%q stderr empty", code, out, errOut, wantOut)
43
105
  }
44
106
  }
45
107
 
@@ -74,6 +136,47 @@ func TestReadinessUsesStructuralArtifactsOnly(t *testing.T) {
74
136
  }
75
137
  }
76
138
 
139
+ func TestGateQuestionPolicyCLIContract(t *testing.T) {
140
+ const openQuestion = "## q-1\nstatus: open\ngate: blocking\n"
141
+ cases := []struct {
142
+ name string
143
+ kind string
144
+ current state.Phase
145
+ required state.Phase
146
+ wantCode int
147
+ wantResult string
148
+ wantReason string
149
+ }{
150
+ {name: "frame-open", kind: "readiness", current: state.PhaseFrame, required: state.PhaseFrame, wantCode: 0, wantResult: "pass", wantReason: "DRV-GATE-READINESS-PASSED"},
151
+ {name: "spec-open", kind: "readiness", current: state.PhaseSpec, required: state.PhaseSpec, wantCode: 0, wantResult: "pass", wantReason: "DRV-GATE-READINESS-PASSED"},
152
+ {name: "clarify-open", kind: "readiness", current: state.PhaseClarify, required: state.PhaseClarify, wantCode: 3, wantResult: "blocked (state invariant)", wantReason: "DRV-GATE-READINESS-MISSING"},
153
+ {name: "seal-from-spec", kind: "seal", current: state.PhaseSpec, required: state.PhaseSeal, wantCode: 3, wantResult: "blocked (state invariant)", wantReason: "DRV-GATE-SEAL-MISSING"},
154
+ }
155
+
156
+ for _, tc := range cases {
157
+ t.Run(tc.name, func(t *testing.T) {
158
+ root := filepath.Join(t.TempDir(), ".devrites")
159
+ writeCompleteGateCLIWorkspace(t, root, tc.name, tc.current, tc.required, openQuestion)
160
+ if tc.kind == "seal" {
161
+ binding, err := internalgate.ReadinessBinding(root, tc.name)
162
+ if err != nil {
163
+ t.Fatal(err)
164
+ }
165
+ testutil.AppendFile(t, filepath.Join(root, "work", tc.name, "eng-review.md"), "\n"+binding+"\n")
166
+ }
167
+
168
+ out, errOut, code := runDevrites(t, root, "check", tc.kind, tc.name)
169
+ wantOut := "gate: " + tc.kind + "\nfeature: " + tc.name + "\nphase: " + string(tc.current) + "\nresult: " + tc.wantResult + "\nreason: " + tc.wantReason + "\n"
170
+ if tc.wantCode == 3 {
171
+ wantOut += "invariant: open blocking human question(s) remain in questions.md but state.md is not awaiting_human\nretry: devrites-engine check " + tc.kind + " " + tc.name + "\n"
172
+ }
173
+ if code != tc.wantCode || out != wantOut || errOut != "" {
174
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=%d stdout=%q stderr empty", code, out, errOut, tc.wantCode, wantOut)
175
+ }
176
+ })
177
+ }
178
+ }
179
+
77
180
  func TestSealBlocksWhenSealSectionsMissing(t *testing.T) {
78
181
  root := newWorkspace(t)
79
182
  out, _, code := runDevrites(t, root, "check", "seal", "auth-tokens")
@@ -91,19 +194,21 @@ func TestSealPassesWhenComplete(t *testing.T) {
91
194
  if err := os.Chtimes(source, time.Unix(2_000_000_000, 0), time.Unix(2_000_000_000, 0)); err != nil {
92
195
  t.Fatal(err)
93
196
  }
197
+ digest, _, err := lib.CandidateIdentity(root, "final")
198
+ if err != nil {
199
+ t.Fatal(err)
200
+ }
94
201
  chdirForSeal(t, project)
95
202
 
96
203
  out, errOut, code := runDevrites(t, root, "check", "seal", "final")
97
- if code != 0 {
98
- t.Fatalf("exit = %d, want 0\nstdout:\n%s\nstderr:\n%s", code, out, errOut)
99
- }
100
- for _, want := range []string{
101
- "result: pass",
102
- "evidence-fresh: OK",
103
- } {
104
- if !strings.Contains(out, want) {
105
- t.Fatalf("stdout missing %q:\n%s", want, out)
106
- }
204
+ wantOut := "evidence-fresh: OK: candidate digest " + digest + " matches evidence, review, and seal.\n" +
205
+ "gate: seal\n" +
206
+ "feature: final\n" +
207
+ "phase: seal\n" +
208
+ "result: pass\n" +
209
+ "reason: DRV-GATE-SEAL-PASSED\n"
210
+ if code != 0 || out != wantOut || errOut != "" {
211
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=0 stdout=%q stderr empty", code, out, errOut, wantOut)
107
212
  }
108
213
  }
109
214
 
@@ -198,6 +303,276 @@ func TestSealTracksCanonicalQuestionTableStatus(t *testing.T) {
198
303
  }
199
304
  }
200
305
 
306
+ func TestWorkspaceObservationEarlyStateErrorsCLIContract(t *testing.T) {
307
+ for _, test := range []struct {
308
+ name string
309
+ slug string
310
+ mutate func(*testing.T, string)
311
+ wantErr string
312
+ notDisclose []string
313
+ }{
314
+ {
315
+ name: "absent state",
316
+ slug: "absent-state",
317
+ mutate: func(t *testing.T, workspace string) {
318
+ if err := os.Remove(filepath.Join(workspace, "state.md")); err != nil {
319
+ t.Fatal(err)
320
+ }
321
+ },
322
+ wantErr: `devrites: gate readiness: feature "absent-state": state.md is absent; add real content to state.md and retry
323
+ `,
324
+ },
325
+ {
326
+ name: "empty state",
327
+ slug: "empty-state",
328
+ mutate: func(t *testing.T, workspace string) {
329
+ testutil.WriteFile(t, filepath.Join(workspace, "state.md"), "")
330
+ },
331
+ wantErr: `devrites: gate readiness: feature "empty-state": state.md is empty; add real content to state.md and retry
332
+ `,
333
+ },
334
+ {
335
+ name: "malformed state",
336
+ slug: "malformed-state",
337
+ mutate: func(t *testing.T, workspace string) {
338
+ testutil.WriteFile(t, filepath.Join(workspace, "state.md"), "# State\n\nhostile-secret\x00\n")
339
+ },
340
+ wantErr: `devrites: gate readiness: feature "malformed-state": state.md is malformed (malformed_markdown); repair state.md and retry
341
+ `,
342
+ notDisclose: []string{"hostile-secret"},
343
+ },
344
+ {
345
+ name: "unsafe state final symlink",
346
+ slug: "unsafe-state",
347
+ mutate: func(t *testing.T, workspace string) {
348
+ const target = "hostile-state-target.md"
349
+ statePath := filepath.Join(workspace, "state.md")
350
+ if err := os.Remove(statePath); err != nil {
351
+ t.Fatal(err)
352
+ }
353
+ testutil.WriteFile(t, filepath.Join(workspace, target), "- Phase: spec\n- Status: running\n")
354
+ if err := os.Symlink(target, statePath); err != nil {
355
+ t.Fatalf("create final symlink fixture: %v", err)
356
+ }
357
+ },
358
+ wantErr: `devrites: gate readiness: feature "unsafe-state": state.md is unsafe (final_symlink); repair state.md and retry
359
+ `,
360
+ notDisclose: []string{"hostile-state-target.md"},
361
+ },
362
+ {
363
+ name: "state without phase",
364
+ slug: "state-without-phase",
365
+ mutate: func(t *testing.T, workspace string) {
366
+ testutil.WriteFile(t, filepath.Join(workspace, "state.md"), "# State\n\n- Status: running\n")
367
+ },
368
+ wantErr: `devrites: gate readiness: feature "state-without-phase": no phase in state.md ledger; record phase in state.md and retry
369
+ `,
370
+ },
371
+ {
372
+ name: "state with unknown phase",
373
+ slug: "state-with-unknown-phase",
374
+ mutate: func(t *testing.T, workspace string) {
375
+ testutil.WriteFile(t, filepath.Join(workspace, "state.md"), "# State\n\n- Phase: mystery\n- Status: running\n")
376
+ },
377
+ wantErr: `devrites: gate readiness: feature "state-with-unknown-phase": unknown phase "mystery"; record a known phase in state.md and retry
378
+ `,
379
+ },
380
+ } {
381
+ t.Run(test.name, func(t *testing.T) {
382
+ root := filepath.Join(t.TempDir(), ".devrites")
383
+ writeCompleteGateCLIWorkspace(t, root, test.slug, state.PhaseSpec, state.PhaseSpec, "none\n")
384
+ workspace := filepath.Join(root, "work", test.slug)
385
+ test.mutate(t, workspace)
386
+
387
+ out, errOut, code := runDevrites(t, root, "check", "readiness", test.slug)
388
+ if code != 2 || out != "" || errOut != test.wantErr {
389
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=2 stdout empty stderr=%q", code, out, errOut, test.wantErr)
390
+ }
391
+ for _, secret := range test.notDisclose {
392
+ if strings.Contains(out, secret) || strings.Contains(errOut, secret) {
393
+ t.Errorf("CLI output disclosed hostile fixture content %q: stdout=%q stderr=%q", secret, out, errOut)
394
+ }
395
+ }
396
+ })
397
+ }
398
+ }
399
+
400
+ func TestWorkspaceObservationGateDiagnosticCLIContract(t *testing.T) {
401
+ root := filepath.Join(t.TempDir(), ".devrites")
402
+ writeCompleteGateCLIWorkspace(t, root, "diagnostic", state.PhaseSpec, state.PhaseSpec, "none\n")
403
+ testutil.WriteFile(t, filepath.Join(root, "work", "diagnostic", "spec.md"), "hostile-secret\x00")
404
+
405
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "diagnostic")
406
+ wantOut := "gate: readiness\n" +
407
+ "feature: diagnostic\n" +
408
+ "phase: spec\n" +
409
+ "result: blocked (missing to leave \"spec\": spec.md)\n" +
410
+ "reason: DRV-GATE-READINESS-MISSING\n" +
411
+ "artifact: spec.md: malformed (malformed_markdown)\n" +
412
+ "next: repair spec.md: replace invalid Markdown with valid Markdown; required artifacts need substantive content\n" +
413
+ "retry: devrites-engine check readiness diagnostic\n"
414
+ if code != 3 || out != wantOut || errOut != "" {
415
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=3 stdout=%q stderr empty", code, out, errOut, wantOut)
416
+ }
417
+ }
418
+
419
+ func TestWorkspaceObservationStandaloneBindingDiagnosticCLIContract(t *testing.T) {
420
+ root := filepath.Join(t.TempDir(), ".devrites")
421
+ writeCompleteGateCLIWorkspace(t, root, "binding-diagnostic", state.PhaseBuild, state.PhaseBuild, "none\n")
422
+ testutil.WriteFile(t, filepath.Join(root, "work", "binding-diagnostic", "strategy.md"), "hostile-secret\x00")
423
+
424
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "--emit-binding", "binding-diagnostic")
425
+ wantErr := "readiness-binding: BLOCKED: readiness input strategy.md is malformed (malformed_markdown); replace invalid Markdown with valid Markdown\n"
426
+ if code != 3 || out != "" || errOut != wantErr {
427
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=3 stdout empty stderr=%q", code, out, errOut, wantErr)
428
+ }
429
+ }
430
+
431
+ func TestWorkspaceObservationConstructibleDiagnosticsCLIContract(t *testing.T) {
432
+ for _, test := range []struct {
433
+ name string
434
+ slug string
435
+ mutate func(*testing.T, string)
436
+ diagnostic string
437
+ recovery string
438
+ }{
439
+ {
440
+ name: "final symlink gate",
441
+ slug: "final-symlink",
442
+ mutate: func(t *testing.T, workspace string) {
443
+ path := filepath.Join(workspace, "spec.md")
444
+ if err := os.Remove(path); err != nil {
445
+ t.Fatal(err)
446
+ }
447
+ if err := os.Symlink("brief.md", path); err != nil {
448
+ t.Fatalf("create final symlink fixture: %v", err)
449
+ }
450
+ },
451
+ diagnostic: "artifact: spec.md: unsafe (final_symlink)\n",
452
+ recovery: "next: repair spec.md: replace the symlink with a regular file\n",
453
+ },
454
+ {
455
+ name: "nonregular gate",
456
+ slug: "nonregular",
457
+ mutate: func(t *testing.T, workspace string) {
458
+ path := filepath.Join(workspace, "spec.md")
459
+ if err := os.Remove(path); err != nil {
460
+ t.Fatal(err)
461
+ }
462
+ if err := os.Mkdir(path, 0o755); err != nil {
463
+ t.Fatal(err)
464
+ }
465
+ },
466
+ diagnostic: "artifact: spec.md: unsafe (non_regular)\n",
467
+ recovery: "next: repair spec.md: replace the non-regular entry with a regular file\n",
468
+ },
469
+ } {
470
+ t.Run(test.name, func(t *testing.T) {
471
+ root := filepath.Join(t.TempDir(), ".devrites")
472
+ writeCompleteGateCLIWorkspace(t, root, test.slug, state.PhaseSpec, state.PhaseSpec, "none\n")
473
+ workspace := filepath.Join(root, "work", test.slug)
474
+ test.mutate(t, workspace)
475
+
476
+ out, errOut, code := runDevrites(t, root, "check", "readiness", test.slug)
477
+ wantOut := "gate: readiness\n" +
478
+ "feature: " + test.slug + "\n" +
479
+ "phase: spec\n" +
480
+ "result: blocked (missing to leave \"spec\": spec.md)\n" +
481
+ "reason: DRV-GATE-READINESS-MISSING\n" +
482
+ test.diagnostic +
483
+ test.recovery +
484
+ "retry: devrites-engine check readiness " + test.slug + "\n"
485
+ if code != 3 || out != wantOut || errOut != "" {
486
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=3 stdout=%q stderr empty", code, out, errOut, wantOut)
487
+ }
488
+ })
489
+ }
490
+
491
+ t.Run("file too large standalone binding", func(t *testing.T) {
492
+ root := filepath.Join(t.TempDir(), ".devrites")
493
+ writeCompleteGateCLIWorkspace(t, root, "binding-too-large", state.PhaseBuild, state.PhaseBuild, "none\n")
494
+ testutil.WriteFile(t, filepath.Join(root, "work", "binding-too-large", "strategy.md"), strings.Repeat("x", (1<<20)+1))
495
+
496
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "--emit-binding", "binding-too-large")
497
+ wantErr := "readiness-binding: BLOCKED: readiness input strategy.md is unsafe (file_too_large); reduce the file to at most 1 MiB\n"
498
+ if code != 3 || out != "" || errOut != wantErr {
499
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=3 stdout empty stderr=%q", code, out, errOut, wantErr)
500
+ }
501
+ })
502
+ }
503
+
504
+ func TestWorkspaceObservationWholeFailureCLIChannels(t *testing.T) {
505
+ t.Run("workspace invalid gate", func(t *testing.T) {
506
+ root := filepath.Join(t.TempDir(), ".devrites")
507
+ if err := os.MkdirAll(root, 0o755); err != nil {
508
+ t.Fatal(err)
509
+ }
510
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "missing")
511
+ wantErr := "devrites: gate readiness: workspace observation: workspace_invalid: workspace is unavailable; verify the selected logical workspace and canonical workspace override, then retry\n"
512
+ if code != 2 || out != "" || errOut != wantErr {
513
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=2 stdout empty stderr=%q", code, out, errOut, wantErr)
514
+ }
515
+ })
516
+
517
+ t.Run("workspace invalid binding", func(t *testing.T) {
518
+ root := filepath.Join(t.TempDir(), ".devrites")
519
+ if err := os.MkdirAll(root, 0o755); err != nil {
520
+ t.Fatal(err)
521
+ }
522
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "--emit-binding", "missing")
523
+ wantErr := "readiness-binding: BLOCKED: workspace observation: workspace_invalid: workspace is unavailable; verify the selected logical workspace and canonical workspace override, then retry\n"
524
+ if code != 3 || out != "" || errOut != wantErr {
525
+ t.Fatalf("code=%d stdout=%q stderr=%q, want code=3 stdout empty stderr=%q", code, out, errOut, wantErr)
526
+ }
527
+ })
528
+
529
+ t.Run("aggregate too large gate and binding", func(t *testing.T) {
530
+ root := filepath.Join(t.TempDir(), ".devrites")
531
+ writeCompleteGateCLIWorkspace(t, root, "aggregate", state.PhaseBuild, state.PhaseBuild, "none\n")
532
+ for i, name := range []string{"state.md", "brief.md", "spec.md", "decisions.md", "assumptions.md", "questions.md", "decision-coverage.md", "architecture.md", "plan.md"} {
533
+ prefix := "retained content\n"
534
+ if i == 0 {
535
+ prefix = "- Phase: build\n"
536
+ }
537
+ body := prefix + strings.Repeat("x", (1<<20)-len(prefix))
538
+ testutil.WriteFile(t, filepath.Join(root, "work", "aggregate", name), body)
539
+ }
540
+ wantFailure := "workspace observation: aggregate_too_large: retained content exceeds the 8 MiB aggregate limit; reduce retained Markdown below 8 MiB, then retry"
541
+ out, errOut, code := runDevrites(t, root, "check", "readiness", "aggregate")
542
+ if code != 2 || out != "" || errOut != "devrites: gate readiness: "+wantFailure+"\n" {
543
+ t.Fatalf("gate code=%d stdout=%q stderr=%q", code, out, errOut)
544
+ }
545
+ out, errOut, code = runDevrites(t, root, "check", "readiness", "--emit-binding", "aggregate")
546
+ if code != 3 || out != "" || errOut != "readiness-binding: BLOCKED: "+wantFailure+"\n" {
547
+ t.Fatalf("binding code=%d stdout=%q stderr=%q", code, out, errOut)
548
+ }
549
+ })
550
+ }
551
+
552
+ func writeCompleteGateCLIWorkspace(t *testing.T, root, slug string, current, required state.Phase, questions string) {
553
+ t.Helper()
554
+ policy, ok := state.PolicyFor(required)
555
+ if !ok {
556
+ t.Fatalf("PolicyFor(%q) returned unknown", required)
557
+ }
558
+ questionsRequired := false
559
+ for _, artifact := range policy.RequiredArtifacts {
560
+ name := string(artifact)
561
+ content := "# " + name + "\n\nreal\n"
562
+ switch name {
563
+ case "state.md":
564
+ content = "- Phase: " + string(current) + "\n- Status: running\n"
565
+ case "questions.md":
566
+ questionsRequired = true
567
+ content = questions
568
+ }
569
+ testutil.WriteFile(t, filepath.Join(root, "work", slug, name), content)
570
+ }
571
+ if !questionsRequired {
572
+ testutil.WriteFile(t, filepath.Join(root, "work", slug, "questions.md"), questions)
573
+ }
574
+ }
575
+
201
576
  func newFinalSealRepo(t *testing.T) (string, string) {
202
577
  t.Helper()
203
578
  requireGit(t)