devrites 5.14.4 → 6.0.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 (637) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/NOTICE.md +6 -4
  3. package/README.md +77 -16
  4. package/SECURITY.md +25 -11
  5. package/bin/devrites.mjs +49 -15
  6. package/docs/adr/0001-go-engine-as-control-plane.md +6 -3
  7. package/docs/adr/0029-v5-workspace-schema-and-native-migration.md +9 -0
  8. package/docs/adr/README.md +3 -2
  9. package/docs/agents/issue-tracker.md +1 -1
  10. package/docs/architecture.md +6 -3
  11. package/docs/cli.md +32 -9
  12. package/docs/command-map.md +5 -3
  13. package/docs/engine/state-schema.md +1 -1
  14. package/docs/flow.md +1 -1
  15. package/docs/harness-compliance.md +2 -2
  16. package/docs/release.md +15 -11
  17. package/docs/usage.md +1 -1
  18. package/engine/commands.go +1 -1
  19. package/engine/go.mod +1 -1
  20. package/engine/help.go +41 -15
  21. package/engine/help_test.go +134 -0
  22. package/engine/internal/acceptance/acceptance_test.go +298 -7
  23. package/engine/internal/acceptance/approve.go +7 -2
  24. package/engine/internal/acceptance/cli.go +3 -0
  25. package/engine/internal/acceptance/evidence.go +69 -5
  26. package/engine/internal/acceptance/lint.go +1 -1
  27. package/engine/internal/acceptance/run.go +5 -3
  28. package/engine/internal/acceptance/scaffold.go +5 -16
  29. package/engine/internal/devritespaths/paths.go +7 -6
  30. package/engine/internal/devritespaths/paths_test.go +18 -0
  31. package/engine/internal/fsutil/copy.go +83 -49
  32. package/engine/internal/fsutil/copy_test.go +70 -109
  33. package/engine/internal/gate/gate.go +89 -16
  34. package/engine/internal/gate/gate_test.go +101 -0
  35. package/engine/internal/hostpack/hostpack.go +52 -2
  36. package/engine/internal/hostpack/hostpack_test.go +83 -2
  37. package/engine/internal/install/apply.go +59 -16
  38. package/engine/internal/install/binary.go +10 -1
  39. package/engine/internal/install/install_test.go +428 -0
  40. package/engine/internal/install/merge.go +69 -38
  41. package/engine/internal/install/preflight.go +7 -0
  42. package/engine/internal/install/uninstall.go +43 -4
  43. package/engine/internal/lib/claims.go +25 -4
  44. package/engine/internal/lib/claims_test.go +57 -0
  45. package/engine/internal/lib/closeout.go +41 -3
  46. package/engine/internal/lib/closeout_test.go +144 -0
  47. package/engine/internal/lib/context.go +8 -4
  48. package/engine/internal/lib/context_next_test.go +100 -0
  49. package/engine/internal/lib/detect.go +1 -1
  50. package/engine/internal/lib/detect_test.go +13 -0
  51. package/engine/internal/lib/diffscope.go +19 -9
  52. package/engine/internal/lib/dispatch.go +7 -0
  53. package/engine/internal/lib/dup.go +40 -37
  54. package/engine/internal/lib/dup_test.go +178 -0
  55. package/engine/internal/lib/manifest_union.go +4 -1
  56. package/engine/internal/lib/manifest_union_test.go +37 -0
  57. package/engine/internal/lib/metrics.go +4 -0
  58. package/engine/internal/lib/metrics_test.go +28 -0
  59. package/engine/internal/lib/migrate_test.go +59 -0
  60. package/engine/internal/lib/observe_budgets.go +25 -9
  61. package/engine/internal/lib/observe_budgets_test.go +254 -0
  62. package/engine/internal/lib/observe_summary.go +23 -2
  63. package/engine/internal/lib/open_visual.go +4 -2
  64. package/engine/internal/lib/open_visual_test.go +11 -0
  65. package/engine/internal/lib/regression.go +62 -23
  66. package/engine/internal/lib/regression_test.go +103 -0
  67. package/engine/internal/lib/resolve.go +36 -17
  68. package/engine/internal/lib/resolve_remediation_test.go +132 -0
  69. package/engine/internal/lib/skilltrust.go +0 -11
  70. package/engine/internal/lib/slicecheck.go +7 -5
  71. package/engine/internal/lib/slicecheck_test.go +18 -0
  72. package/engine/internal/lib/triggers.go +9 -3
  73. package/engine/internal/lib/triggers_test.go +23 -0
  74. package/engine/internal/lib/util.go +17 -3
  75. package/engine/internal/lib/util_test.go +104 -0
  76. package/engine/internal/lib/visual_outline.go +7 -3
  77. package/engine/internal/lib/visual_outline_test.go +28 -0
  78. package/engine/internal/lib/windows.go +13 -9
  79. package/engine/internal/lib/windows_test.go +98 -0
  80. package/engine/internal/lib/workspace_read.go +2 -11
  81. package/engine/internal/lib/workspace_read_test.go +102 -0
  82. package/engine/internal/markdowntext/markdowntext.go +194 -11
  83. package/engine/internal/markdowntext/testdata/structural.json +250 -0
  84. package/engine/internal/notes/cli.go +30 -12
  85. package/engine/internal/notes/notes.go +242 -39
  86. package/engine/internal/notes/notes_test.go +372 -0
  87. package/engine/internal/overhaul/admit/packet.go +89 -0
  88. package/engine/internal/overhaul/admit/packet_test.go +223 -0
  89. package/engine/internal/overhaul/admit/run.go +4 -0
  90. package/engine/internal/overhaul/bench/run.go +6 -0
  91. package/engine/internal/overhaul/bench/run_test.go +46 -0
  92. package/engine/internal/overhaul/overhaul.go +6 -1
  93. package/engine/internal/overhaul/ovio/ovio.go +10 -3
  94. package/engine/internal/overhaul/ovio/ovio_test.go +75 -0
  95. package/engine/internal/overhaul/packet/packet.go +208 -0
  96. package/engine/internal/overhaul/packet/packet_test.go +263 -0
  97. package/engine/internal/overhaul/records/check.go +6 -0
  98. package/engine/internal/overhaul/records/init.go +16 -5
  99. package/engine/internal/overhaul/records/records_test.go +4 -0
  100. package/engine/internal/overhaul/records/run.go +66 -0
  101. package/engine/internal/overhaul/records/run_test.go +77 -0
  102. package/engine/internal/overhaul/render/run.go +15 -11
  103. package/engine/internal/overhaul/render/run_test.go +463 -1
  104. package/engine/internal/overhaul/render/visual.go +95 -33
  105. package/engine/internal/overhaul/score/run.go +20 -0
  106. package/engine/internal/overhaul/score/run_test.go +156 -1
  107. package/engine/internal/overhaul/snapshot/run.go +78 -21
  108. package/engine/internal/overhaul/snapshot/run_test.go +344 -8
  109. package/engine/internal/parallel/cli.go +33 -20
  110. package/engine/internal/parallel/cli_test.go +59 -0
  111. package/engine/internal/parallel/git.go +39 -1
  112. package/engine/internal/parallel/ops.go +101 -11
  113. package/engine/internal/parallel/ops_test.go +552 -69
  114. package/engine/internal/parallel/parallel_test.go +31 -1
  115. package/engine/internal/parallel/pathdisjoint.go +19 -1
  116. package/engine/internal/parallel/pathdisjoint_test.go +72 -0
  117. package/engine/internal/parallel/select.go +6 -2
  118. package/engine/internal/release/release.go +13 -3
  119. package/engine/internal/release/release_test.go +208 -3
  120. package/engine/internal/rootfacts/facts.go +9 -0
  121. package/engine/internal/rootfacts/facts_test.go +38 -0
  122. package/engine/internal/state/acceptance.go +7 -1
  123. package/engine/internal/state/budgets.go +11 -10
  124. package/engine/internal/state/budgets_test.go +93 -0
  125. package/engine/internal/state/cursor.go +19 -8
  126. package/engine/internal/state/cursor_test.go +120 -0
  127. package/engine/internal/state/lock_unix.go +7 -1
  128. package/engine/internal/state/lock_windows.go +7 -1
  129. package/engine/internal/state/state_test.go +49 -18
  130. package/engine/internal/state/taskgraph.go +18 -4
  131. package/engine/internal/state/taskgraph_test.go +43 -0
  132. package/engine/internal/state/workspaceschema.go +16 -2
  133. package/engine/internal/state/workspaceschema_test.go +34 -0
  134. package/engine/internal/state/write.go +67 -6
  135. package/engine/internal/state/write_test.go +136 -0
  136. package/engine/internal/version/version_test.go +2 -0
  137. package/engine/main.go +8 -1
  138. package/engine/observation_contract_test.go +1 -1
  139. package/engine/root_routing_test.go +23 -1
  140. package/install.sh +132 -12
  141. package/pack/.claude/agents/devrites-spec-reviewer.md +2 -2
  142. package/pack/.claude/skills/devrites-browser-proof/SKILL.md +2 -2
  143. package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  144. package/pack/.claude/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  145. package/pack/.claude/skills/devrites-interview/SKILL.md +4 -4
  146. package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  147. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  148. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +3 -2
  149. package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +6 -5
  150. package/pack/.claude/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  151. package/pack/.claude/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  152. package/pack/.claude/skills/devrites-lib/reference/standards/windows.md +3 -3
  153. package/pack/.claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  154. package/pack/.claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  155. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  156. package/pack/.claude/skills/devrites-ux-shape/SKILL.md +11 -12
  157. package/pack/.claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  158. package/pack/.claude/skills/overhaul/SKILL.md +1 -1
  159. package/pack/.claude/skills/overhaul/references/orchestration.md +5 -3
  160. package/pack/.claude/skills/overhaul/references/records.md +39 -0
  161. package/pack/.claude/skills/overhaul/references/scoring.md +14 -4
  162. package/pack/.claude/skills/rite/reference/menu.md +1 -1
  163. package/pack/.claude/skills/rite-adopt/SKILL.md +8 -2
  164. package/pack/.claude/skills/rite-autocomplete/SKILL.md +11 -6
  165. package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  166. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +1 -1
  167. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  168. package/pack/.claude/skills/rite-build/SKILL.md +2 -1
  169. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +1 -1
  170. package/pack/.claude/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  171. package/pack/.claude/skills/rite-build/reference/checkpoint.md +5 -0
  172. package/pack/.claude/skills/rite-build/reference/parallel-batch.md +2 -2
  173. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +3 -2
  174. package/pack/.claude/skills/rite-clarify/SKILL.md +5 -4
  175. package/pack/.claude/skills/rite-clarify/reference/anti-patterns.md +2 -2
  176. package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +3 -2
  177. package/pack/.claude/skills/rite-converge/SKILL.md +2 -0
  178. package/pack/.claude/skills/rite-customize/SKILL.md +6 -4
  179. package/pack/.claude/skills/rite-define/SKILL.md +2 -0
  180. package/pack/.claude/skills/rite-define/reference/gates.md +8 -7
  181. package/pack/.claude/skills/rite-explain/SKILL.md +1 -1
  182. package/pack/.claude/skills/rite-explain/reference/intake.md +1 -1
  183. package/pack/.claude/skills/rite-fast/SKILL.md +1 -1
  184. package/pack/.claude/skills/rite-plan/SKILL.md +4 -3
  185. package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +4 -4
  186. package/pack/.claude/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  187. package/pack/.claude/skills/rite-prove/reference/browser-proof.md +5 -5
  188. package/pack/.claude/skills/rite-resolve/SKILL.md +3 -3
  189. package/pack/.claude/skills/rite-seal/SKILL.md +4 -3
  190. package/pack/.claude/skills/rite-seal/reference/phase-contract.md +3 -2
  191. package/pack/.claude/skills/rite-seal/reference/seal-template.md +2 -0
  192. package/pack/.claude/skills/rite-ship/SKILL.md +4 -2
  193. package/pack/.claude/skills/rite-ship/reference/git-ship.md +8 -2
  194. package/pack/.claude/skills/rite-ship/reference/ship-template.md +2 -1
  195. package/pack/.claude/skills/rite-spec/SKILL.md +2 -2
  196. package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +1 -1
  197. package/pack/.claude/skills/rite-spec/reference/spec-template.md +7 -3
  198. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +2 -0
  199. package/pack/.claude/skills/rite-temper/SKILL.md +12 -9
  200. package/pack/.claude/skills/rite-temper/reference/scope-modes.md +1 -1
  201. package/pack/.claude/skills/rite-temper/reference/significance.md +10 -3
  202. package/pack/.claude/skills/rite-temper/reference/strategy-template.md +13 -2
  203. package/pack/.claude/skills/rite-vet/SKILL.md +4 -3
  204. package/pack/.claude/skills/rite-vet/reference/artifacts.md +1 -1
  205. package/pack/.claude/workflows/devrites-readonly-review.js +5 -4
  206. package/pack/generated/claude/agents/devrites-spec-reviewer.md +2 -2
  207. package/pack/generated/claude/skills/devrites-browser-proof/SKILL.md +2 -2
  208. package/pack/generated/claude/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  209. package/pack/generated/claude/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  210. package/pack/generated/claude/skills/devrites-interview/SKILL.md +4 -4
  211. package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  212. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  213. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +3 -2
  214. package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +6 -5
  215. package/pack/generated/claude/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  216. package/pack/generated/claude/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  217. package/pack/generated/claude/skills/devrites-lib/reference/standards/windows.md +3 -3
  218. package/pack/generated/claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  219. package/pack/generated/claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  220. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  221. package/pack/generated/claude/skills/devrites-ux-shape/SKILL.md +11 -12
  222. package/pack/generated/claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  223. package/pack/generated/claude/skills/overhaul/SKILL.md +1 -1
  224. package/pack/generated/claude/skills/overhaul/references/orchestration.md +5 -3
  225. package/pack/generated/claude/skills/overhaul/references/records.md +39 -0
  226. package/pack/generated/claude/skills/overhaul/references/scoring.md +14 -4
  227. package/pack/generated/claude/skills/rite/reference/menu.md +1 -1
  228. package/pack/generated/claude/skills/rite-adopt/SKILL.md +8 -2
  229. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +11 -6
  230. package/pack/generated/claude/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  231. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +1 -1
  232. package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  233. package/pack/generated/claude/skills/rite-build/SKILL.md +2 -1
  234. package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +1 -1
  235. package/pack/generated/claude/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  236. package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +5 -0
  237. package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +2 -2
  238. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +3 -2
  239. package/pack/generated/claude/skills/rite-clarify/SKILL.md +5 -4
  240. package/pack/generated/claude/skills/rite-clarify/reference/anti-patterns.md +2 -2
  241. package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +3 -2
  242. package/pack/generated/claude/skills/rite-converge/SKILL.md +2 -0
  243. package/pack/generated/claude/skills/rite-customize/SKILL.md +6 -4
  244. package/pack/generated/claude/skills/rite-define/SKILL.md +2 -0
  245. package/pack/generated/claude/skills/rite-define/reference/gates.md +8 -7
  246. package/pack/generated/claude/skills/rite-explain/SKILL.md +1 -1
  247. package/pack/generated/claude/skills/rite-explain/reference/intake.md +1 -1
  248. package/pack/generated/claude/skills/rite-fast/SKILL.md +1 -1
  249. package/pack/generated/claude/skills/rite-plan/SKILL.md +4 -3
  250. package/pack/generated/claude/skills/rite-plan/reference/replan-and-repair.md +4 -4
  251. package/pack/generated/claude/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  252. package/pack/generated/claude/skills/rite-prove/reference/browser-proof.md +5 -5
  253. package/pack/generated/claude/skills/rite-resolve/SKILL.md +3 -3
  254. package/pack/generated/claude/skills/rite-seal/SKILL.md +4 -3
  255. package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +3 -2
  256. package/pack/generated/claude/skills/rite-seal/reference/seal-template.md +2 -0
  257. package/pack/generated/claude/skills/rite-ship/SKILL.md +4 -2
  258. package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +8 -2
  259. package/pack/generated/claude/skills/rite-ship/reference/ship-template.md +2 -1
  260. package/pack/generated/claude/skills/rite-spec/SKILL.md +2 -2
  261. package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +1 -1
  262. package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +7 -3
  263. package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +2 -0
  264. package/pack/generated/claude/skills/rite-temper/SKILL.md +12 -9
  265. package/pack/generated/claude/skills/rite-temper/reference/scope-modes.md +1 -1
  266. package/pack/generated/claude/skills/rite-temper/reference/significance.md +10 -3
  267. package/pack/generated/claude/skills/rite-temper/reference/strategy-template.md +13 -2
  268. package/pack/generated/claude/skills/rite-vet/SKILL.md +4 -3
  269. package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +1 -1
  270. package/pack/generated/claude/workflows/devrites-readonly-review.js +5 -4
  271. package/pack/generated/codex/AGENTS.md +1 -1
  272. package/pack/generated/codex/agents/devrites-spec-reviewer.toml +2 -2
  273. package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +2 -2
  274. package/pack/generated/codex/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  275. package/pack/generated/codex/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  276. package/pack/generated/codex/skills/devrites-interview/SKILL.md +4 -4
  277. package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  278. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  279. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +3 -2
  280. package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +6 -5
  281. package/pack/generated/codex/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  282. package/pack/generated/codex/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  283. package/pack/generated/codex/skills/devrites-lib/reference/standards/windows.md +3 -3
  284. package/pack/generated/codex/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  285. package/pack/generated/codex/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  286. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  287. package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +11 -12
  288. package/pack/generated/codex/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  289. package/pack/generated/codex/skills/overhaul/SKILL.md +1 -1
  290. package/pack/generated/codex/skills/overhaul/references/orchestration.md +5 -3
  291. package/pack/generated/codex/skills/overhaul/references/records.md +39 -0
  292. package/pack/generated/codex/skills/overhaul/references/scoring.md +14 -4
  293. package/pack/generated/codex/skills/rite/reference/menu.md +1 -1
  294. package/pack/generated/codex/skills/rite-adopt/SKILL.md +8 -2
  295. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +11 -6
  296. package/pack/generated/codex/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  297. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +1 -1
  298. package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  299. package/pack/generated/codex/skills/rite-build/SKILL.md +2 -1
  300. package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +1 -1
  301. package/pack/generated/codex/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  302. package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +5 -0
  303. package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +2 -2
  304. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +3 -2
  305. package/pack/generated/codex/skills/rite-clarify/SKILL.md +5 -4
  306. package/pack/generated/codex/skills/rite-clarify/reference/anti-patterns.md +2 -2
  307. package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +3 -2
  308. package/pack/generated/codex/skills/rite-converge/SKILL.md +2 -0
  309. package/pack/generated/codex/skills/rite-customize/SKILL.md +6 -4
  310. package/pack/generated/codex/skills/rite-define/SKILL.md +2 -0
  311. package/pack/generated/codex/skills/rite-define/reference/gates.md +8 -7
  312. package/pack/generated/codex/skills/rite-explain/SKILL.md +1 -1
  313. package/pack/generated/codex/skills/rite-explain/reference/intake.md +1 -1
  314. package/pack/generated/codex/skills/rite-fast/SKILL.md +1 -1
  315. package/pack/generated/codex/skills/rite-plan/SKILL.md +4 -3
  316. package/pack/generated/codex/skills/rite-plan/reference/replan-and-repair.md +4 -4
  317. package/pack/generated/codex/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  318. package/pack/generated/codex/skills/rite-prove/reference/browser-proof.md +5 -5
  319. package/pack/generated/codex/skills/rite-resolve/SKILL.md +3 -3
  320. package/pack/generated/codex/skills/rite-seal/SKILL.md +4 -3
  321. package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +3 -2
  322. package/pack/generated/codex/skills/rite-seal/reference/seal-template.md +2 -0
  323. package/pack/generated/codex/skills/rite-ship/SKILL.md +4 -2
  324. package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +8 -2
  325. package/pack/generated/codex/skills/rite-ship/reference/ship-template.md +2 -1
  326. package/pack/generated/codex/skills/rite-spec/SKILL.md +2 -2
  327. package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +1 -1
  328. package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +7 -3
  329. package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +2 -0
  330. package/pack/generated/codex/skills/rite-temper/SKILL.md +12 -9
  331. package/pack/generated/codex/skills/rite-temper/reference/scope-modes.md +1 -1
  332. package/pack/generated/codex/skills/rite-temper/reference/significance.md +10 -3
  333. package/pack/generated/codex/skills/rite-temper/reference/strategy-template.md +13 -2
  334. package/pack/generated/codex/skills/rite-vet/SKILL.md +4 -3
  335. package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +1 -1
  336. package/pack/generated/devin/AGENTS.md +1 -1
  337. package/pack/generated/devin/agents/devrites-spec-reviewer.md +2 -2
  338. package/pack/generated/devin/skills/devrites-browser-proof/SKILL.md +2 -2
  339. package/pack/generated/devin/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  340. package/pack/generated/devin/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  341. package/pack/generated/devin/skills/devrites-interview/SKILL.md +4 -4
  342. package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  343. package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  344. package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +3 -2
  345. package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +6 -5
  346. package/pack/generated/devin/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  347. package/pack/generated/devin/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  348. package/pack/generated/devin/skills/devrites-lib/reference/standards/windows.md +3 -3
  349. package/pack/generated/devin/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  350. package/pack/generated/devin/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  351. package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  352. package/pack/generated/devin/skills/devrites-ux-shape/SKILL.md +11 -12
  353. package/pack/generated/devin/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  354. package/pack/generated/devin/skills/overhaul/SKILL.md +1 -1
  355. package/pack/generated/devin/skills/overhaul/references/orchestration.md +5 -3
  356. package/pack/generated/devin/skills/overhaul/references/records.md +39 -0
  357. package/pack/generated/devin/skills/overhaul/references/scoring.md +14 -4
  358. package/pack/generated/devin/skills/rite/reference/menu.md +1 -1
  359. package/pack/generated/devin/skills/rite-adopt/SKILL.md +8 -2
  360. package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +11 -6
  361. package/pack/generated/devin/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  362. package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +1 -1
  363. package/pack/generated/devin/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  364. package/pack/generated/devin/skills/rite-build/SKILL.md +2 -1
  365. package/pack/generated/devin/skills/rite-build/reference/afk-discipline.md +1 -1
  366. package/pack/generated/devin/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  367. package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +5 -0
  368. package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +2 -2
  369. package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +3 -2
  370. package/pack/generated/devin/skills/rite-clarify/SKILL.md +5 -4
  371. package/pack/generated/devin/skills/rite-clarify/reference/anti-patterns.md +2 -2
  372. package/pack/generated/devin/skills/rite-clarify/reference/decision-coverage.md +3 -2
  373. package/pack/generated/devin/skills/rite-converge/SKILL.md +2 -0
  374. package/pack/generated/devin/skills/rite-customize/SKILL.md +6 -4
  375. package/pack/generated/devin/skills/rite-define/SKILL.md +2 -0
  376. package/pack/generated/devin/skills/rite-define/reference/gates.md +8 -7
  377. package/pack/generated/devin/skills/rite-explain/SKILL.md +1 -1
  378. package/pack/generated/devin/skills/rite-explain/reference/intake.md +1 -1
  379. package/pack/generated/devin/skills/rite-fast/SKILL.md +1 -1
  380. package/pack/generated/devin/skills/rite-plan/SKILL.md +4 -3
  381. package/pack/generated/devin/skills/rite-plan/reference/replan-and-repair.md +4 -4
  382. package/pack/generated/devin/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  383. package/pack/generated/devin/skills/rite-prove/reference/browser-proof.md +5 -5
  384. package/pack/generated/devin/skills/rite-resolve/SKILL.md +3 -3
  385. package/pack/generated/devin/skills/rite-seal/SKILL.md +4 -3
  386. package/pack/generated/devin/skills/rite-seal/reference/phase-contract.md +3 -2
  387. package/pack/generated/devin/skills/rite-seal/reference/seal-template.md +2 -0
  388. package/pack/generated/devin/skills/rite-ship/SKILL.md +4 -2
  389. package/pack/generated/devin/skills/rite-ship/reference/git-ship.md +8 -2
  390. package/pack/generated/devin/skills/rite-ship/reference/ship-template.md +2 -1
  391. package/pack/generated/devin/skills/rite-spec/SKILL.md +2 -2
  392. package/pack/generated/devin/skills/rite-spec/reference/spec-checklists.md +1 -1
  393. package/pack/generated/devin/skills/rite-spec/reference/spec-template.md +7 -3
  394. package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +2 -0
  395. package/pack/generated/devin/skills/rite-temper/SKILL.md +12 -9
  396. package/pack/generated/devin/skills/rite-temper/reference/scope-modes.md +1 -1
  397. package/pack/generated/devin/skills/rite-temper/reference/significance.md +10 -3
  398. package/pack/generated/devin/skills/rite-temper/reference/strategy-template.md +13 -2
  399. package/pack/generated/devin/skills/rite-vet/SKILL.md +4 -3
  400. package/pack/generated/devin/skills/rite-vet/reference/artifacts.md +1 -1
  401. package/pack/generated/omp/agents/devrites-spec-reviewer.md +2 -2
  402. package/pack/generated/omp/commands/rite-define.md +1 -1
  403. package/pack/generated/omp/commands/rite-handoff.md +1 -1
  404. package/pack/generated/omp/commands/rite-plan.md +1 -1
  405. package/pack/generated/omp/commands/rite-pressure-test.md +1 -1
  406. package/pack/generated/omp/commands/rite-quick.md +1 -1
  407. package/pack/generated/omp/commands/rite-status.md +1 -1
  408. package/pack/generated/omp/commands/rite-temper.md +1 -1
  409. package/pack/generated/omp/commands/rite-zoom-out.md +1 -1
  410. package/pack/generated/omp/skills/devrites-browser-proof/SKILL.md +2 -2
  411. package/pack/generated/omp/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  412. package/pack/generated/omp/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  413. package/pack/generated/omp/skills/devrites-interview/SKILL.md +4 -4
  414. package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  415. package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  416. package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +3 -2
  417. package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +6 -5
  418. package/pack/generated/omp/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  419. package/pack/generated/omp/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  420. package/pack/generated/omp/skills/devrites-lib/reference/standards/windows.md +3 -3
  421. package/pack/generated/omp/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  422. package/pack/generated/omp/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  423. package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  424. package/pack/generated/omp/skills/devrites-ux-shape/SKILL.md +11 -12
  425. package/pack/generated/omp/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  426. package/pack/generated/omp/skills/overhaul/SKILL.md +1 -1
  427. package/pack/generated/omp/skills/overhaul/references/orchestration.md +5 -3
  428. package/pack/generated/omp/skills/overhaul/references/records.md +39 -0
  429. package/pack/generated/omp/skills/overhaul/references/scoring.md +14 -4
  430. package/pack/generated/omp/skills/rite/reference/menu.md +1 -1
  431. package/pack/generated/omp/skills/rite-adopt/SKILL.md +8 -2
  432. package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +11 -6
  433. package/pack/generated/omp/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  434. package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +1 -1
  435. package/pack/generated/omp/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  436. package/pack/generated/omp/skills/rite-build/SKILL.md +2 -1
  437. package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +1 -1
  438. package/pack/generated/omp/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  439. package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +5 -0
  440. package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +2 -2
  441. package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +3 -2
  442. package/pack/generated/omp/skills/rite-clarify/SKILL.md +5 -4
  443. package/pack/generated/omp/skills/rite-clarify/reference/anti-patterns.md +2 -2
  444. package/pack/generated/omp/skills/rite-clarify/reference/decision-coverage.md +3 -2
  445. package/pack/generated/omp/skills/rite-converge/SKILL.md +2 -0
  446. package/pack/generated/omp/skills/rite-customize/SKILL.md +6 -4
  447. package/pack/generated/omp/skills/rite-define/SKILL.md +2 -0
  448. package/pack/generated/omp/skills/rite-define/reference/gates.md +8 -7
  449. package/pack/generated/omp/skills/rite-explain/SKILL.md +1 -1
  450. package/pack/generated/omp/skills/rite-explain/reference/intake.md +1 -1
  451. package/pack/generated/omp/skills/rite-fast/SKILL.md +1 -1
  452. package/pack/generated/omp/skills/rite-plan/SKILL.md +4 -3
  453. package/pack/generated/omp/skills/rite-plan/reference/replan-and-repair.md +4 -4
  454. package/pack/generated/omp/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  455. package/pack/generated/omp/skills/rite-prove/reference/browser-proof.md +5 -5
  456. package/pack/generated/omp/skills/rite-resolve/SKILL.md +3 -3
  457. package/pack/generated/omp/skills/rite-seal/SKILL.md +4 -3
  458. package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +3 -2
  459. package/pack/generated/omp/skills/rite-seal/reference/seal-template.md +2 -0
  460. package/pack/generated/omp/skills/rite-ship/SKILL.md +4 -2
  461. package/pack/generated/omp/skills/rite-ship/reference/git-ship.md +8 -2
  462. package/pack/generated/omp/skills/rite-ship/reference/ship-template.md +2 -1
  463. package/pack/generated/omp/skills/rite-spec/SKILL.md +2 -2
  464. package/pack/generated/omp/skills/rite-spec/reference/spec-checklists.md +1 -1
  465. package/pack/generated/omp/skills/rite-spec/reference/spec-template.md +7 -3
  466. package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +2 -0
  467. package/pack/generated/omp/skills/rite-temper/SKILL.md +12 -9
  468. package/pack/generated/omp/skills/rite-temper/reference/scope-modes.md +1 -1
  469. package/pack/generated/omp/skills/rite-temper/reference/significance.md +10 -3
  470. package/pack/generated/omp/skills/rite-temper/reference/strategy-template.md +13 -2
  471. package/pack/generated/omp/skills/rite-vet/SKILL.md +4 -3
  472. package/pack/generated/omp/skills/rite-vet/reference/artifacts.md +1 -1
  473. package/pack/generated/pi/AGENTS.md +1 -1
  474. package/pack/generated/pi/agents/devrites-spec-reviewer.md +2 -2
  475. package/pack/generated/pi/prompts/rite-define.md +1 -1
  476. package/pack/generated/pi/prompts/rite-handoff.md +1 -1
  477. package/pack/generated/pi/prompts/rite-plan.md +1 -1
  478. package/pack/generated/pi/prompts/rite-pressure-test.md +1 -1
  479. package/pack/generated/pi/prompts/rite-quick.md +1 -1
  480. package/pack/generated/pi/prompts/rite-status.md +1 -1
  481. package/pack/generated/pi/prompts/rite-temper.md +1 -1
  482. package/pack/generated/pi/prompts/rite-zoom-out.md +1 -1
  483. package/pack/generated/pi/skills/devrites-browser-proof/SKILL.md +2 -2
  484. package/pack/generated/pi/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  485. package/pack/generated/pi/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  486. package/pack/generated/pi/skills/devrites-interview/SKILL.md +4 -4
  487. package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  488. package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  489. package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +3 -2
  490. package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +6 -5
  491. package/pack/generated/pi/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  492. package/pack/generated/pi/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  493. package/pack/generated/pi/skills/devrites-lib/reference/standards/windows.md +3 -3
  494. package/pack/generated/pi/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  495. package/pack/generated/pi/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  496. package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  497. package/pack/generated/pi/skills/devrites-ux-shape/SKILL.md +11 -12
  498. package/pack/generated/pi/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  499. package/pack/generated/pi/skills/overhaul/SKILL.md +1 -1
  500. package/pack/generated/pi/skills/overhaul/references/orchestration.md +5 -3
  501. package/pack/generated/pi/skills/overhaul/references/records.md +39 -0
  502. package/pack/generated/pi/skills/overhaul/references/scoring.md +14 -4
  503. package/pack/generated/pi/skills/rite/reference/menu.md +1 -1
  504. package/pack/generated/pi/skills/rite-adopt/SKILL.md +8 -2
  505. package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +11 -6
  506. package/pack/generated/pi/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  507. package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +1 -1
  508. package/pack/generated/pi/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  509. package/pack/generated/pi/skills/rite-build/SKILL.md +2 -1
  510. package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +1 -1
  511. package/pack/generated/pi/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  512. package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +5 -0
  513. package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +2 -2
  514. package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +3 -2
  515. package/pack/generated/pi/skills/rite-clarify/SKILL.md +5 -4
  516. package/pack/generated/pi/skills/rite-clarify/reference/anti-patterns.md +2 -2
  517. package/pack/generated/pi/skills/rite-clarify/reference/decision-coverage.md +3 -2
  518. package/pack/generated/pi/skills/rite-converge/SKILL.md +2 -0
  519. package/pack/generated/pi/skills/rite-customize/SKILL.md +6 -4
  520. package/pack/generated/pi/skills/rite-define/SKILL.md +2 -0
  521. package/pack/generated/pi/skills/rite-define/reference/gates.md +8 -7
  522. package/pack/generated/pi/skills/rite-explain/SKILL.md +1 -1
  523. package/pack/generated/pi/skills/rite-explain/reference/intake.md +1 -1
  524. package/pack/generated/pi/skills/rite-fast/SKILL.md +1 -1
  525. package/pack/generated/pi/skills/rite-plan/SKILL.md +4 -3
  526. package/pack/generated/pi/skills/rite-plan/reference/replan-and-repair.md +4 -4
  527. package/pack/generated/pi/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  528. package/pack/generated/pi/skills/rite-prove/reference/browser-proof.md +5 -5
  529. package/pack/generated/pi/skills/rite-resolve/SKILL.md +3 -3
  530. package/pack/generated/pi/skills/rite-seal/SKILL.md +4 -3
  531. package/pack/generated/pi/skills/rite-seal/reference/phase-contract.md +3 -2
  532. package/pack/generated/pi/skills/rite-seal/reference/seal-template.md +2 -0
  533. package/pack/generated/pi/skills/rite-ship/SKILL.md +4 -2
  534. package/pack/generated/pi/skills/rite-ship/reference/git-ship.md +8 -2
  535. package/pack/generated/pi/skills/rite-ship/reference/ship-template.md +2 -1
  536. package/pack/generated/pi/skills/rite-spec/SKILL.md +2 -2
  537. package/pack/generated/pi/skills/rite-spec/reference/spec-checklists.md +1 -1
  538. package/pack/generated/pi/skills/rite-spec/reference/spec-template.md +7 -3
  539. package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +2 -0
  540. package/pack/generated/pi/skills/rite-temper/SKILL.md +12 -9
  541. package/pack/generated/pi/skills/rite-temper/reference/scope-modes.md +1 -1
  542. package/pack/generated/pi/skills/rite-temper/reference/significance.md +10 -3
  543. package/pack/generated/pi/skills/rite-temper/reference/strategy-template.md +13 -2
  544. package/pack/generated/pi/skills/rite-vet/SKILL.md +4 -3
  545. package/pack/generated/pi/skills/rite-vet/reference/artifacts.md +1 -1
  546. package/package.json +5 -4
  547. package/scripts/build-host-artifacts.sh +15 -0
  548. package/scripts/codex-generate.sh +1 -1
  549. package/scripts/devin-generate.sh +1 -1
  550. package/scripts/expand-includes.py +46 -0
  551. package/scripts/install-lib.sh +42 -7
  552. package/scripts/omp-generate.sh +11 -0
  553. package/scripts/pi-generate.sh +12 -1
  554. package/update.sh +1 -2
  555. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/README.md +0 -7
  556. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/architecture.md +0 -3
  557. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/assumptions.md +0 -3
  558. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/brief.md +0 -3
  559. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decision-coverage.md +0 -3
  560. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decisions.md +0 -4
  561. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/eng-review.md +0 -3
  562. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/gates.md +0 -4
  563. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/plan.md +0 -5
  564. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/questions.md +0 -3
  565. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/spec.md +0 -6
  566. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/state.md +0 -8
  567. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/tasks.md +0 -1
  568. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/test-plan.md +0 -3
  569. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/traceability.md +0 -3
  570. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/README.md +0 -7
  571. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/assumptions.md +0 -3
  572. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/brief.md +0 -3
  573. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/decisions.md +0 -3
  574. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/questions.md +0 -3
  575. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/spec.md +0 -6
  576. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/state.md +0 -3
  577. package/engine/testdata/golden/TestParityCloseOut/active_pointed_elsewhere.golden +0 -2
  578. package/engine/testdata/golden/TestParityCloseOut/active_slug_cleared.golden +0 -2
  579. package/engine/testdata/golden/TestParityCloseOut/archive_clobber.golden +0 -1
  580. package/engine/testdata/golden/TestParityCloseOut/missing_slug.golden +0 -1
  581. package/engine/testdata/golden/TestParityCloseOut/missing_workspace.golden +0 -1
  582. package/engine/testdata/golden/TestParityLearnings/add.golden +0 -2
  583. package/engine/testdata/golden/TestParityLearnings/list.golden +0 -5
  584. package/engine/testdata/golden/TestParityLearnings/mine-no-archive.golden +0 -2
  585. package/engine/testdata/golden/TestParityLearnings/mine.golden +0 -5
  586. package/engine/testdata/golden/TestParityLearnings/nudge.golden +0 -2
  587. package/engine/testdata/golden/TestParityLearnings/unknown.golden +0 -1
  588. package/engine/testdata/golden/TestParityPackageExistence/ghost-workspace.golden +0 -1
  589. package/engine/testdata/golden/TestParityPackageExistence/no-manifest.golden +0 -1
  590. package/engine/testdata/golden/TestParityPackageExistence/not-git.golden +0 -1
  591. package/engine/testdata/golden/TestParityPackageExistence/undeclared.golden +0 -1
  592. package/engine/testdata/golden/TestParityPreamble/afk/a.golden +0 -14
  593. package/engine/testdata/golden/TestParityPreamble/hitl/active.golden +0 -18
  594. package/engine/testdata/golden/TestParityPreamble/hitl/bare.golden +0 -10
  595. package/engine/testdata/golden/TestParityPreamble/hitl/full.golden +0 -18
  596. package/engine/testdata/golden/TestParityPreamble/hitl/ghost.golden +0 -2
  597. package/engine/testdata/golden/TestParityPreamble/hitl/nonl.golden +0 -11
  598. package/engine/testdata/golden/TestParityPreamble/hitl/openend.golden +0 -13
  599. package/engine/testdata/golden/TestParityProgress/arg=allbuilt.golden +0 -4
  600. package/engine/testdata/golden/TestParityProgress/arg=done.golden +0 -3
  601. package/engine/testdata/golden/TestParityProgress/arg=ghost.golden +0 -1
  602. package/engine/testdata/golden/TestParityProgress/arg=mid.golden +0 -4
  603. package/engine/testdata/golden/TestParityProgress/arg=nophase.golden +0 -3
  604. package/engine/testdata/golden/TestParityProgress/arg=noslice.golden +0 -3
  605. package/engine/testdata/golden/TestParityProgress/arg=plan.golden +0 -4
  606. package/engine/testdata/golden/TestParityProgress/arg=seal.golden +0 -3
  607. package/engine/testdata/golden/TestParityResolve/answer/questions.md.golden +0 -9
  608. package/engine/testdata/golden/TestParityResolve/answer/state.md.golden +0 -7
  609. package/engine/testdata/golden/TestParityResolve/answer.golden +0 -4
  610. package/engine/testdata/golden/TestParityResolve/batch/questions.md.golden +0 -9
  611. package/engine/testdata/golden/TestParityResolve/batch-unterminated/questions.md.golden +0 -9
  612. package/engine/testdata/golden/TestParityResolve/batch-unterminated.golden +0 -2
  613. package/engine/testdata/golden/TestParityResolve/batch.golden +0 -3
  614. package/engine/testdata/golden/TestParityResolve/drop/questions.md.golden +0 -9
  615. package/engine/testdata/golden/TestParityResolve/drop/state.md.golden +0 -9
  616. package/engine/testdata/golden/TestParityResolve/drop.golden +0 -4
  617. package/engine/testdata/golden/TestParityResolve/missing-answer.golden +0 -1
  618. package/engine/testdata/golden/TestParityResolve/no-workspace.golden +0 -1
  619. package/engine/testdata/golden/TestParityResolve/not-found.golden +0 -1
  620. package/engine/testdata/golden/TestParityResolve/not-open.golden +0 -1
  621. package/engine/testdata/golden/TestStatusLiveWorkspace.golden +0 -10
  622. package/engine/testdata/golden/status/auth-tokens.txt +0 -9
  623. package/engine/testdata/golden/status/search-ranking.txt +0 -9
  624. package/engine/testdata/visual/open-visual-smoke.html +0 -675
  625. package/engine/testdata/visual/open-visual-smoke.outline.md +0 -54
  626. package/engine/tests/adr_0003_gate_exit_code_test.go +0 -32
  627. package/engine/tests/adr_0004_required_by_phase_test.go +0 -54
  628. package/engine/tests/adr_0011_define_plan_test.go +0 -32
  629. package/engine/tests/adr_0027_readiness_binding_test.go +0 -107
  630. package/engine/tests/cli_test.go +0 -126
  631. package/engine/tests/gate_test.go +0 -669
  632. package/engine/tests/meta_test.go +0 -37
  633. package/engine/tests/parity_closeout_test.go +0 -105
  634. package/engine/tests/parity_githelpers_test.go +0 -41
  635. package/engine/tests/parity_resolve_test.go +0 -136
  636. package/engine/tests/parity_test.go +0 -86
  637. package/engine/tests/workspace_observation_migration_test.go +0 -1069
@@ -2,8 +2,11 @@ package lib
2
2
 
3
3
  import (
4
4
  "bytes"
5
+
6
+ "encoding/json"
5
7
  "os"
6
8
  "path/filepath"
9
+ "runtime"
7
10
  "strings"
8
11
  "testing"
9
12
 
@@ -140,3 +143,254 @@ func TestObserveSummaryReportsSequenceCursor(t *testing.T) {
140
143
  t.Fatalf("sequence must be absent without cursor fields: %+v", summary.Sequence)
141
144
  }
142
145
  }
146
+
147
+ // summaryUnreadable decodes the emitted summary JSON and fails when the consumer has
148
+ // no way to tell an omitted section from an empty one.
149
+ func summaryUnreadable(t *testing.T, out []byte) []string {
150
+ t.Helper()
151
+ var doc map[string]json.RawMessage
152
+ if err := json.Unmarshal(out, &doc); err != nil {
153
+ t.Fatalf("summary is not a JSON object: %v (%s)", err, out)
154
+ }
155
+ raw, ok := doc["unreadable"]
156
+ if !ok {
157
+ t.Fatalf("summary carries no \"unreadable\" key, so an artifact that could not be read is indistinguishable from one that does not exist: %s", out)
158
+ }
159
+ var names []string
160
+ if err := json.Unmarshal(raw, &names); err != nil {
161
+ t.Fatalf("unreadable is not a list of artifact names: %v (%s)", err, raw)
162
+ }
163
+ return names
164
+ }
165
+
166
+ func summaryFiles(t *testing.T, out []byte, key string) []string {
167
+ t.Helper()
168
+ var doc map[string]json.RawMessage
169
+ if err := json.Unmarshal(out, &doc); err != nil {
170
+ t.Fatalf("summary is not a JSON object: %v (%s)", err, out)
171
+ }
172
+ var rows []struct {
173
+ File string `json:"file"`
174
+ }
175
+ raw, ok := doc[key]
176
+ if !ok {
177
+ t.Fatalf("summary key %q is absent entirely: %s", key, out)
178
+ }
179
+ if err := json.Unmarshal(raw, &rows); err != nil {
180
+ t.Fatalf("%s is not a list: %v (%s)", key, err, raw)
181
+ }
182
+ names := make([]string, 0, len(rows))
183
+ for _, row := range rows {
184
+ names = append(names, row.File)
185
+ }
186
+ return names
187
+ }
188
+
189
+ // One canonical artifact that exists but cannot be read must not take the
190
+ // task graph, the artifact budgets and the bulk-file list down with it.
191
+ func TestObserveSummaryNamesUnreadableArtifactAndKeepsReadableBudgets(t *testing.T) {
192
+ if os.Geteuid() == 0 || runtime.GOOS == "windows" {
193
+ t.Skip("file permissions do not bind root or windows")
194
+ }
195
+ root, workspace := writeBudgetWorkspace(t, map[string]string{
196
+ "state.md": "| phase | build |\n| schema | 4 |\n",
197
+ "tasks.md": budgetTasks,
198
+ "vet-review-input-1.json": strings.Repeat("{}", 40_000),
199
+ })
200
+ // spec.md is canonical and sorts first; the entries behind it must survive.
201
+ spec := filepath.Join(workspace, "spec.md")
202
+ if err := os.WriteFile(spec, []byte("# Spec\n"), 0o000); err != nil {
203
+ t.Fatal(err)
204
+ }
205
+ if err := os.Chmod(spec, 0o000); err != nil {
206
+ t.Fatal(err)
207
+ }
208
+ t.Cleanup(func() { _ = os.Chmod(spec, 0o644) })
209
+
210
+ var out, errOut bytes.Buffer
211
+ if code := RunObserveSummary(root, "feature", &out, &errOut); code != 0 {
212
+ t.Fatalf("exit=%d stderr=%s", code, errOut.String())
213
+ }
214
+ names := summaryUnreadable(t, out.Bytes())
215
+ if len(names) != 1 || names[0] != "spec.md" {
216
+ t.Fatalf("unreadable=%v, want exactly [spec.md]", names)
217
+ }
218
+ budgets := summaryFiles(t, out.Bytes(), "artifact_budgets")
219
+ for _, want := range []string{"state.md", "tasks.md"} {
220
+ found := false
221
+ for _, got := range budgets {
222
+ if got == want {
223
+ found = true
224
+ }
225
+ }
226
+ if !found {
227
+ t.Fatalf("artifact_budgets=%v lost %q to the unreadable spec.md: %s", budgets, want, out.String())
228
+ }
229
+ }
230
+ bulk := summaryFiles(t, out.Bytes(), "bulk_files")
231
+ if len(bulk) != 1 || bulk[0] != "vet-review-input-1.json" {
232
+ t.Fatalf("bulk_files=%v lost the readable 80 KiB file to the unreadable spec.md: %s", bulk, out.String())
233
+ }
234
+ }
235
+
236
+ // A tasks.md that is not a readable regular file must be named, not dropped.
237
+ func TestObserveSummaryNamesUnreadableTasksInsteadOfOmittingTaskGraph(t *testing.T) {
238
+ root, workspace := writeBudgetWorkspace(t, map[string]string{
239
+ "state.md": "| phase | build |\n| schema | 4 |\n",
240
+ "tasks.md": budgetTasks,
241
+ })
242
+ if err := os.Remove(filepath.Join(workspace, "tasks.md")); err != nil {
243
+ t.Fatal(err)
244
+ }
245
+ if err := os.Mkdir(filepath.Join(workspace, "tasks.md"), 0o755); err != nil {
246
+ t.Fatal(err)
247
+ }
248
+
249
+ var out, errOut bytes.Buffer
250
+ if code := RunObserveSummary(root, "feature", &out, &errOut); code != 0 {
251
+ t.Fatalf("exit=%d stderr=%s", code, errOut.String())
252
+ }
253
+ names := summaryUnreadable(t, out.Bytes())
254
+ if len(names) != 1 || names[0] != "tasks.md" {
255
+ t.Fatalf("unreadable=%v, want exactly [tasks.md]", names)
256
+ }
257
+ if _, ok := map[string]json.RawMessage(mustDecode(t, out.Bytes()))["task_graph"]; ok {
258
+ t.Fatalf("task_graph must stay absent when tasks.md cannot be read: %s", out.String())
259
+ }
260
+ if budgets := summaryFiles(t, out.Bytes(), "artifact_budgets"); len(budgets) != 1 || budgets[0] != "state.md" {
261
+ t.Fatalf("artifact_budgets=%v, want [state.md]", budgets)
262
+ }
263
+ }
264
+
265
+ func mustDecode(t *testing.T, out []byte) map[string]json.RawMessage {
266
+ t.Helper()
267
+ var doc map[string]json.RawMessage
268
+ if err := json.Unmarshal(out, &doc); err != nil {
269
+ t.Fatalf("summary is not a JSON object: %v (%s)", err, out)
270
+ }
271
+ return doc
272
+ }
273
+
274
+ // A workspace that has not reached define has no tasks.md; that is absence, not a read failure.
275
+ func TestObserveSummaryOmitsUnreadableWhenTasksAbsent(t *testing.T) {
276
+ root, _ := writeBudgetWorkspace(t, map[string]string{
277
+ "state.md": "| phase | spec |\n| schema | 4 |\n",
278
+ })
279
+ var out, errOut bytes.Buffer
280
+ if code := RunObserveSummary(root, "feature", &out, &errOut); code != 0 {
281
+ t.Fatalf("exit=%d stderr=%s", code, errOut.String())
282
+ }
283
+ if _, ok := mustDecode(t, out.Bytes())["unreadable"]; ok {
284
+ t.Fatalf("a missing tasks.md must not be reported as unreadable: %s", out.String())
285
+ }
286
+ }
287
+
288
+ // A tasks.md that fails both the task-graph read and the budget read is named once.
289
+ func TestObserveSummaryNamesUnreadableTasksOnce(t *testing.T) {
290
+ if os.Geteuid() == 0 || runtime.GOOS == "windows" {
291
+ t.Skip("file permissions do not bind root or windows")
292
+ }
293
+ root, workspace := writeBudgetWorkspace(t, map[string]string{
294
+ "state.md": "| phase | build |\n| schema | 4 |\n",
295
+ "tasks.md": budgetTasks,
296
+ })
297
+ tasks := filepath.Join(workspace, "tasks.md")
298
+ if err := os.Chmod(tasks, 0o000); err != nil {
299
+ t.Fatal(err)
300
+ }
301
+ t.Cleanup(func() { _ = os.Chmod(tasks, 0o644) })
302
+
303
+ var out, errOut bytes.Buffer
304
+ if code := RunObserveSummary(root, "feature", &out, &errOut); code != 0 {
305
+ t.Fatalf("exit=%d stderr=%s", code, errOut.String())
306
+ }
307
+ if names := summaryUnreadable(t, out.Bytes()); len(names) != 1 || names[0] != "tasks.md" {
308
+ t.Fatalf("unreadable=%v, want exactly [tasks.md]", names)
309
+ }
310
+ }
311
+
312
+ const (
313
+ artifactSchemaDocPath = "../../../pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md"
314
+ outlineTemplateDocPath = "../../../pack/.claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md"
315
+ )
316
+
317
+ // Every artifact the schema's Budget column names must either be measured by the
318
+ // engine or say in its Budget cell that the budget is advisory.
319
+ func TestSchemaBudgetRowsAreEnforcedOrMarkedAdvisory(t *testing.T) {
320
+ raw, err := os.ReadFile(artifactSchemaDocPath)
321
+ if err != nil {
322
+ t.Fatal(err)
323
+ }
324
+ rows := 0
325
+ for _, line := range strings.Split(string(raw), "\n") {
326
+ cells := strings.Split(line, "|")
327
+ if len(cells) != 5 || !strings.Contains(cells[3], "lines") {
328
+ continue
329
+ }
330
+ first, budget := strings.TrimSpace(cells[1]), cells[3]
331
+ if !strings.HasPrefix(first, "`") || !strings.HasSuffix(first, "`") {
332
+ continue
333
+ }
334
+ rows++
335
+ name := strings.Trim(first, "`")
336
+ if _, canonical := state.ArtifactLineBudget(name); canonical {
337
+ continue
338
+ }
339
+ if !strings.Contains(strings.ToLower(budget), "advisory") {
340
+ t.Errorf("%s has a budget %q but is neither in state.artifactLineBudgets nor marked advisory", name, strings.TrimSpace(budget))
341
+ }
342
+ }
343
+ if rows < 30 {
344
+ t.Fatalf("parsed %d budget rows from the schema table, want at least 30", rows)
345
+ }
346
+ }
347
+
348
+ func TestOutlineTemplateBudgetIsMarkedAdvisory(t *testing.T) {
349
+ raw, err := os.ReadFile(outlineTemplateDocPath)
350
+ if err != nil {
351
+ t.Fatal(err)
352
+ }
353
+ for _, line := range strings.Split(string(raw), "\n") {
354
+ if strings.HasPrefix(line, "- Budget:") {
355
+ if !strings.Contains(strings.ToLower(line), "advisory") {
356
+ t.Fatalf("outline budget line %q does not say the budget is advisory", line)
357
+ }
358
+ return
359
+ }
360
+ }
361
+ t.Fatal("outline template has no \"- Budget:\" line")
362
+ }
363
+
364
+ // A canonical artifact larger than the read cap is reported over budget from its
365
+ // size alone, without being read whole.
366
+ func TestObserveArtifactBudgetsOversizedArtifactIsOverWithoutFullRead(t *testing.T) {
367
+ const size = 32 << 20
368
+ _, workspace := writeBudgetWorkspace(t, map[string]string{"state.md": "| phase | build |\n"})
369
+ file, err := os.OpenFile(filepath.Join(workspace, "state.md"), os.O_WRONLY, 0o644)
370
+ if err != nil {
371
+ t.Fatal(err)
372
+ }
373
+ if err := file.Truncate(size); err != nil {
374
+ t.Fatal(err)
375
+ }
376
+ if err := file.Close(); err != nil {
377
+ t.Fatal(err)
378
+ }
379
+
380
+ var before, after runtime.MemStats
381
+ runtime.ReadMemStats(&before)
382
+ budgets, _, unreadable, err := observeArtifactBudgets(workspace)
383
+ runtime.ReadMemStats(&after)
384
+ if err != nil {
385
+ t.Fatal(err)
386
+ }
387
+ if len(unreadable) != 0 {
388
+ t.Fatalf("unreadable=%v, an oversized artifact is over budget, not unreadable", unreadable)
389
+ }
390
+ if len(budgets) != 1 || !budgets[0].Over || budgets[0].Bytes != size {
391
+ t.Fatalf("budgets=%+v, want state.md over budget with Bytes=%d", budgets, size)
392
+ }
393
+ if allocated := after.TotalAlloc - before.TotalAlloc; allocated > size/4 {
394
+ t.Fatalf("allocated %d bytes for a %d byte artifact; the read must be bounded", allocated, size)
395
+ }
396
+ }
@@ -2,8 +2,12 @@ package lib
2
2
 
3
3
  import (
4
4
  "encoding/json"
5
+ "errors"
5
6
  "fmt"
6
7
  "io"
8
+ "io/fs"
9
+ "path/filepath"
10
+ "slices"
7
11
 
8
12
  "github.com/devrites/devrites/internal/devritespaths"
9
13
  "github.com/devrites/devrites/internal/state"
@@ -41,6 +45,7 @@ type ObserveSummary struct {
41
45
  NextAction string `json:"next_action,omitempty"`
42
46
  MissingSections []string `json:"missing_sections,omitempty"`
43
47
  MissingFiles []string `json:"missing_files,omitempty"`
48
+ Unreadable []string `json:"unreadable,omitempty"`
44
49
  PrinciplesPresent bool `json:"principles_present"`
45
50
  TaskGraph *ObserveTaskGraph `json:"task_graph,omitempty"`
46
51
  ArtifactBudgets []ArtifactBudget `json:"artifact_budgets,omitempty"`
@@ -64,7 +69,13 @@ func ObserveSummaryFor(root, slug string) (ObserveSummary, error) {
64
69
  MissingSections: missingSectionNames(report.Missing),
65
70
  }
66
71
 
67
- if graph, graphErr := CheckTaskGraph(root, slug); graphErr == nil && (len(graph.Slices) > 0 || len(graph.Problems) > 0) {
72
+ graph, graphErr := CheckTaskGraph(root, slug)
73
+ switch {
74
+ case errors.Is(graphErr, fs.ErrNotExist):
75
+ // tasks.md is created at define; before that its absence is expected.
76
+ case graphErr != nil:
77
+ summary.Unreadable = append(summary.Unreadable, "tasks.md")
78
+ case len(graph.Slices) > 0 || len(graph.Problems) > 0:
68
79
  slices := make([]ObserveSlice, 0, len(graph.Slices))
69
80
  for _, slice := range graph.Slices {
70
81
  deps := make([]string, 0, len(slice.Dependencies))
@@ -89,9 +100,19 @@ func ObserveSummaryFor(root, slug string) (ObserveSummary, error) {
89
100
  }
90
101
  }
91
102
  if workspace, wsErr := devritespaths.ExistingFeatureDirChecked(root, slug); wsErr == nil {
92
- if budgets, bulk, budgetErr := observeArtifactBudgets(workspace); budgetErr == nil {
103
+ budgets, bulk, unreadable, budgetErr := observeArtifactBudgets(workspace)
104
+ if budgetErr == nil {
93
105
  summary.ArtifactBudgets = budgets
94
106
  summary.BulkFiles = bulk
107
+ for _, name := range unreadable {
108
+ if !slices.Contains(summary.Unreadable, name) {
109
+ summary.Unreadable = append(summary.Unreadable, name)
110
+ }
111
+ }
112
+ } else {
113
+ // The directory itself is unreadable, so no entry name is available; report
114
+ // the loss under the workspace rather than emitting a shorter summary.
115
+ summary.Unreadable = append(summary.Unreadable, filepath.Base(workspace))
95
116
  }
96
117
  }
97
118
  return summary, nil
@@ -1,8 +1,10 @@
1
1
  package lib
2
2
 
3
3
  import (
4
+ "errors"
4
5
  "fmt"
5
6
  "io"
7
+ "io/fs"
6
8
  "os"
7
9
  "os/exec"
8
10
  "path/filepath"
@@ -227,8 +229,8 @@ func resolveOpenVisualFeatureDir(root, slug string) (string, error) {
227
229
  }
228
230
  dir, err := devritespaths.ExistingFeatureDirChecked(root, slug)
229
231
  if err != nil {
230
- if os.IsNotExist(err) {
231
- retErr := fmt.Errorf("no workspace for slug %q", slug)
232
+ if errors.Is(err, fs.ErrNotExist) {
233
+ retErr := fmt.Errorf("no workspace for slug %q at %s", slug, filepath.Join(root, "work", slug))
232
234
  return "", retErr
233
235
  }
234
236
  return "", err
@@ -278,3 +278,14 @@ func swapOpenVisualOpener(fn func(string) error) func() {
278
278
  openVisualOpener = fn
279
279
  return func() { openVisualOpener = prev }
280
280
  }
281
+
282
+ func TestOpenVisualMissingWorkspaceNamesResolvedPath(t *testing.T) {
283
+ root := t.TempDir()
284
+ var stdout, stderr bytes.Buffer
285
+
286
+ code := OpenVisual(root, []string{"demo", "--slug", "ghost"}, &stdout, &stderr)
287
+ want := filepath.Join(root, "work", "ghost")
288
+ if code != 2 || !strings.Contains(stderr.String(), `"ghost"`) || !strings.Contains(stderr.String(), want) {
289
+ t.Fatalf("open-visual missing workspace = %d, want exit 2 naming %q\n%s", code, want, stderr.String())
290
+ }
291
+ }
@@ -26,6 +26,9 @@ import (
26
26
  //
27
27
  // devrites-engine check regression <slug> compare vs baseline
28
28
  // devrites-engine check regression <slug> --update ratchet baseline to now
29
+ // devrites-engine check regression <slug> --update --allow-empty
30
+ // ratchet even when every
31
+ // acceptance fact is gone
29
32
  //
30
33
  // 0 clean / no baseline yet
31
34
  // 2 usage error or workspace unreadable
@@ -75,18 +78,18 @@ type regressionBaseline struct {
75
78
  // RunCheckRegression compares the workspace against its recorded progress
76
79
  // baseline, or ratchets that baseline forward with --update.
77
80
  func RunCheckRegression(root string, args []string, stdout, stderr io.Writer) int {
78
- if len(args) < 1 || len(args) > 2 {
81
+ if len(args) < 1 || len(args) > 3 {
79
82
  fmt.Fprintln(stderr, regressionUsage)
80
83
  return 2
81
84
  }
82
85
  slug := args[0]
83
- update := false
84
- if len(args) == 2 {
85
- if args[1] != "--update" {
86
+ update, allowEmpty := false, false
87
+ if len(args) >= 2 {
88
+ if args[1] != "--update" || (len(args) == 3 && args[2] != "--allow-empty") {
86
89
  fmt.Fprintln(stderr, regressionUsage)
87
90
  return 2
88
91
  }
89
- update = true
92
+ update, allowEmpty = true, len(args) == 3
90
93
  }
91
94
  workspace, err := devritespaths.ExistingFeatureDirChecked(root, slug)
92
95
  if err != nil {
@@ -120,24 +123,41 @@ func RunCheckRegression(root string, args []string, stdout, stderr io.Writer) in
120
123
  fmt.Fprintf(stdout, "check regression: BLOCKED: %d regression(s) vs baseline %s\n", len(regressions), baseline.UpdatedAt)
121
124
  return 3
122
125
  }
123
- return updateRegressionBaseline(root, slug, baselinePath, baseline, hasBaseline, current, stdout, stderr)
126
+ return updateRegressionBaseline(root, slug, baselinePath, baseline, hasBaseline, current, allowEmpty, stdout, stderr)
124
127
  }
125
128
 
126
- // fingerprintWorkspace computes the current structural progress facts.
129
+ // fingerprintWorkspace computes the current structural progress facts. A
130
+ // non-nil error names every artifact that existed but could not be read or
131
+ // parsed; the returned fingerprint is then incomplete.
127
132
  func fingerprintWorkspace(root, slug, workspace string) (progressFingerprint, error) {
128
133
  fp := progressFingerprint{PhaseOrdinal: -1}
129
134
 
130
- if report, err := state.Status(root, slug); err == nil && report != nil {
131
- fp.Phase = string(report.Phase)
132
- for i, policy := range state.PhasePolicies() {
133
- if policy.Target == report.Phase {
134
- fp.PhaseOrdinal = i
135
- break
136
- }
135
+ // An unobservable phase would disable the phase-regression comparison, so
136
+ // it blocks instead of yielding PhaseOrdinal -1.
137
+ report, err := state.Status(root, slug)
138
+ if err != nil {
139
+ return fp, fmt.Errorf("phase unreadable, refusing to treat as progress facts: %w", err)
140
+ }
141
+ fp.Phase = string(report.Phase)
142
+ for i, policy := range state.PhasePolicies() {
143
+ if policy.Target == report.Phase {
144
+ fp.PhaseOrdinal = i
145
+ break
146
+ }
147
+ }
148
+
149
+ // A missing artifact is a legitimate early-phase state; an unreadable or
150
+ // unparsable one would silently yield an empty fact set, so it is named.
151
+ var degraded []string
152
+ note := func(name string, err error) {
153
+ if err != nil && !os.IsNotExist(err) {
154
+ degraded = append(degraded, fmt.Sprintf("%s: %v", name, err))
137
155
  }
138
156
  }
139
157
 
140
- if masked, err := maskedArtifact(workspace, "spec.md"); err == nil {
158
+ masked, err := maskedArtifact(workspace, "spec.md")
159
+ note("spec.md", err)
160
+ if err == nil {
141
161
  for _, m := range regressACRe.FindAllStringSubmatch(masked, -1) {
142
162
  if strings.EqualFold(m[1], "x") {
143
163
  fp.CheckedAC = append(fp.CheckedAC, m[2])
@@ -145,14 +165,19 @@ func fingerprintWorkspace(root, slug, workspace string) (progressFingerprint, er
145
165
  }
146
166
  }
147
167
 
148
- if raw, err := os.ReadFile(filepath.Join(workspace, "tasks.md")); err == nil { // #nosec G304 -- workspace artifact
149
- if masked, maskErr := markdowntext.Structural(raw); maskErr == nil {
150
- fp.DoneSlices = doneSlices(string(masked))
151
- }
168
+ masked, err = maskedArtifact(workspace, "tasks.md")
169
+ note("tasks.md", err)
170
+ if err == nil {
171
+ fp.DoneSlices = doneSlices(masked)
152
172
  }
153
173
 
154
- if raw, err := os.ReadFile(filepath.Join(workspace, acceptance.GatesFile)); err == nil { // #nosec G304 -- workspace artifact
174
+ raw, err := os.ReadFile(filepath.Join(workspace, acceptance.GatesFile)) // #nosec G304 -- workspace artifact
175
+ note(acceptance.GatesFile, err)
176
+ if err == nil {
155
177
  doc := acceptance.ParseLedger(string(raw))
178
+ if len(doc.Errors) > 0 {
179
+ note(acceptance.GatesFile, fmt.Errorf("%s", strings.Join(doc.Errors, "; ")))
180
+ }
156
181
  for _, g := range doc.Gates {
157
182
  if g.Checked {
158
183
  fp.MetGates = append(fp.MetGates, g.ID)
@@ -163,12 +188,17 @@ func fingerprintWorkspace(root, slug, workspace string) (progressFingerprint, er
163
188
  }
164
189
  }
165
190
 
166
- if masked, err := maskedArtifact(workspace, "questions.md"); err == nil {
191
+ masked, err = maskedArtifact(workspace, "questions.md")
192
+ note("questions.md", err)
193
+ if err == nil {
167
194
  fp.ResolvedQuestions = resolvedQuestions(masked)
168
195
  }
169
196
 
170
197
  fp.PresentArtifacts = presentArtifacts(workspace)
171
198
  sortSets(&fp)
199
+ if len(degraded) > 0 {
200
+ return fp, fmt.Errorf("degraded artifact(s), refusing to treat as progress facts: %s", strings.Join(degraded, "; "))
201
+ }
172
202
  return fp, nil
173
203
  }
174
204
 
@@ -297,10 +327,19 @@ func compareProgress(base, current progressFingerprint) []string {
297
327
  // updateRegressionBaseline replaces the baseline with the current fingerprint.
298
328
  // Regressions being blessed are printed, never hidden — a ratchet is the
299
329
  // recorded acknowledgment that the current state is the new floor.
300
- func updateRegressionBaseline(root, slug, baselinePath string, base regressionBaseline, hasBaseline bool, current progressFingerprint, stdout, stderr io.Writer) int {
330
+ func updateRegressionBaseline(root, slug, baselinePath string, base regressionBaseline, hasBaseline bool, current progressFingerprint, allowEmpty bool, stdout, stderr io.Writer) int {
301
331
  var blessed []string
302
332
  if hasBaseline {
303
333
  blessed = compareProgress(base.progressFingerprint, current)
334
+ // Wiping every recorded acceptance fact is indistinguishable from a
335
+ // destroyed workspace, so it needs an explicit flag.
336
+ if !allowEmpty && len(base.CheckedAC)+len(base.MetGates) > 0 && len(current.CheckedAC)+len(current.MetGates) == 0 {
337
+ for _, line := range blessed {
338
+ fmt.Fprintf(stdout, "REGRESSION: %s\n", line)
339
+ }
340
+ fmt.Fprintf(stdout, "check regression: BLOCKED: --update would leave no checked acceptance criterion or met gate; rerun with --allow-empty to accept\n")
341
+ return 3
342
+ }
304
343
  }
305
344
  // Keep the phase high-water mark: a baseline never forgets the furthest phase.
306
345
  if hasBaseline && base.PhaseOrdinal > current.PhaseOrdinal {
@@ -375,4 +414,4 @@ func sortSets(fp *progressFingerprint) {
375
414
  sort.Strings(fp.PresentArtifacts)
376
415
  }
377
416
 
378
- const regressionUsage = "usage: devrites-engine check regression <slug> [--update]"
417
+ const regressionUsage = "usage: devrites-engine check regression <slug> [--update [--allow-empty]]"
@@ -177,3 +177,106 @@ func TestRegressionUsageErrors(t *testing.T) {
177
177
  t.Fatalf("bad flag code=%d", code)
178
178
  }
179
179
  }
180
+
181
+ func TestRegressionDegradedArtifactRefusesRatchet(t *testing.T) {
182
+ root, dir := regressionWorkspace(t, "build")
183
+ if code, out := checkRegression(t, root, "feat", "--update"); code != 0 || !strings.Contains(out, "baseline updated") {
184
+ t.Fatalf("healthy update code=%d out=%s", code, out)
185
+ }
186
+ baselinePath := filepath.Join(dir, regressionBaselineFile)
187
+ before, err := os.ReadFile(baselinePath)
188
+ if err != nil {
189
+ t.Fatal(err)
190
+ }
191
+ healthy, err := fingerprintWorkspace(root, "feat", dir)
192
+ if err != nil || len(healthy.CheckedAC) != 1 || healthy.CheckedAC[0] != "AC-001" {
193
+ t.Fatalf("healthy fingerprint err=%v checked=%v", err, healthy.CheckedAC)
194
+ }
195
+
196
+ writeFile(t, filepath.Join(dir, "spec.md"), "# Spec\n\n## Acceptance criteria\n- [x] AC-001: a\x00\n")
197
+ if _, err := fingerprintWorkspace(root, "feat", dir); err == nil || !strings.Contains(err.Error(), "spec.md") {
198
+ t.Fatalf("degraded fingerprint must name spec.md, err=%v", err)
199
+ }
200
+ code, out := checkRegression(t, root, "feat", "--update")
201
+ if code != 2 || strings.Contains(out, "baseline updated") || !strings.Contains(out, "spec.md") {
202
+ t.Fatalf("degraded ratchet code=%d out=%s", code, out)
203
+ }
204
+ after, err := os.ReadFile(baselinePath)
205
+ if err != nil || !bytes.Equal(before, after) {
206
+ t.Fatalf("baseline rewritten from degraded fingerprint: err=%v", err)
207
+ }
208
+ }
209
+
210
+ func TestRegressionUpdateRefusesToWipeAcceptanceFacts(t *testing.T) {
211
+ root, dir := regressionWorkspace(t, "build")
212
+ if code, out := checkRegression(t, root, "feat", "--update"); code != 0 || !strings.Contains(out, "baseline updated") {
213
+ t.Fatalf("healthy update code=%d out=%s", code, out)
214
+ }
215
+ baselinePath := filepath.Join(dir, regressionBaselineFile)
216
+ before, err := os.ReadFile(baselinePath)
217
+ if err != nil {
218
+ t.Fatal(err)
219
+ }
220
+
221
+ writeFile(t, filepath.Join(dir, "spec.md"), strings.Replace(regressionSpec, "- [x] AC-001", "- [ ] AC-001", 1))
222
+ writeFile(t, filepath.Join(dir, "gates.md"), strings.Replace(regressionGates, "- [x] AC-001", "- [ ] AC-001", 1))
223
+
224
+ code, out := checkRegression(t, root, "feat", "--update")
225
+ if code != 3 || strings.Contains(out, "baseline updated") || !strings.Contains(out, "--allow-empty") {
226
+ t.Fatalf("wiping ratchet code=%d out=%s", code, out)
227
+ }
228
+ after, err := os.ReadFile(baselinePath)
229
+ if err != nil || !bytes.Equal(before, after) {
230
+ t.Fatalf("baseline rewritten by refused wipe: err=%v", err)
231
+ }
232
+
233
+ code, out = checkRegression(t, root, "feat", "--update", "--allow-empty")
234
+ if code != 0 || !strings.Contains(out, "REGRESSION-BLESSED") || !strings.Contains(out, "baseline updated") {
235
+ t.Fatalf("explicit wipe code=%d out=%s", code, out)
236
+ }
237
+ }
238
+
239
+ func TestRegressionMalformedGatesRefusesRatchet(t *testing.T) {
240
+ root, dir := regressionWorkspace(t, "build")
241
+ if code, out := checkRegression(t, root, "feat", "--update"); code != 0 || !strings.Contains(out, "baseline updated") {
242
+ t.Fatalf("healthy update code=%d out=%s", code, out)
243
+ }
244
+ baselinePath := filepath.Join(dir, regressionBaselineFile)
245
+ before, err := os.ReadFile(baselinePath)
246
+ if err != nil {
247
+ t.Fatal(err)
248
+ }
249
+
250
+ writeFile(t, filepath.Join(dir, "gates.md"), strings.Replace(regressionGates, "first thing works", "first thing works\x00", 1))
251
+ if _, err := fingerprintWorkspace(root, "feat", dir); err == nil || !strings.Contains(err.Error(), "gates.md") {
252
+ t.Fatalf("malformed gates fingerprint must name gates.md, err=%v", err)
253
+ }
254
+ code, out := checkRegression(t, root, "feat", "--update", "--allow-empty")
255
+ if code != 2 || strings.Contains(out, "baseline updated") || !strings.Contains(out, "gates.md") {
256
+ t.Fatalf("malformed gates ratchet code=%d out=%s", code, out)
257
+ }
258
+ after, err := os.ReadFile(baselinePath)
259
+ if err != nil || !bytes.Equal(before, after) {
260
+ t.Fatalf("baseline rewritten from malformed gates: err=%v", err)
261
+ }
262
+ }
263
+
264
+ func TestRegressionUnreadablePhaseIsNotPass(t *testing.T) {
265
+ root, dir := regressionWorkspace(t, "prove")
266
+ if code, out := checkRegression(t, root, "feat", "--update"); code != 0 || !strings.Contains(out, "baseline updated") {
267
+ t.Fatalf("healthy update code=%d out=%s", code, out)
268
+ }
269
+ if code, out := checkRegression(t, root, "feat"); code != 0 || !strings.Contains(out, "PASS") {
270
+ t.Fatalf("healthy control code=%d out=%s", code, out)
271
+ }
272
+
273
+ writeFile(t, filepath.Join(dir, "state.md"), "# State\n\n## Cursor\n| Key | Value |\n| --- | --- |\n| status | running |\n")
274
+ // Premise: the corrupted state.md must leave the phase unobservable.
275
+ if fp, err := fingerprintWorkspace(root, "feat", dir); err == nil && fp.PhaseOrdinal >= 0 {
276
+ t.Fatalf("premise failed: phase still observable, ordinal=%d", fp.PhaseOrdinal)
277
+ }
278
+ code, out := checkRegression(t, root, "feat")
279
+ if code == 0 || strings.Contains(out, "PASS") {
280
+ t.Fatalf("unreadable phase must not pass: code=%d out=%s", code, out)
281
+ }
282
+ }