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
@@ -39,6 +39,10 @@ func Resolve(root string, args []string, stdout, stderr io.Writer) int {
39
39
  return fail(stderr, err.Error(), 3)
40
40
  }
41
41
 
42
+ human := argAt(args, 0) == "--human"
43
+ if human {
44
+ args = args[1:]
45
+ }
42
46
  var mode, qid, payload string
43
47
  switch first := argAt(args, 0); first {
44
48
  case "--drop":
@@ -55,7 +59,7 @@ func Resolve(root string, args []string, stdout, stderr io.Writer) int {
55
59
  return fail(stderr, "Batch file not found: "+payload, 5)
56
60
  }
57
61
  case "":
58
- return fail(stderr, `Usage: devrites-engine state resolve <qid> "<answer>" | state resolve --drop <qid> ["<reason>"] | state resolve --batch <file>`, 5)
62
+ return fail(stderr, `Usage: devrites-engine state resolve [--human] <qid> "<answer>" | state resolve [--human] --drop <qid> ["<reason>"] | state resolve [--human] --batch <file>`, 5)
59
63
  default:
60
64
  mode = "answer"
61
65
  qid = first
@@ -67,7 +71,7 @@ func Resolve(root string, args []string, stdout, stderr io.Writer) int {
67
71
 
68
72
  code := 0
69
73
  if err := state.WithFeatureLock(root, slug, func() error {
70
- code = resolveMutation(mode, qid, payload, qfile, sfile, stdout, stderr)
74
+ code = resolveMutation(mode, qid, payload, qfile, sfile, human, stdout, stderr)
71
75
  return nil
72
76
  }); err != nil {
73
77
  return fail(stderr, err.Error(), 1)
@@ -75,10 +79,10 @@ func Resolve(root string, args []string, stdout, stderr io.Writer) int {
75
79
  return code
76
80
  }
77
81
 
78
- func resolveMutation(mode, qid, payload, qfile, sfile string, stdout, stderr io.Writer) int {
82
+ func resolveMutation(mode, qid, payload, qfile, sfile string, human bool, stdout, stderr io.Writer) int {
79
83
  switch mode {
80
84
  case "answer":
81
- if code := resolveQuestion(qfile, qid, "answered", payload, stderr); code != 0 {
85
+ if code := resolveQuestion(qfile, qid, "answered", payload, human, stderr); code != 0 {
82
86
  return code
83
87
  }
84
88
  if err := clearAwaiting(sfile, qid); err != nil {
@@ -88,7 +92,7 @@ func resolveMutation(mode, qid, payload, qfile, sfile string, stdout, stderr io.
88
92
  fmt.Fprintf(stdout, "Status: answered\n")
89
93
  fmt.Fprintf(stdout, "Workspace: questions.md + state.md updated.\n")
90
94
  case "drop":
91
- if code := resolveQuestion(qfile, qid, "dropped", payload, stderr); code != 0 {
95
+ if code := resolveQuestion(qfile, qid, "dropped", payload, human, stderr); code != 0 {
92
96
  return code
93
97
  }
94
98
  if err := clearAwaiting(sfile, qid); err != nil {
@@ -111,7 +115,7 @@ func resolveMutation(mode, qid, payload, qfile, sfile string, stdout, stderr io.
111
115
  rest := strings.TrimPrefix(line, "--drop ")
112
116
  bid, reason := splitColon(rest)
113
117
  reason = strings.TrimPrefix(reason, " ")
114
- if code := resolveQuestion(qfile, bid, "dropped", reason, stderr); code != 0 {
118
+ if code := resolveQuestion(qfile, bid, "dropped", reason, human, stderr); code != 0 {
115
119
  return code
116
120
  }
117
121
  if err := clearAwaiting(sfile, bid); err != nil {
@@ -121,7 +125,7 @@ func resolveMutation(mode, qid, payload, qfile, sfile string, stdout, stderr io.
121
125
  } else {
122
126
  bid, ans := splitColon(line)
123
127
  ans = strings.TrimPrefix(ans, " ")
124
- if code := resolveQuestion(qfile, bid, "answered", ans, stderr); code != 0 {
128
+ if code := resolveQuestion(qfile, bid, "answered", ans, human, stderr); code != 0 {
125
129
  return code
126
130
  }
127
131
  if err := clearAwaiting(sfile, bid); err != nil {
@@ -156,12 +160,15 @@ func isFile(path string) bool {
156
160
  return err == nil && info.Mode().IsRegular()
157
161
  }
158
162
 
159
- // batchLines returns the newline-terminated lines of a batch file. An unterminated
160
- // final line is dropped, matching a shell `read` loop, so a partial trailing line
161
- // is never applied as an entry.
163
+ // batchLines returns the lines of a batch file. A final line without a
164
+ // terminating newline is kept; only the empty element after a trailing newline
165
+ // is dropped.
162
166
  func batchLines(data []byte) []string {
163
167
  lines := strings.Split(string(data), "\n")
164
- return lines[:len(lines)-1]
168
+ if lines[len(lines)-1] == "" {
169
+ lines = lines[:len(lines)-1]
170
+ }
171
+ return lines
165
172
  }
166
173
 
167
174
  // splitColon splits s at the first ':', returning the parts before and after it
@@ -192,9 +199,12 @@ func clockNow() time.Time {
192
199
  func nowUTC() string { return clockNow().UTC().Format("2006-01-02T15:04:05Z") }
193
200
 
194
201
  // resolveQuestion rewrites the <qid> block in questions.md so it records the new
195
- // status, answer, and answered-at time in one pass. Returns 0, or 3 (qid
202
+ // status, answer, and answered-at time in one pass. With human set it also records
203
+ // answered_by: human; without it any answered_by line in the block, whatever its
204
+ // indentation or case, is removed, so
205
+ // an identity written before the resolve cannot survive it. Returns 0, or 3 (qid
196
206
  // not found) / 4 (qid not open), writing the message on failure.
197
- func resolveQuestion(qfile, qid, status, answer string, stderr io.Writer) int {
207
+ func resolveQuestion(qfile, qid, status, answer string, human bool, stderr io.Writer) int {
198
208
  // #nosec G304 -- questions.md path inside the feature workspace
199
209
  data, err := os.ReadFile(qfile)
200
210
  if err != nil {
@@ -204,7 +214,7 @@ func resolveQuestion(qfile, qid, status, answer string, stderr io.Writer) int {
204
214
  answer = oneLine(answer)
205
215
  target := regexp.MustCompile(`^## ` + regexp.QuoteMeta(qid) + `([[:space:]]|$)`)
206
216
 
207
- updated, found, notOpen := rewriteQuestionFields(splitLinesNoTrailing(data), target, status, answer, ts)
217
+ updated, found, notOpen := rewriteQuestionFields(splitLinesNoTrailing(data), target, status, answer, ts, human)
208
218
  if !found {
209
219
  return fail(stderr, "qid not found: "+qid, 3)
210
220
  }
@@ -224,6 +234,7 @@ var (
224
234
  statusStrip = regexp.MustCompile(`^status:[[:space:]]*`)
225
235
  answeredAtRe = regexp.MustCompile(`^answered_at:`)
226
236
  answerRe = regexp.MustCompile(`^answer:`)
237
+ answeredByRe = regexp.MustCompile(`(?i)^[[:space:]]*answered_by:`)
227
238
  )
228
239
 
229
240
  // rewriteQuestionFields walks questions.md and, inside the target question's
@@ -231,9 +242,9 @@ var (
231
242
  // reports whether the block was found and whether it was already not open (an
232
243
  // attempt to re-answer). A target block with no status line at all gets a full set
233
244
  // of closing fields appended.
234
- func rewriteQuestionFields(lines []string, target *regexp.Regexp, status, answer, ts string) (out []string, found, notOpen bool) {
245
+ func rewriteQuestionFields(lines []string, target *regexp.Regexp, status, answer, ts string, human bool) (out []string, found, notOpen bool) {
235
246
  inQ := false
236
- statusSeen, answeredAtSeen, answerSeen := false, false, false
247
+ statusSeen, answeredAtSeen, answerSeen, answeredBySeen := false, false, false, false
237
248
  closeBlock := func() {
238
249
  if !inQ {
239
250
  return
@@ -247,13 +258,16 @@ func rewriteQuestionFields(lines []string, target *regexp.Regexp, status, answer
247
258
  if !answerSeen {
248
259
  out = append(out, "answer: "+answer)
249
260
  }
261
+ if human && !answeredBySeen {
262
+ out = append(out, "answered_by: human")
263
+ }
250
264
  }
251
265
  for _, line := range lines {
252
266
  switch {
253
267
  case qHeaderRe.MatchString(line):
254
268
  closeBlock()
255
269
  inQ = target.MatchString(line)
256
- statusSeen, answeredAtSeen, answerSeen = false, false, false
270
+ statusSeen, answeredAtSeen, answerSeen, answeredBySeen = false, false, false, false
257
271
  if inQ {
258
272
  found = true
259
273
  }
@@ -274,6 +288,11 @@ func rewriteQuestionFields(lines []string, target *regexp.Regexp, status, answer
274
288
  case inQ && answerRe.MatchString(line):
275
289
  answerSeen = true
276
290
  out = append(out, "answer: "+answer)
291
+ case inQ && answeredByRe.MatchString(line):
292
+ if human && !answeredBySeen {
293
+ answeredBySeen = true
294
+ out = append(out, "answered_by: human")
295
+ }
277
296
  default:
278
297
  out = append(out, line)
279
298
  }
@@ -58,3 +58,135 @@ func resolveWorkspace(t *testing.T, questions string) string {
58
58
  testutil.WriteFile(t, filepath.Join(root, "work", "feat", "state.md"), "- Status: running\n- Next step: continue\n- Schema: 4\n")
59
59
  return root
60
60
  }
61
+
62
+ func TestResolveHumanFlagRecordsResolverIdentity(t *testing.T) {
63
+ root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\n")
64
+ var stdout, stderr bytes.Buffer
65
+
66
+ if code := Resolve(root, []string{"--human", "q-1", "yes"}, &stdout, &stderr); code != 0 {
67
+ t.Fatalf("code = %d, want 0; stderr=%q", code, stderr.String())
68
+ }
69
+ data, err := os.ReadFile(filepath.Join(root, "work", "feat", "questions.md"))
70
+ if err != nil {
71
+ t.Fatal(err)
72
+ }
73
+ if !strings.Contains(string(data), "answered_by: human\n") {
74
+ t.Fatalf("questions.md missing answered_by: human:\n%s", data)
75
+ }
76
+ }
77
+
78
+ func TestResolveWithoutHumanFlagDropsPreSeededIdentity(t *testing.T) {
79
+ root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\nanswered_by: human\n")
80
+ var stdout, stderr bytes.Buffer
81
+
82
+ if code := Resolve(root, []string{"q-1", "yes"}, &stdout, &stderr); code != 0 {
83
+ t.Fatalf("code = %d, want 0; stderr=%q", code, stderr.String())
84
+ }
85
+ data, err := os.ReadFile(filepath.Join(root, "work", "feat", "questions.md"))
86
+ if err != nil {
87
+ t.Fatal(err)
88
+ }
89
+ if strings.Contains(string(data), "answered_by") {
90
+ t.Fatalf("forged answered_by survived an unflagged resolve:\n%s", data)
91
+ }
92
+ }
93
+
94
+ func TestResolveWithoutHumanFlagDropsVariantPreSeededIdentity(t *testing.T) {
95
+ for _, seed := range []string{" answered_by: human", "Answered_By: human", "\tANSWERED_BY: human"} {
96
+ root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\n"+seed+"\n")
97
+ var stdout, stderr bytes.Buffer
98
+
99
+ if code := Resolve(root, []string{"q-1", "yes"}, &stdout, &stderr); code != 0 {
100
+ t.Fatalf("%q: code = %d, want 0; stderr=%q", seed, code, stderr.String())
101
+ }
102
+ if text := readQuestions(t, root); strings.Contains(strings.ToLower(text), "answered_by") {
103
+ t.Fatalf("%q: forged answered_by survived an unflagged resolve:\n%s", seed, text)
104
+ }
105
+ }
106
+ }
107
+
108
+ func TestResolveHumanFlagKeepsSingleCanonicalIdentity(t *testing.T) {
109
+ root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\n answered_by: agent\nAnswered_By: agent\n")
110
+ var stdout, stderr bytes.Buffer
111
+
112
+ if code := Resolve(root, []string{"--human", "q-1", "yes"}, &stdout, &stderr); code != 0 {
113
+ t.Fatalf("code = %d, want 0; stderr=%q", code, stderr.String())
114
+ }
115
+ text := readQuestions(t, root)
116
+ if strings.Count(strings.ToLower(text), "answered_by") != 1 || !strings.Contains(text, "\nanswered_by: human\n") {
117
+ t.Fatalf("want exactly one canonical answered_by: human:\n%s", text)
118
+ }
119
+ }
120
+
121
+ func TestResolveDropHonorsHumanFlag(t *testing.T) {
122
+ seeded := "## q-1 blocking\nstatus: open\n answered_by: human\n"
123
+ for _, tc := range []struct {
124
+ args []string
125
+ want bool
126
+ }{
127
+ {[]string{"--human", "--drop", "q-1", "obsolete"}, true},
128
+ {[]string{"--drop", "q-1", "obsolete"}, false},
129
+ } {
130
+ root := resolveWorkspace(t, seeded)
131
+ var stdout, stderr bytes.Buffer
132
+
133
+ if code := Resolve(root, tc.args, &stdout, &stderr); code != 0 {
134
+ t.Fatalf("%v: code = %d, want 0; stderr=%q", tc.args, code, stderr.String())
135
+ }
136
+ text := readQuestions(t, root)
137
+ if got := strings.Contains(text, "\nanswered_by: human\n"); got != tc.want || !strings.Contains(text, "status: dropped") {
138
+ t.Fatalf("%v: canonical answered_by = %v, want %v:\n%s", tc.args, got, tc.want, text)
139
+ }
140
+ if !tc.want && strings.Contains(text, "answered_by") {
141
+ t.Fatalf("%v: answered_by survived:\n%s", tc.args, text)
142
+ }
143
+ }
144
+ }
145
+
146
+ func TestResolveBatchHonorsHumanFlag(t *testing.T) {
147
+ questions := "## q-1 blocking\nstatus: open\n answered_by: human\n## q-2 blocking\nstatus: open\n"
148
+ batch := "q-1: yes\n--drop q-2: obsolete\n"
149
+ for _, tc := range []struct {
150
+ args []string
151
+ want int
152
+ }{
153
+ {[]string{"--human"}, 2},
154
+ {nil, 0},
155
+ } {
156
+ root := resolveWorkspace(t, questions)
157
+ file := filepath.Join(t.TempDir(), "batch.txt")
158
+ testutil.WriteFile(t, file, batch)
159
+ var stdout, stderr bytes.Buffer
160
+
161
+ if code := Resolve(root, append(tc.args, "--batch", file), &stdout, &stderr); code != 0 {
162
+ t.Fatalf("%v: code = %d, want 0; stderr=%q", tc.args, code, stderr.String())
163
+ }
164
+ text := readQuestions(t, root)
165
+ if got := strings.Count(text, "\nanswered_by: human\n"); got != tc.want || (tc.want == 0 && strings.Contains(text, "answered_by")) {
166
+ t.Fatalf("%v: answered_by count = %d, want %d:\n%s", tc.args, got, tc.want, text)
167
+ }
168
+ }
169
+ }
170
+
171
+ func readQuestions(t *testing.T, root string) string {
172
+ t.Helper()
173
+ data, err := os.ReadFile(filepath.Join(root, "work", "feat", "questions.md"))
174
+ if err != nil {
175
+ t.Fatal(err)
176
+ }
177
+ return string(data)
178
+ }
179
+
180
+ func TestResolveBatchAppliesUnterminatedFinalLine(t *testing.T) {
181
+ root := resolveWorkspace(t, "## q-1 blocking\nstatus: open\n## q-2 blocking\nstatus: open\n")
182
+ file := filepath.Join(t.TempDir(), "batch.txt")
183
+ testutil.WriteFile(t, file, "q-1: yes\n--drop q-2: obsolete")
184
+ var stdout, stderr bytes.Buffer
185
+
186
+ if code := Resolve(root, []string{"--batch", file}, &stdout, &stderr); code != 0 {
187
+ t.Fatalf("code = %d, want 0; stderr=%q", code, stderr.String())
188
+ }
189
+ if text := readQuestions(t, root); strings.Contains(text, "status: open") {
190
+ t.Fatalf("a question stayed open:\n%s", text)
191
+ }
192
+ }
@@ -7,7 +7,6 @@ import (
7
7
  "path/filepath"
8
8
  "regexp"
9
9
  "strings"
10
- "unicode"
11
10
  )
12
11
 
13
12
  // SkillTrustFinding is one deterministic trust scan result.
@@ -185,13 +184,3 @@ func FormatSkillTrust(result SkillTrustResult) string {
185
184
  }
186
185
  return b.String()
187
186
  }
188
-
189
- // ContainsOnlyASCII returns false when non-ASCII control or bidi characters appear.
190
- func ContainsOnlyASCII(text string) bool {
191
- for _, r := range text {
192
- if r > unicode.MaxASCII && isSuspiciousUnicode(r) {
193
- return false
194
- }
195
- }
196
- return true
197
- }
@@ -3,6 +3,7 @@ package lib
3
3
  import (
4
4
  "fmt"
5
5
  "io"
6
+ "path"
6
7
  "regexp"
7
8
  "strings"
8
9
 
@@ -68,6 +69,7 @@ func checkAllowlistPaths(paths []string) []string {
68
69
  var problems []string
69
70
  seen := map[string]bool{}
70
71
  for _, p := range paths {
72
+ c := path.Clean(p)
71
73
  switch {
72
74
  case strings.HasPrefix(p, "/") || windowsDrivePath.MatchString(p):
73
75
  problems = append(problems, fmt.Sprintf("allowlist path %q is not project-relative", p))
@@ -77,12 +79,12 @@ func checkAllowlistPaths(paths []string) []string {
77
79
  problems = append(problems, fmt.Sprintf("allowlist path %q uses a glob — exact paths only", p))
78
80
  case strings.HasSuffix(p, "/"):
79
81
  problems = append(problems, fmt.Sprintf("allowlist path %q is a directory — exact files only", p))
80
- case devritesPathRe.MatchString(p):
82
+ case devritesPathRe.MatchString(c):
81
83
  problems = append(problems, fmt.Sprintf("allowlist path %q targets .devrites — wrights never write workflow state", p))
82
- case seen[p]:
84
+ case seen[c]:
83
85
  problems = append(problems, fmt.Sprintf("allowlist path %q is duplicated", p))
84
86
  }
85
- seen[p] = true
87
+ seen[c] = true
86
88
  }
87
89
  return problems
88
90
  }
@@ -128,10 +130,10 @@ func RunCheckSlice(root string, args []string, stdout, stderr io.Writer) int {
128
130
  if touchedRaw, ok := fieldValue(fields, "files likely touched"); ok {
129
131
  allowed := map[string]bool{}
130
132
  for _, p := range allowlist {
131
- allowed[p] = true
133
+ allowed[path.Clean(p)] = true
132
134
  }
133
135
  for _, p := range parsePathList(touchedRaw) {
134
- if hasAllow && !allowed[p] {
136
+ if hasAllow && !allowed[path.Clean(p)] {
135
137
  problems = append(problems, fmt.Sprintf("Files likely touched %q is outside the Writer allowlist", p))
136
138
  }
137
139
  }
@@ -109,3 +109,21 @@ Tests/proof: none needed
109
109
  t.Fatalf("code=%d out:\n%s%s", code, stdout, stderr)
110
110
  }
111
111
  }
112
+
113
+ func TestCheckAllowlistPathsNormalizesBeforeRules(t *testing.T) {
114
+ if got := checkAllowlistPaths([]string{"./.devrites/state.md"}); len(got) != 1 || !strings.Contains(got[0], ".devrites") {
115
+ t.Fatalf("./.devrites path not rejected as workflow state: %v", got)
116
+ }
117
+ if got := checkAllowlistPaths([]string{"src/a.go", "./src/a.go"}); len(got) != 1 || !strings.Contains(got[0], "duplicated") {
118
+ t.Fatalf("./src/a.go not detected as duplicate of src/a.go: %v", got)
119
+ }
120
+ }
121
+
122
+ func TestCheckSliceTouchedComparesNormalizedPaths(t *testing.T) {
123
+ tasks := strings.Replace(goodSliceTasks, "Files likely touched: src/a.go; src/a_test.go", "Files likely touched: ./src/a.go; src/a_test.go", 1)
124
+ root := sliceWorkspace(t, tasks, sliceSpec)
125
+ stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
126
+ if code := RunCheckSlice(root, []string{"feat", "SLICE-001"}, stdout, stderr); code != 0 {
127
+ t.Fatalf("code=%d want 0\n%s%s", code, stdout, stderr)
128
+ }
129
+ }
@@ -1,6 +1,7 @@
1
1
  package lib
2
2
 
3
3
  import (
4
+ "io"
4
5
  "os"
5
6
  "path/filepath"
6
7
  "regexp"
@@ -103,11 +104,16 @@ func gatherTriggerFacts(root, featureDir, role string) triggerFacts {
103
104
  for _, name := range triggerEvidenceFiles {
104
105
  path := filepath.Join(featureDir, name)
105
106
  info, err := os.Stat(path)
106
- if err != nil || !info.Mode().IsRegular() || info.Size() > triggerEvidenceFileCap {
107
+ if err != nil || !info.Mode().IsRegular() {
107
108
  continue
108
109
  }
109
- // #nosec G304 -- workspace artifact; size cap checked above
110
- if data, err := os.ReadFile(path); err == nil {
110
+ f, err := os.Open(path) // #nosec G304 -- workspace artifact; read is capped below
111
+ if err != nil {
112
+ continue
113
+ }
114
+ data, err := io.ReadAll(io.LimitReader(f, triggerEvidenceFileCap))
115
+ _ = f.Close()
116
+ if err == nil {
111
117
  corpus.Write(data)
112
118
  corpus.WriteByte('\n')
113
119
  }
@@ -0,0 +1,23 @@
1
+ package lib
2
+
3
+ import (
4
+ "os"
5
+ "path/filepath"
6
+ "strings"
7
+ "testing"
8
+ )
9
+
10
+ func TestGatherTriggerFactsReadsCappedPrefixOfOversizedArtifact(t *testing.T) {
11
+ dir := t.TempDir()
12
+ body := "this feature adds a frontend component\n" + strings.Repeat(" ", triggerEvidenceFileCap)
13
+ if err := os.WriteFile(filepath.Join(dir, "spec.md"), []byte(body), 0o600); err != nil {
14
+ t.Fatal(err)
15
+ }
16
+ facts := gatherTriggerFacts("", dir, "")
17
+ if !uiSignalRe.MatchString(facts.corpus) {
18
+ t.Fatalf("oversized artifact contributed no corpus (len=%d)", len(facts.corpus))
19
+ }
20
+ if len(facts.corpus) > triggerEvidenceFileCap+1 {
21
+ t.Fatalf("corpus exceeds cap: %d", len(facts.corpus))
22
+ }
23
+ }
@@ -9,6 +9,7 @@ import (
9
9
  "os"
10
10
  "os/exec"
11
11
  "strings"
12
+ "sync"
12
13
  "time"
13
14
 
14
15
  "github.com/devrites/devrites/internal/devritespaths"
@@ -21,18 +22,27 @@ const (
21
22
  )
22
23
 
23
24
  type cappedGitOutput struct {
24
- bytes.Buffer
25
+ mu sync.Mutex
26
+ buffer bytes.Buffer
25
27
  truncated bool
26
28
  }
27
29
 
30
+ func (w *cappedGitOutput) Len() int { return w.buffer.Len() }
31
+
32
+ func (w *cappedGitOutput) Bytes() []byte { return w.buffer.Bytes() }
33
+
34
+ func (w *cappedGitOutput) String() string { return w.buffer.String() }
35
+
28
36
  func (w *cappedGitOutput) Write(p []byte) (int, error) {
37
+ w.mu.Lock()
38
+ defer w.mu.Unlock()
29
39
  remaining := gitOutputLimit - w.Len()
30
40
  if remaining > 0 {
31
41
  if len(p) > remaining {
32
- _, _ = w.Buffer.Write(p[:remaining])
42
+ _, _ = w.buffer.Write(p[:remaining])
33
43
  w.truncated = true
34
44
  } else {
35
- _, _ = w.Buffer.Write(p)
45
+ _, _ = w.buffer.Write(p)
36
46
  }
37
47
  } else {
38
48
  w.truncated = true
@@ -77,6 +87,7 @@ func runGitCommandIO(dir string, env []string, input []byte, stdout io.Writer, a
77
87
  env = gitenv.Sanitize(env)
78
88
  cmd.Env = append(
79
89
  env,
90
+ "GIT_OPTIONAL_LOCKS=0",
80
91
  "GIT_TERMINAL_PROMPT=0",
81
92
  "GCM_INTERACTIVE=never",
82
93
  "GIT_PAGER=cat",
@@ -92,6 +103,9 @@ func runGitCommandIO(dir string, env []string, input []byte, stdout io.Writer, a
92
103
  cmd.Stderr = &output
93
104
  err := cmd.Run()
94
105
  if err == nil {
106
+ if output.truncated {
107
+ return nil, &gitCommandError{args: args, exitCode: 0, err: errors.New("git output exceeds limit")}
108
+ }
95
109
  return output.Bytes(), nil
96
110
  }
97
111
  code := -1
@@ -1,11 +1,15 @@
1
1
  package lib
2
2
 
3
3
  import (
4
+ "bytes"
5
+ "io"
4
6
  "os"
5
7
  "os/exec"
6
8
  "path/filepath"
7
9
  "strings"
10
+ "sync"
8
11
  "testing"
12
+ "time"
9
13
  )
10
14
 
11
15
  func TestRunGitCommandIgnoresInheritedRepositoryTargets(t *testing.T) {
@@ -30,6 +34,41 @@ func TestRunGitCommandIgnoresInheritedRepositoryTargets(t *testing.T) {
30
34
  }
31
35
  }
32
36
 
37
+ func TestGitStatusPathsLeavesStaleIndexUntouched(t *testing.T) {
38
+ t.Setenv("GIT_OPTIONAL_LOCKS", "")
39
+ if err := os.Unsetenv("GIT_OPTIONAL_LOCKS"); err != nil {
40
+ t.Fatal(err)
41
+ }
42
+ repo := initGitRepository(t, filepath.Join(t.TempDir(), "repo"))
43
+ file := filepath.Join(repo, "a.txt")
44
+ if err := os.WriteFile(file, []byte("one\n"), 0o644); err != nil {
45
+ t.Fatal(err)
46
+ }
47
+ add := exec.Command("git", "-C", repo, "add", "a.txt")
48
+ if out, err := add.CombinedOutput(); err != nil {
49
+ t.Fatalf("git add: %v\n%s", err, out)
50
+ }
51
+ stale := time.Now().Add(-time.Hour)
52
+ if err := os.Chtimes(file, stale, stale); err != nil {
53
+ t.Fatal(err)
54
+ }
55
+ indexPath := filepath.Join(repo, ".git", "index")
56
+ before, err := os.ReadFile(indexPath)
57
+ if err != nil {
58
+ t.Fatal(err)
59
+ }
60
+ if _, err := gitStatusPaths(repo); err != nil {
61
+ t.Fatal(err)
62
+ }
63
+ after, err := os.ReadFile(indexPath)
64
+ if err != nil {
65
+ t.Fatal(err)
66
+ }
67
+ if !bytes.Equal(before, after) {
68
+ t.Fatal("git status rewrote .git/index")
69
+ }
70
+ }
71
+
33
72
  func initGitRepository(t *testing.T, path string) string {
34
73
  t.Helper()
35
74
  if err := os.MkdirAll(path, 0o755); err != nil {
@@ -42,3 +81,68 @@ func initGitRepository(t *testing.T, path string) string {
42
81
  }
43
82
  return path
44
83
  }
84
+
85
+ // cappedGitOutput is installed as both cmd.Stdout and cmd.Stderr; this drives
86
+ // two concurrent writers at it so -race flags any unsynchronized access.
87
+ func TestCappedGitOutputConcurrentWriters(t *testing.T) {
88
+ const writes, size = 2000, 64
89
+ chunk := []byte(strings.Repeat("x", size))
90
+
91
+ var seq cappedGitOutput
92
+ for i := 0; i < 2*writes; i++ {
93
+ _, _ = seq.Write(chunk)
94
+ }
95
+ if seq.Len() != 2*writes*size || seq.truncated {
96
+ t.Fatalf("sequential: got %d bytes truncated=%v, want %d", seq.Len(), seq.truncated, 2*writes*size)
97
+ }
98
+
99
+ var out cappedGitOutput
100
+ var wg sync.WaitGroup
101
+ for w := 0; w < 2; w++ {
102
+ wg.Add(1)
103
+ go func() {
104
+ defer wg.Done()
105
+ for i := 0; i < writes; i++ {
106
+ _, _ = out.Write(chunk)
107
+ }
108
+ }()
109
+ }
110
+ wg.Wait()
111
+ t.Logf("concurrent bytes %d of %d", out.Len(), 2*writes*size)
112
+ }
113
+
114
+ func TestCappedGitOutputBoundsIOCopy(t *testing.T) {
115
+ src := func() io.Reader { return io.LimitReader(zeroReader{}, 25<<20) }
116
+
117
+ var control boundedSecretScanBuffer
118
+ control.limit = gitOutputLimit
119
+ _, _ = io.Copy(&control, src())
120
+ if control.Len() != gitOutputLimit || !control.overflow {
121
+ t.Fatalf("control: got %d bytes overflow=%v, want %d and overflow", control.Len(), control.overflow, gitOutputLimit)
122
+ }
123
+
124
+ var out cappedGitOutput
125
+ _, _ = io.Copy(&out, src())
126
+ if out.Len() > gitOutputLimit || !out.truncated {
127
+ t.Fatalf("got %d bytes truncated=%v, want at most %d and truncated", out.Len(), out.truncated, gitOutputLimit)
128
+ }
129
+ }
130
+
131
+ func TestRunGitCommandRejectsTruncatedOutput(t *testing.T) {
132
+ repo := initGitRepository(t, t.TempDir())
133
+ blob := filepath.Join(t.TempDir(), "big")
134
+ if err := os.WriteFile(blob, bytes.Repeat([]byte("x"), gitOutputLimit+1), 0o600); err != nil {
135
+ t.Fatal(err)
136
+ }
137
+ oid, err := runGitCommand(repo, nil, "hash-object", "-w", blob)
138
+ if err != nil {
139
+ t.Fatal(err)
140
+ }
141
+ if _, err := runGitCommand(repo, nil, "cat-file", "blob", strings.TrimSpace(string(oid))); err == nil {
142
+ t.Fatal("truncated git output returned without error")
143
+ }
144
+ }
145
+
146
+ type zeroReader struct{}
147
+
148
+ func (zeroReader) Read(p []byte) (int, error) { return len(p), nil }
@@ -5,8 +5,9 @@ import (
5
5
  "strings"
6
6
  )
7
7
 
8
- // htmlIDAttrRE matches id="..." or id='...' attributes without a full HTML parser.
9
- var htmlIDAttrRE = regexp.MustCompile(`(?i)\bid\s*=\s*(?:"([^"]*)"|'([^']*)')`)
8
+ // htmlIDAttrRE matches quoted and unquoted id attributes without a full HTML
9
+ // parser. The attribute name is anchored so data-id and similar do not match.
10
+ var htmlIDAttrRE = regexp.MustCompile(`(?i)(?:^|[\s"'/])id\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>` + "`" + `]+))`)
10
11
 
11
12
  // VisualIDConsistency summarizes outline ## ID inventory vs HTML id attributes.
12
13
  //
@@ -29,7 +30,7 @@ func ParseOutlineInventoryIDs(outline string) []string {
29
30
  return parseMarkdownFirstColumnIDs(section)
30
31
  }
31
32
 
32
- // ScanHTMLIDs returns unique id="..." / id='...' attribute values in document order.
33
+ // ScanHTMLIDs returns unique id="..." / id='...' / id=value attribute values in document order.
33
34
  func ScanHTMLIDs(html string) []string {
34
35
  matches := htmlIDAttrRE.FindAllStringSubmatch(html, -1)
35
36
  if len(matches) == 0 {
@@ -42,6 +43,9 @@ func ScanHTMLIDs(html string) []string {
42
43
  if id == "" {
43
44
  id = m[2]
44
45
  }
46
+ if id == "" {
47
+ id = m[3]
48
+ }
45
49
  id = strings.TrimSpace(id)
46
50
  if id == "" {
47
51
  continue
@@ -159,3 +159,31 @@ func TestOpenVisualIDsOkTip(t *testing.T) {
159
159
  t.Fatalf("stdout = %q, want ids=ok tip", stdout.String())
160
160
  }
161
161
  }
162
+
163
+ func TestCheckVisualIDConsistencyAttributeForms(t *testing.T) {
164
+ outline := `## ID inventory
165
+ | HTML id | Meaning |
166
+ | --- | --- |
167
+ | viz-title | Header |
168
+ `
169
+ cases := []struct {
170
+ name string
171
+ html string
172
+ wantMissing []string
173
+ }{
174
+ {"unquoted", `<section id=viz-title></section>`, nil},
175
+ {"unquoted before close", `<section id=viz-title>x</section>`, nil},
176
+ {"single quoted", `<section id='viz-title'></section>`, nil},
177
+ {"data-id is not id", `<section data-id="viz-title"></section>`, []string{"viz-title"}},
178
+ {"hyphenated name ending in id", `<section grid-id=viz-title></section>`, []string{"viz-title"}},
179
+ {"newline before attribute", "<section\nid=viz-title></section>", nil},
180
+ }
181
+ for _, tc := range cases {
182
+ t.Run(tc.name, func(t *testing.T) {
183
+ got := CheckVisualIDConsistency(tc.html, outline).MissingInHTML
184
+ if len(got) != len(tc.wantMissing) || (len(got) == 1 && got[0] != tc.wantMissing[0]) {
185
+ t.Fatalf("MissingInHTML = %#v, want %#v", got, tc.wantMissing)
186
+ }
187
+ })
188
+ }
189
+ }