devrites 5.14.4 → 6.0.1

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 +23 -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 +5 -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 +6 -3
  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 +5 -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 +6 -3
  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 +5 -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 +6 -3
  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 +5 -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 +6 -3
  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 +5 -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 +6 -3
  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 +5 -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 +6 -3
  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
@@ -1,18 +1,33 @@
1
1
  package fsutil
2
2
 
3
3
  import (
4
+ "crypto/rand"
5
+ "encoding/binary"
6
+ "errors"
4
7
  "fmt"
5
8
  "io/fs"
6
9
  "os"
7
10
  "path/filepath"
8
11
  "runtime"
12
+ "syscall"
9
13
  )
10
14
 
11
- // PermissionsMatch compares POSIX permission bits where the platform exposes
12
- // them. Windows os.FileMode synthesizes 0666/0777 from file attributes, so its
13
- // inherited ACL remains the security boundary instead.
14
- func PermissionsMatch(mode, want fs.FileMode) bool {
15
- return runtime.GOOS == "windows" || mode.Perm() == want.Perm()
15
+ // syncDir flushes a directory's entries so a completed rename survives a crash.
16
+ // It is a variable so tests can observe the call.
17
+ var syncDir = func(dir string) error {
18
+ if runtime.GOOS == "windows" {
19
+ return nil
20
+ }
21
+ d, err := os.Open(dir) // #nosec G304 -- dir is the parent of an engine-managed path
22
+ if err != nil {
23
+ return err
24
+ }
25
+ err = d.Sync()
26
+ _ = d.Close()
27
+ if errors.Is(err, syscall.EINVAL) || errors.Is(err, errors.ErrUnsupported) {
28
+ return nil
29
+ }
30
+ return err
16
31
  }
17
32
 
18
33
  // WriteFileAtomic writes path by first writing a sibling temp file and then
@@ -51,61 +66,80 @@ func WriteFileAtomic(path string, data []byte, perm fs.FileMode) error {
51
66
  return fmt.Errorf("atomic write %s: %w", path, err)
52
67
  }
53
68
  cleanup = false
54
- return nil
55
- }
56
-
57
- // FileModTime returns a regular file's modification time in whole seconds.
58
- func FileModTime(path string) (int64, bool) {
59
- info, err := os.Stat(path)
60
- if err != nil || !info.Mode().IsRegular() {
61
- return 0, false
69
+ if err := syncDir(filepath.Dir(path)); err != nil {
70
+ return fmt.Errorf("atomic write %s: %w", path, err)
62
71
  }
63
- return info.ModTime().Unix(), true
72
+ return nil
64
73
  }
65
74
 
66
- // NewestModTime returns the newest modification time among regular files.
67
- func NewestModTime(paths ...string) (newest int64, ok bool) {
68
- for _, path := range paths {
69
- if modified, exists := FileModTime(path); exists && (!ok || modified > newest) {
70
- newest, ok = modified, true
75
+ // WriteFileAtomicIn is WriteFileAtomic confined to root: every directory
76
+ // component of rel is resolved relative to the open root, so a component
77
+ // swapped for a symlink that leaves the root fails instead of redirecting
78
+ // the write.
79
+ func WriteFileAtomicIn(root *os.Root, rel string, data []byte, perm fs.FileMode) (err error) {
80
+ defer func() {
81
+ if err != nil {
82
+ err = fmt.Errorf("atomic write %s: %w", filepath.Join(root.Name(), rel), err)
71
83
  }
84
+ }()
85
+ dir := filepath.Dir(rel)
86
+ if err := root.MkdirAll(dir, 0o755); err != nil {
87
+ return err
72
88
  }
73
- return newest, ok
74
- }
75
-
76
- // CopyTree recursively copies src to dst, creating parent directories and
77
- // overwriting files. A missing src is not an error.
78
- func CopyTree(src, dst string) error {
79
- info, err := os.Stat(src)
80
- if os.IsNotExist(err) {
81
- return nil
89
+ var tmpName string
90
+ var tmp *os.File
91
+ for range 100 {
92
+ var nonce [8]byte
93
+ _, _ = rand.Read(nonce[:]) // never fails since go 1.24
94
+ tmpName = filepath.Join(dir, fmt.Sprintf(".%s.tmp-%d", filepath.Base(rel), binary.BigEndian.Uint64(nonce[:])))
95
+ tmp, err = root.OpenFile(tmpName, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600)
96
+ if !errors.Is(err, fs.ErrExist) {
97
+ break
98
+ }
82
99
  }
83
100
  if err != nil {
84
- return fmt.Errorf("copy %s: %w", src, err)
101
+ return err
85
102
  }
86
- if !info.IsDir() {
87
- // #nosec G304 -- src is an engine-managed path inside the operator-supplied root
88
- data, err := os.ReadFile(src)
89
- if err != nil {
90
- return fmt.Errorf("copy %s: %w", src, err)
91
- }
92
- if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
93
- return fmt.Errorf("copy to %s: %w", dst, err)
103
+ cleanup := true
104
+ defer func() {
105
+ if cleanup {
106
+ _ = root.Remove(tmpName)
94
107
  }
95
- // #nosec G703 -- dst mirrors src within the same managed tree
96
- return os.WriteFile(dst, data, 0o644)
108
+ }()
109
+ if _, err := tmp.Write(data); err != nil {
110
+ _ = tmp.Close()
111
+ return err
97
112
  }
98
- entries, err := os.ReadDir(src)
99
- if err != nil {
100
- return fmt.Errorf("copy %s: %w", src, err)
113
+ if err := tmp.Chmod(perm); err != nil {
114
+ _ = tmp.Close()
115
+ return err
101
116
  }
102
- if err := os.MkdirAll(dst, 0o755); err != nil {
103
- return fmt.Errorf("copy to %s: %w", dst, err)
117
+ if err := tmp.Sync(); err != nil {
118
+ _ = tmp.Close()
119
+ return err
104
120
  }
105
- for _, e := range entries {
106
- if err := CopyTree(filepath.Join(src, e.Name()), filepath.Join(dst, e.Name())); err != nil {
107
- return err
108
- }
121
+ if err := tmp.Close(); err != nil {
122
+ return err
109
123
  }
110
- return nil
124
+ if err := root.Rename(tmpName, rel); err != nil {
125
+ return err
126
+ }
127
+ cleanup = false
128
+ return syncDirIn(root, dir)
129
+ }
130
+
131
+ func syncDirIn(root *os.Root, dir string) error {
132
+ if runtime.GOOS == "windows" {
133
+ return nil
134
+ }
135
+ d, err := root.Open(dir)
136
+ if err != nil {
137
+ return err
138
+ }
139
+ err = d.Sync()
140
+ _ = d.Close()
141
+ if errors.Is(err, syscall.EINVAL) || errors.Is(err, errors.ErrUnsupported) {
142
+ return nil
143
+ }
144
+ return err
111
145
  }
@@ -6,7 +6,6 @@ import (
6
6
  "runtime"
7
7
  "strings"
8
8
  "testing"
9
- "time"
10
9
  )
11
10
 
12
11
  func TestWriteFileAtomicWritesAndOverwrites(t *testing.T) {
@@ -22,7 +21,7 @@ func TestWriteFileAtomicWritesAndOverwrites(t *testing.T) {
22
21
  if string(got) != "first\n" {
23
22
  t.Fatalf("content %q", got)
24
23
  }
25
- if !PermissionsMatch(mustMode(t, path), 0o644) {
24
+ if runtime.GOOS != "windows" && mustMode(t, path).Perm() != 0o644 {
26
25
  t.Fatalf("perm %v", mustMode(t, path))
27
26
  }
28
27
  // Overwrite in place.
@@ -53,141 +52,103 @@ func mustMode(t *testing.T, path string) os.FileMode {
53
52
  return info.Mode()
54
53
  }
55
54
 
56
- func TestFileModTime(t *testing.T) {
55
+ func TestWriteFileAtomicSurfacesFailure(t *testing.T) {
57
56
  dir := t.TempDir()
58
- path := filepath.Join(dir, "file.txt")
59
- if err := os.WriteFile(path, []byte("x"), 0o644); err != nil {
57
+ blocker := filepath.Join(dir, "blocker")
58
+ if err := os.WriteFile(blocker, []byte("x"), 0o644); err != nil {
60
59
  t.Fatal(err)
61
60
  }
62
- modified, ok := FileModTime(path)
63
- if !ok {
64
- t.Fatal("regular file should report mod time")
65
- }
66
- if modified <= 0 {
67
- t.Fatalf("mod time %d", modified)
68
- }
69
- if _, ok := FileModTime(filepath.Join(dir, "missing.txt")); ok {
70
- t.Fatal("missing file should report !ok")
61
+ // The parent path is an existing file, so creating the destination
62
+ // directory must fail and the error must surface to the caller.
63
+ err := WriteFileAtomic(filepath.Join(blocker, "nested", "file.txt"), []byte("x"), 0o644)
64
+ if err == nil {
65
+ t.Fatal("expected the write failure to surface")
71
66
  }
72
- if _, ok := FileModTime(dir); ok {
73
- t.Fatal("directory should report !ok")
67
+ if !strings.Contains(err.Error(), "atomic write") {
68
+ t.Fatalf("error should identify the operation, got %v", err)
74
69
  }
75
70
  }
76
71
 
77
- func TestNewestModTime(t *testing.T) {
78
- dir := t.TempDir()
79
- old := filepath.Join(dir, "old.txt")
80
- new := filepath.Join(dir, "new.txt")
81
- if err := os.WriteFile(old, []byte("x"), 0o644); err != nil {
82
- t.Fatal(err)
72
+ func TestWriteFileAtomicSyncsParentDirAfterRename(t *testing.T) {
73
+ var calls []string
74
+ var existedAtSync bool
75
+ path := filepath.Join(t.TempDir(), "nested", "file.txt")
76
+ orig := syncDir
77
+ syncDir = func(dir string) error {
78
+ calls = append(calls, dir)
79
+ _, err := os.Stat(path)
80
+ existedAtSync = err == nil
81
+ return nil
83
82
  }
84
- if err := os.WriteFile(new, []byte("x"), 0o644); err != nil {
83
+ t.Cleanup(func() { syncDir = orig })
84
+ if err := WriteFileAtomic(path, []byte("x"), 0o644); err != nil {
85
85
  t.Fatal(err)
86
86
  }
87
- future := time.Now().Add(2 * time.Hour)
88
- if err := os.Chtimes(new, future, future); err != nil {
89
- t.Skipf("cannot set file times on this platform: %v", err)
90
- }
91
- newest, ok := NewestModTime(old, new)
92
- if !ok {
93
- t.Fatal("expected ok")
87
+ if len(calls) != 1 || calls[0] != filepath.Dir(path) {
88
+ t.Fatalf("syncDir calls = %v, want one call with %q", calls, filepath.Dir(path))
94
89
  }
95
- want, _ := FileModTime(new)
96
- if newest != want {
97
- t.Fatalf("newest=%d want %d", newest, want)
98
- }
99
- if _, ok := NewestModTime(filepath.Join(dir, "missing.txt")); ok {
100
- t.Fatal("missing-only inputs should report !ok")
90
+ if !existedAtSync {
91
+ t.Fatal("syncDir ran before the rename")
101
92
  }
102
93
  }
103
94
 
104
- func TestCopyTreeMissingSourceIsNoOp(t *testing.T) {
105
- dir := t.TempDir()
106
- dst := filepath.Join(dir, "dst")
107
- if err := CopyTree(filepath.Join(dir, "missing"), dst); err != nil {
108
- t.Fatalf("missing src must not error: %v", err)
109
- }
110
- if _, err := os.Stat(dst); !os.IsNotExist(err) {
111
- t.Fatalf("dst must not be created, got %v", err)
112
- }
113
- }
114
-
115
- func TestCopyTreeFileAndTree(t *testing.T) {
116
- dir := t.TempDir()
117
- src := filepath.Join(dir, "src")
118
- if err := os.MkdirAll(filepath.Join(src, "sub"), 0o755); err != nil {
119
- t.Fatal(err)
120
- }
121
- if err := os.WriteFile(filepath.Join(src, "root.txt"), []byte("root\n"), 0o644); err != nil {
122
- t.Fatal(err)
123
- }
124
- if err := os.WriteFile(filepath.Join(src, "sub", "leaf.txt"), []byte("leaf\n"), 0o644); err != nil {
125
- t.Fatal(err)
126
- }
127
- dst := filepath.Join(dir, "dst")
128
- if err := CopyTree(src, dst); err != nil {
129
- t.Fatal(err)
130
- }
131
- for rel, want := range map[string]string{
132
- "root.txt": "root\n",
133
- "sub/leaf.txt": "leaf\n",
134
- } {
135
- got, err := os.ReadFile(filepath.Join(dst, filepath.FromSlash(rel)))
136
- if err != nil {
137
- t.Fatalf("%s: %v", rel, err)
138
- }
139
- if string(got) != want {
140
- t.Fatalf("%s: %q want %q", rel, got, want)
95
+ func TestWriteFileAtomicInRefusesSymlinkedDirectoryOutsideRoot(t *testing.T) {
96
+ if runtime.GOOS == "windows" {
97
+ t.Skip("creating symlinks needs elevated privileges on Windows")
98
+ }
99
+ base := t.TempDir()
100
+ target := filepath.Join(base, "target")
101
+ outside := filepath.Join(base, "outside")
102
+ for _, dir := range []string{target, outside} {
103
+ if err := os.MkdirAll(dir, 0o755); err != nil {
104
+ t.Fatal(err)
141
105
  }
142
106
  }
143
-
144
- // Copying a single file copies its contents.
145
- single := filepath.Join(dir, "single.txt")
146
- if err := os.WriteFile(single, []byte("one\n"), 0o644); err != nil {
107
+ if err := os.Symlink(outside, filepath.Join(target, ".claude")); err != nil {
147
108
  t.Fatal(err)
148
109
  }
149
- singleDst := filepath.Join(dir, "single-copy.txt")
150
- if err := CopyTree(single, singleDst); err != nil {
110
+ root, err := os.OpenRoot(target)
111
+ if err != nil {
151
112
  t.Fatal(err)
152
113
  }
153
- if got, _ := os.ReadFile(singleDst); string(got) != "one\n" {
154
- t.Fatalf("single copy %q", got)
155
- }
156
-
157
- // Recopying overwrites existing files.
158
- if err := os.WriteFile(filepath.Join(src, "root.txt"), []byte("changed\n"), 0o644); err != nil {
159
- t.Fatal(err)
114
+ defer func() { _ = root.Close() }()
115
+ if err := WriteFileAtomicIn(root, filepath.Join(".claude", "skills", "x.md"), []byte("x"), 0o644); err == nil {
116
+ t.Fatal("expected the write through a symlink leaving the root to fail")
160
117
  }
161
- if err := CopyTree(src, dst); err != nil {
118
+ entries, err := os.ReadDir(outside)
119
+ if err != nil {
162
120
  t.Fatal(err)
163
121
  }
164
- if got, _ := os.ReadFile(filepath.Join(dst, "root.txt")); string(got) != "changed\n" {
165
- t.Fatalf("overwrite %q", got)
122
+ if len(entries) != 0 {
123
+ t.Fatalf("outside directory was written to: %v", entries)
166
124
  }
167
125
  }
168
126
 
169
- func TestPermissionsMatch(t *testing.T) {
170
- if !PermissionsMatch(0o644, 0o644) {
171
- t.Fatal("matching perms must match")
172
- }
173
- if runtime.GOOS != "windows" && PermissionsMatch(0o600, 0o644) {
174
- t.Fatal("differing POSIX perms must not match")
175
- }
176
- }
177
-
178
- func TestWriteFileAtomicSurfacesFailure(t *testing.T) {
179
- dir := t.TempDir()
180
- blocker := filepath.Join(dir, "blocker")
181
- if err := os.WriteFile(blocker, []byte("x"), 0o644); err != nil {
127
+ func TestWriteFileAtomicInWritesOverwritesAndLeavesNoTemp(t *testing.T) {
128
+ target := t.TempDir()
129
+ root, err := os.OpenRoot(target)
130
+ if err != nil {
182
131
  t.Fatal(err)
183
132
  }
184
- // The parent path is an existing file, so creating the destination
185
- // directory must fail and the error must surface to the caller.
186
- err := WriteFileAtomic(filepath.Join(blocker, "nested", "file.txt"), []byte("x"), 0o644)
187
- if err == nil {
188
- t.Fatal("expected the write failure to surface")
133
+ defer func() { _ = root.Close() }()
134
+ rel := filepath.Join("a", "b", "f.txt")
135
+ for _, content := range []string{"one", "two"} {
136
+ if err := WriteFileAtomicIn(root, rel, []byte(content), 0o640); err != nil {
137
+ t.Fatal(err)
138
+ }
139
+ got, err := os.ReadFile(filepath.Join(target, rel))
140
+ if err != nil || string(got) != content {
141
+ t.Fatalf("read = %q, %v; want %q", got, err, content)
142
+ }
189
143
  }
190
- if !strings.Contains(err.Error(), "atomic write") {
191
- t.Fatalf("error should identify the operation, got %v", err)
144
+ if runtime.GOOS != "windows" {
145
+ info, err := os.Stat(filepath.Join(target, rel))
146
+ if err != nil || info.Mode().Perm() != 0o640 {
147
+ t.Fatalf("mode = %v, %v; want 0640", info, err)
148
+ }
149
+ }
150
+ entries, err := os.ReadDir(filepath.Join(target, "a", "b"))
151
+ if err != nil || len(entries) != 1 {
152
+ t.Fatalf("directory entries = %v, %v; want only the target file", entries, err)
192
153
  }
193
154
  }
@@ -6,8 +6,10 @@ package gate
6
6
 
7
7
  import (
8
8
  "fmt"
9
+ "regexp"
9
10
  "strings"
10
11
 
12
+ "github.com/devrites/devrites/internal/markdowntext"
11
13
  "github.com/devrites/devrites/internal/reason"
12
14
  "github.com/devrites/devrites/internal/state"
13
15
  )
@@ -114,7 +116,11 @@ func checkObservation(kind Kind, observation *state.WorkspaceObservation) (*Resu
114
116
  var stateProblems []string
115
117
 
116
118
  if policy.BlocksOpenQuestions {
117
- if gates, awaitingHuman := retainedHumanGates(observation); len(gates) > 0 {
119
+ gates, awaitingHuman, err := retainedHumanGates(observation)
120
+ if err != nil {
121
+ stateProblems = append(stateProblems, "questions.md is invalid Markdown, so open human questions cannot be ruled out")
122
+ blocked = true
123
+ } else if len(gates) > 0 {
118
124
  problem := fmt.Sprintf("open %s human question(s) remain in questions.md", strings.Join(gates, "/"))
119
125
  if !awaitingHuman {
120
126
  problem += " but state.md is not awaiting_human"
@@ -247,7 +253,55 @@ func acceptanceMapProblems(observation *state.WorkspaceObservation, policy state
247
253
  testPlan = fact.Bytes()
248
254
  }
249
255
  }
250
- return state.ParseAcceptanceMap(spec.Bytes(), tasks, testPlan, requireTasks, requireTestPlan).Problems
256
+ result := state.ParseAcceptanceMap(spec.Bytes(), tasks, testPlan, requireTasks, requireTestPlan)
257
+ if len(result.SpecIDs) == 0 && specClaimsAcceptance(spec.Bytes()) {
258
+ return []string{"spec.md mentions acceptance criteria but no AC-### id was found under a `## Acceptance criteria` heading; use that exact heading and three-digit ids such as AC-001"}
259
+ }
260
+ return append(result.Problems, specUnreadAcceptanceProblems(spec.Bytes())...)
261
+ }
262
+
263
+ var (
264
+ specAcceptanceHeadingRE = regexp.MustCompile(`(?i)^\s{0,3}#{1,6}\s+.*acceptance criteria`)
265
+ specCanonicalAcceptanceHead = regexp.MustCompile(`(?i)^##\s+Acceptance criteria\s*$`)
266
+ specACTokenRE = regexp.MustCompile(`\bAC-\d+\b`)
267
+ specAcceptanceClaimRE = regexp.MustCompile(`(?im)^\s{0,3}#{1,6}\s+.*acceptance criteria|\bAC-\d+\b`)
268
+ )
269
+
270
+ // specClaimsAcceptance reports whether structural (unfenced) spec text looks
271
+ // like it carries acceptance criteria, so a parse that finds none is a defect
272
+ // in the spec rather than a spec with nothing to map.
273
+ func specClaimsAcceptance(spec []byte) bool {
274
+ structural, err := markdowntext.Structural(spec)
275
+ return err == nil && specAcceptanceClaimRE.Match(structural)
276
+ }
277
+
278
+ // specUnreadAcceptanceProblems names acceptance text the parser skips: ids that
279
+ // are not exactly three digits and acceptance headings after the first
280
+ // canonical one, which would otherwise escape the coverage check.
281
+ func specUnreadAcceptanceProblems(spec []byte) []string {
282
+ structural, err := markdowntext.Structural(spec)
283
+ if err != nil {
284
+ return nil
285
+ }
286
+ var problems []string
287
+ seen := map[string]bool{}
288
+ readHeading := false
289
+ for _, line := range strings.Split(string(structural), "\n") {
290
+ if specAcceptanceHeadingRE.MatchString(line) {
291
+ if trimmed := strings.TrimSpace(line); !readHeading && specCanonicalAcceptanceHead.MatchString(trimmed) {
292
+ readHeading = true
293
+ } else {
294
+ problems = append(problems, fmt.Sprintf("spec.md has an acceptance criteria heading the gate does not read (%q); only the first `## Acceptance criteria` section is checked", trimmed))
295
+ }
296
+ }
297
+ for _, id := range specACTokenRE.FindAllString(line, -1) {
298
+ if len(id) != len("AC-000") && !seen[id] {
299
+ seen[id] = true
300
+ problems = append(problems, fmt.Sprintf("spec.md uses %s, which is not a three-digit AC-### id, so the gate does not check it", id))
301
+ }
302
+ }
303
+ }
304
+ return problems
251
305
  }
252
306
 
253
307
  func missingSections(observation *state.WorkspaceObservation, required []state.Section) []state.Section {
@@ -378,25 +432,43 @@ func diagnosticRepair(code state.DiagnosticCode) string {
378
432
 
379
433
  const gateSpaceChars = " \t\n\v\f\r"
380
434
 
381
- func retainedHumanGates(observation *state.WorkspaceObservation) ([]string, bool) {
435
+ func retainedHumanGates(observation *state.WorkspaceObservation) ([]string, bool, error) {
382
436
  questions, ok := observation.Fact("questions.md")
383
437
  if !ok || (questions.State() != state.ArtifactPresent && questions.State() != state.ArtifactEmpty) {
384
- return nil, false
438
+ return nil, false, nil
385
439
  }
386
- gates := OpenBlockingQuestionGates(questions.Bytes())
387
- if len(gates) == 0 {
388
- return nil, false
440
+ gates, err := openBlockingQuestionGates(questions.Bytes())
441
+ if err != nil || len(gates) == 0 {
442
+ return nil, false, err
389
443
  }
390
444
  ledger, ok := observation.Fact(state.LedgerFile)
391
- return gates, ok && ledger.State() == state.ArtifactPresent && stateAwaitingHuman(ledger.Bytes())
445
+ return gates, ok && ledger.State() == state.ArtifactPresent && stateAwaitingHuman(ledger.Bytes()), nil
392
446
  }
393
447
 
394
448
  // OpenBlockingQuestionGates returns the deduplicated gate kinds (blocking,
395
449
  // validating, escalating) still open in questions.md, tolerating both the
396
450
  // per-question block form and the register table form. Exported so the
397
- // handoff resume record reports the same gates the lifecycle enforces.
451
+ // handoff resume record reports the same gates the lifecycle enforces. Content
452
+ // that cannot be parsed fails closed as [blocking], matching the lifecycle gate,
453
+ // so a caller never reads an unparseable file as having no open gates.
398
454
  func OpenBlockingQuestionGates(data []byte) []string {
399
- lines := splitLinesNoTrailing(data)
455
+ gates, err := openBlockingQuestionGates(data)
456
+ if err != nil {
457
+ return []string{"blocking"}
458
+ }
459
+ return gates
460
+ }
461
+
462
+ // openBlockingQuestionGates masks fenced regions first: a fenced region is a
463
+ // documented example, never live question structure. Content markdowntext
464
+ // rejects yields no gates and an error, which Check turns into a blocking
465
+ // problem rather than reading the file as clean.
466
+ func openBlockingQuestionGates(data []byte) ([]string, error) {
467
+ visible, err := markdowntext.Structural(data)
468
+ if err != nil {
469
+ return nil, err
470
+ }
471
+ lines := splitLinesNoTrailing(visible)
400
472
  seen := map[string]bool{}
401
473
  var gates []string
402
474
  inQ := false
@@ -417,6 +489,7 @@ func OpenBlockingQuestionGates(data []byte) []string {
417
489
  }
418
490
  }
419
491
  for _, line := range lines {
492
+ lower := strings.ToLower(line)
420
493
  if cells, ok := questionTableCells(line); ok {
421
494
  if !tableOpen {
422
495
  tableOpen = true
@@ -431,20 +504,20 @@ func OpenBlockingQuestionGates(data []byte) []string {
431
504
  statusColumn, gateColumn = -1, -1
432
505
  }
433
506
  switch {
434
- case strings.HasPrefix(strings.ToLower(line), "## q-"):
507
+ case strings.HasPrefix(lower, "## q-"):
435
508
  finalize()
436
509
  inQ, status, gate = true, "", ""
437
- case inQ && strings.HasPrefix(line, "status:"):
438
- status = strings.TrimLeft(strings.TrimPrefix(line, "status:"), gateSpaceChars)
439
- case inQ && strings.HasPrefix(line, "gate:"):
440
- gate = strings.TrimLeft(strings.TrimPrefix(line, "gate:"), gateSpaceChars)
510
+ case inQ && strings.HasPrefix(lower, "status:"):
511
+ status = strings.TrimLeft(line[len("status:"):], gateSpaceChars)
512
+ case inQ && strings.HasPrefix(lower, "gate:"):
513
+ gate = strings.TrimLeft(line[len("gate:"):], gateSpaceChars)
441
514
  case inQ && isHeadingLine(line):
442
515
  finalize()
443
516
  inQ = false
444
517
  }
445
518
  }
446
519
  finalize()
447
- return gates
520
+ return gates, nil
448
521
  }
449
522
 
450
523
  func questionTableCells(line string) ([]string, bool) {