devrites 3.2.28 → 4.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 (897) hide show
  1. package/CHANGELOG.md +16 -144
  2. package/NOTICE.md +6 -5
  3. package/README.md +187 -95
  4. package/SECURITY.md +103 -79
  5. package/bin/devrites.mjs +140 -24
  6. package/docs/adr/0003-gate-model-hitl-pause.md +1 -1
  7. package/docs/adr/0013-native-codex-agent-orchestration.md +74 -0
  8. package/docs/adr/0014-native-host-hook-boundary.md +64 -0
  9. package/docs/adr/0015-read-only-root-native-orchestration.md +96 -0
  10. package/docs/adr/0016-codex-writer-fail-closed.md +53 -0
  11. package/docs/adr/0017-native-codex-writer-agent.md +63 -0
  12. package/docs/adr/0018-native-sandbox-instruction-writer-boundary.md +66 -0
  13. package/docs/adr/0019-native-boundary-with-deterministic-gates.md +48 -0
  14. package/docs/adr/0020-thin-engine-native-orchestration-boundary.md +54 -0
  15. package/docs/adr/0021-observable-workspace-compatibility.md +49 -0
  16. package/docs/adr/0022-native-orchestration-thin-engine.md +90 -0
  17. package/docs/adr/0023-native-workspace-reads-line-output.md +71 -0
  18. package/docs/adr/0024-native-policy-offline-installer-boundary.md +111 -0
  19. package/docs/adr/0025-evidence-gated-workspace-upgrades.md +64 -0
  20. package/docs/adr/0026-content-bound-proof-and-bounded-inputs.md +169 -0
  21. package/docs/adr/0027-content-bound-build-readiness.md +77 -0
  22. package/docs/adr/README.md +26 -11
  23. package/docs/agents/domain.md +2 -1
  24. package/docs/agents/issue-driven-rites.md +1 -1
  25. package/docs/architecture.md +191 -103
  26. package/docs/candidate-integrity.md +138 -0
  27. package/docs/capability-surface-selection.md +15 -5
  28. package/docs/cli.md +139 -92
  29. package/docs/command-map.md +88 -63
  30. package/docs/engine/commands.md +115 -507
  31. package/docs/engine/state-schema.md +94 -113
  32. package/docs/engine/workspace-schema.md +169 -229
  33. package/docs/flow.md +113 -68
  34. package/docs/harness-compliance.md +29 -56
  35. package/docs/markdown-instruction-upgrade-2026-08-02.md +302 -0
  36. package/docs/orchestration.md +136 -149
  37. package/docs/porting-to-a-new-harness.md +22 -7
  38. package/docs/quick-reference.md +21 -8
  39. package/docs/release.md +47 -4
  40. package/docs/skills.md +111 -72
  41. package/docs/templates/CRITIC_REVIEW_PACKET_TEMPLATE.md +2 -0
  42. package/docs/upstream-workflow-benchmark-2026-08-01.md +655 -0
  43. package/docs/usage.md +99 -65
  44. package/engine/Makefile +1 -2
  45. package/engine/cmd/releasepack/main.go +45 -25
  46. package/engine/cmd/releasepack/main_test.go +69 -0
  47. package/engine/commands.go +8 -258
  48. package/engine/harnessmatrix_test.go +28 -41
  49. package/engine/internal/devritespaths/paths.go +12 -28
  50. package/engine/internal/fsutil/copy.go +8 -0
  51. package/engine/internal/gate/gate.go +104 -105
  52. package/engine/internal/gate/gate_test.go +94 -84
  53. package/engine/internal/gate/readiness_binding.go +203 -0
  54. package/engine/internal/gate/readiness_binding_test.go +271 -0
  55. package/engine/internal/gitenv/env.go +46 -0
  56. package/engine/internal/gitenv/env_test.go +48 -0
  57. package/engine/internal/hostpack/hostpack.go +16 -20
  58. package/engine/internal/hostpack/hostpack_test.go +6 -6
  59. package/engine/internal/install/install.go +289 -511
  60. package/engine/internal/install/install_test.go +218 -306
  61. package/engine/internal/lib/candidate.go +475 -0
  62. package/engine/internal/lib/candidate_test.go +503 -0
  63. package/engine/internal/lib/closeout.go +17 -21
  64. package/engine/internal/lib/closeout_test.go +23 -0
  65. package/engine/internal/lib/cursor_compat_test.go +12 -75
  66. package/engine/internal/lib/evidencefresh.go +58 -47
  67. package/engine/internal/lib/evidencefresh_test.go +120 -0
  68. package/engine/internal/lib/resolve.go +13 -35
  69. package/engine/internal/lib/resolve_remediation_test.go +5 -17
  70. package/engine/internal/lib/secretscan.go +432 -0
  71. package/engine/internal/lib/secretscan_test.go +555 -0
  72. package/engine/internal/lib/util.go +24 -65
  73. package/engine/internal/lib/util_test.go +44 -0
  74. package/engine/internal/markdowntext/markdowntext.go +108 -0
  75. package/engine/internal/markdowntext/markdowntext_test.go +58 -0
  76. package/engine/internal/markdowntext/testdata/structural.json +27 -0
  77. package/engine/internal/reason/reason.go +2 -123
  78. package/engine/internal/reason/reason_test.go +4 -2
  79. package/engine/internal/rootfacts/facts.go +6 -8
  80. package/engine/internal/rootfacts/facts_test.go +20 -0
  81. package/engine/internal/state/cmd/workflowmanifest/main.go +10 -12
  82. package/engine/internal/state/cursor.go +53 -14
  83. package/engine/internal/state/cursor_test.go +57 -0
  84. package/engine/internal/state/feature.go +64 -154
  85. package/engine/internal/state/schema.go +24 -50
  86. package/engine/internal/state/state_test.go +151 -140
  87. package/engine/internal/state/status.go +4 -17
  88. package/engine/internal/state/workflow_manifest.json +9 -89
  89. package/engine/main.go +73 -502
  90. package/engine/root_routing_test.go +183 -212
  91. package/engine/testdata/fixtures/basic/devrites-root/{features/auth-tokens/feature.md → work/auth-tokens/README.md} +0 -1
  92. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/architecture.md +3 -0
  93. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/assumptions.md +3 -0
  94. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/brief.md +3 -0
  95. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decision-coverage.md +3 -0
  96. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/eng-review.md +3 -0
  97. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/questions.md +3 -0
  98. package/engine/testdata/fixtures/basic/devrites-root/{features/auth-tokens/status.md → work/auth-tokens/state.md} +3 -0
  99. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/test-plan.md +3 -0
  100. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/traceability.md +3 -0
  101. package/engine/testdata/fixtures/basic/devrites-root/{features/search-ranking/feature.md → work/search-ranking/README.md} +0 -1
  102. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/assumptions.md +3 -0
  103. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/brief.md +3 -0
  104. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/decisions.md +3 -0
  105. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/questions.md +3 -0
  106. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/state.md +2 -0
  107. package/engine/testdata/golden/TestParityCloseOut/active_pointed_elsewhere.golden +1 -1
  108. package/engine/testdata/golden/TestParityCloseOut/active_slug_cleared.golden +1 -1
  109. package/engine/tests/adr_0003_gate_exit_code_test.go +2 -2
  110. package/engine/tests/adr_0011_define_plan_test.go +2 -2
  111. package/engine/tests/adr_0027_readiness_binding_test.go +106 -0
  112. package/engine/tests/cli_test.go +24 -107
  113. package/engine/tests/gate_test.go +177 -200
  114. package/engine/tests/meta_test.go +5 -35
  115. package/engine/tests/parity_closeout_test.go +12 -12
  116. package/engine/tests/parity_resolve_test.go +6 -16
  117. package/engine/tests/parity_test.go +8 -302
  118. package/install.sh +201 -34
  119. package/pack/.claude/agents/devrites-code-reviewer.md +9 -18
  120. package/pack/.claude/agents/devrites-devex-reviewer.md +10 -18
  121. package/pack/.claude/agents/devrites-doubt-reviewer.md +10 -20
  122. package/pack/.claude/agents/devrites-evidence-scout.md +14 -26
  123. package/pack/.claude/agents/devrites-frontend-reviewer.md +9 -15
  124. package/pack/.claude/agents/devrites-performance-reviewer.md +13 -21
  125. package/pack/.claude/agents/devrites-plan-drafter.md +24 -28
  126. package/pack/.claude/agents/devrites-plan-reviewer.md +30 -47
  127. package/pack/.claude/agents/devrites-proof-runner.md +41 -47
  128. package/pack/.claude/agents/devrites-retrospector.md +34 -79
  129. package/pack/.claude/agents/devrites-security-auditor.md +9 -17
  130. package/pack/.claude/agents/devrites-simplifier-reviewer.md +9 -18
  131. package/pack/.claude/agents/devrites-slice-wright.md +44 -62
  132. package/pack/.claude/agents/devrites-spec-reviewer.md +38 -50
  133. package/pack/.claude/agents/devrites-strategy-reviewer.md +10 -19
  134. package/pack/.claude/agents/devrites-test-analyst.md +22 -21
  135. package/pack/.claude/agents/devrites-upgrade-planner.md +52 -71
  136. package/pack/.claude/settings.json +12 -100
  137. package/pack/.claude/skills/devrites-api-interface/SKILL.md +1 -2
  138. package/pack/.claude/skills/devrites-audit/SKILL.md +6 -9
  139. package/pack/.claude/skills/devrites-browser-proof/SKILL.md +0 -1
  140. package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +21 -27
  141. package/pack/.claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +22 -33
  142. package/pack/.claude/skills/devrites-doubt/SKILL.md +4 -6
  143. package/pack/.claude/skills/devrites-frontend-craft/SKILL.md +1 -2
  144. package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +2 -1
  145. package/pack/.claude/skills/devrites-interview/SKILL.md +31 -36
  146. package/pack/.claude/skills/devrites-lib/SKILL.md +37 -66
  147. package/pack/.claude/skills/devrites-lib/reference/candidate-integrity.md +51 -0
  148. package/pack/.claude/skills/devrites-lib/reference/intent-map.md +20 -12
  149. package/pack/.claude/skills/devrites-lib/reference/orchestration-profiles.md +22 -0
  150. package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +35 -110
  151. package/pack/.claude/skills/devrites-lib/reference/reply-contract.md +26 -93
  152. package/pack/.claude/skills/devrites-lib/reference/standards/README.md +6 -3
  153. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +43 -34
  154. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +90 -216
  155. package/pack/.claude/skills/devrites-lib/reference/standards/anti-patterns.md +1 -1
  156. package/pack/.claude/skills/devrites-lib/reference/standards/code-review.md +9 -28
  157. package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +13 -11
  158. package/pack/.claude/skills/devrites-lib/reference/standards/core.md +59 -54
  159. package/pack/.claude/skills/devrites-lib/reference/standards/hooks.md +3 -5
  160. package/pack/.claude/skills/devrites-lib/reference/standards/principles.md +29 -143
  161. package/pack/.claude/skills/devrites-lib/reference/standards/release/ship-checklist.md +5 -6
  162. package/pack/.claude/skills/devrites-lib/reference/standards/security.md +13 -31
  163. package/pack/.claude/skills/devrites-lib/reference/standards/skill-authoring.md +112 -82
  164. package/pack/.claude/skills/devrites-lib/reference/standards/spec-grammar.md +71 -45
  165. package/pack/.claude/skills/devrites-lib/reference/standards/testing.md +22 -11
  166. package/pack/.claude/skills/devrites-lib/reference/standards/tooling.md +15 -24
  167. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +106 -37
  168. package/pack/.claude/skills/devrites-prose-craft/SKILL.md +3 -4
  169. package/pack/.claude/skills/devrites-source-driven/SKILL.md +3 -4
  170. package/pack/.claude/skills/devrites-ux-shape/SKILL.md +3 -3
  171. package/pack/.claude/skills/rite/SKILL.md +12 -13
  172. package/pack/.claude/skills/rite/reference/menu.md +11 -11
  173. package/pack/.claude/skills/rite-adopt/SKILL.md +29 -84
  174. package/pack/.claude/skills/rite-adopt/reference/adoption.md +16 -50
  175. package/pack/.claude/skills/rite-autocomplete/SKILL.md +65 -54
  176. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +24 -17
  177. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +18 -21
  178. package/pack/.claude/skills/rite-build/SKILL.md +28 -34
  179. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +36 -34
  180. package/pack/.claude/skills/rite-build/reference/anti-patterns.md +5 -19
  181. package/pack/.claude/skills/rite-build/reference/checkpoint-protocol.md +10 -9
  182. package/pack/.claude/skills/rite-build/reference/checkpoint.md +17 -17
  183. package/pack/.claude/skills/rite-build/reference/frontend-trigger.md +3 -3
  184. package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +11 -14
  185. package/pack/.claude/skills/rite-build/reference/output.md +14 -24
  186. package/pack/.claude/skills/rite-build/reference/phase-contract.md +49 -188
  187. package/pack/.claude/skills/rite-build/reference/spec-drift-guard.md +1 -1
  188. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +43 -133
  189. package/pack/.claude/skills/rite-clarify/SKILL.md +46 -40
  190. package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +4 -10
  191. package/pack/.claude/skills/rite-converge/SKILL.md +9 -33
  192. package/pack/.claude/skills/rite-converge/reference/convergence-assessment.md +2 -2
  193. package/pack/.claude/skills/rite-customize/SKILL.md +34 -50
  194. package/pack/.claude/skills/rite-define/SKILL.md +34 -58
  195. package/pack/.claude/skills/rite-define/reference/plan-template.md +15 -0
  196. package/pack/.claude/skills/rite-doctor/SKILL.md +52 -64
  197. package/pack/.claude/skills/rite-dogfood/SKILL.md +1 -2
  198. package/pack/.claude/skills/rite-explain/SKILL.md +1 -20
  199. package/pack/.claude/skills/rite-frame/SKILL.md +1 -7
  200. package/pack/.claude/skills/rite-frame/reference/failure-modes.md +1 -1
  201. package/pack/.claude/skills/rite-handoff/SKILL.md +1 -2
  202. package/pack/.claude/skills/rite-handoff/reference/handoff-template.md +1 -1
  203. package/pack/.claude/skills/rite-learn/SKILL.md +44 -104
  204. package/pack/.claude/skills/rite-plan/SKILL.md +14 -26
  205. package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +4 -1
  206. package/pack/.claude/skills/rite-polish/SKILL.md +20 -28
  207. package/pack/.claude/skills/rite-polish/reference/adr-promotion.md +11 -0
  208. package/pack/{generated/claude/skills/rite-ship → .claude/skills/rite-polish}/reference/design-memory.md +23 -21
  209. package/pack/.claude/skills/rite-polish/reference/ledger.md +62 -0
  210. package/pack/.claude/skills/rite-pov/SKILL.md +28 -32
  211. package/pack/.claude/skills/rite-pr-feedback/SKILL.md +0 -1
  212. package/pack/.claude/skills/rite-pressure-test/SKILL.md +6 -13
  213. package/pack/.claude/skills/rite-prototype/SKILL.md +0 -6
  214. package/pack/.claude/skills/rite-prove/SKILL.md +73 -68
  215. package/pack/.claude/skills/rite-prove/reference/acceptance-proof.md +34 -30
  216. package/pack/.claude/skills/rite-prove/reference/test-command-discovery.md +15 -14
  217. package/pack/.claude/skills/rite-quick/SKILL.md +5 -19
  218. package/pack/.claude/skills/rite-resolve/SKILL.md +4 -21
  219. package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +2 -2
  220. package/pack/.claude/skills/rite-review/SKILL.md +34 -57
  221. package/pack/.claude/skills/rite-seal/SKILL.md +54 -87
  222. package/pack/.claude/skills/rite-seal/reference/anti-patterns.md +2 -2
  223. package/pack/.claude/skills/rite-seal/reference/final-evidence.md +31 -56
  224. package/pack/.claude/skills/rite-seal/reference/go-no-go.md +27 -51
  225. package/pack/.claude/skills/rite-seal/reference/output.md +2 -4
  226. package/pack/.claude/skills/rite-seal/reference/phase-contract.md +42 -140
  227. package/pack/.claude/skills/rite-seal/reference/risk-and-rollback.md +2 -2
  228. package/pack/.claude/skills/rite-seal/reference/seal-template.md +17 -28
  229. package/pack/.claude/skills/rite-ship/SKILL.md +65 -93
  230. package/pack/.claude/skills/rite-ship/reference/anti-patterns.md +4 -1
  231. package/pack/.claude/skills/rite-ship/reference/close-out.md +4 -12
  232. package/pack/.claude/skills/rite-ship/reference/git-ship.md +86 -48
  233. package/pack/.claude/skills/rite-ship/reference/ship-template.md +22 -16
  234. package/pack/.claude/skills/rite-spec/SKILL.md +62 -95
  235. package/pack/.claude/skills/rite-spec/reference/investigation.md +1 -4
  236. package/pack/.claude/skills/rite-spec/reference/question-protocol.md +21 -20
  237. package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +16 -17
  238. package/pack/.claude/skills/rite-spec/reference/spec-template.md +47 -49
  239. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +28 -13
  240. package/pack/.claude/skills/rite-status/SKILL.md +30 -88
  241. package/pack/.claude/skills/rite-temper/SKILL.md +12 -31
  242. package/pack/.claude/skills/rite-upgrade/SKILL.md +86 -101
  243. package/pack/.claude/skills/rite-vet/SKILL.md +88 -117
  244. package/pack/.claude/skills/rite-vet/reference/artifacts.md +56 -50
  245. package/pack/.claude/skills/rite-vet/reference/cross-model.md +15 -39
  246. package/pack/.claude/skills/rite-vet/reference/depth.md +2 -2
  247. package/pack/.claude/skills/rite-vet/reference/review-axes.md +3 -6
  248. package/pack/.claude/skills/rite-zoom-out/SKILL.md +0 -6
  249. package/pack/generated/README.md +2 -2
  250. package/pack/generated/claude/agents/devrites-code-reviewer.md +9 -18
  251. package/pack/generated/claude/agents/devrites-devex-reviewer.md +10 -18
  252. package/pack/generated/claude/agents/devrites-doubt-reviewer.md +10 -20
  253. package/pack/generated/claude/agents/devrites-evidence-scout.md +14 -26
  254. package/pack/generated/claude/agents/devrites-frontend-reviewer.md +9 -15
  255. package/pack/generated/claude/agents/devrites-performance-reviewer.md +13 -21
  256. package/pack/generated/claude/agents/devrites-plan-drafter.md +24 -28
  257. package/pack/generated/claude/agents/devrites-plan-reviewer.md +30 -47
  258. package/pack/generated/claude/agents/devrites-proof-runner.md +41 -47
  259. package/pack/generated/claude/agents/devrites-retrospector.md +34 -79
  260. package/pack/generated/claude/agents/devrites-security-auditor.md +9 -17
  261. package/pack/generated/claude/agents/devrites-simplifier-reviewer.md +9 -18
  262. package/pack/generated/claude/agents/devrites-slice-wright.md +44 -62
  263. package/pack/generated/claude/agents/devrites-spec-reviewer.md +38 -50
  264. package/pack/generated/claude/agents/devrites-strategy-reviewer.md +10 -19
  265. package/pack/generated/claude/agents/devrites-test-analyst.md +22 -21
  266. package/pack/generated/claude/agents/devrites-upgrade-planner.md +52 -71
  267. package/pack/generated/claude/settings.json +12 -100
  268. package/pack/generated/claude/skills/devrites-api-interface/SKILL.md +1 -2
  269. package/pack/generated/claude/skills/devrites-audit/SKILL.md +6 -9
  270. package/pack/generated/claude/skills/devrites-browser-proof/SKILL.md +0 -1
  271. package/pack/generated/claude/skills/devrites-debug-recovery/SKILL.md +21 -27
  272. package/pack/generated/claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +22 -33
  273. package/pack/generated/claude/skills/devrites-doubt/SKILL.md +4 -6
  274. package/pack/generated/claude/skills/devrites-frontend-craft/SKILL.md +1 -2
  275. package/pack/generated/claude/skills/devrites-frontend-craft/reference/design-references.md +2 -1
  276. package/pack/generated/claude/skills/devrites-interview/SKILL.md +31 -36
  277. package/pack/generated/claude/skills/devrites-lib/SKILL.md +37 -66
  278. package/pack/generated/claude/skills/devrites-lib/reference/candidate-integrity.md +51 -0
  279. package/pack/generated/claude/skills/devrites-lib/reference/intent-map.md +20 -12
  280. package/pack/generated/claude/skills/devrites-lib/reference/orchestration-profiles.md +22 -0
  281. package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +35 -110
  282. package/pack/generated/claude/skills/devrites-lib/reference/reply-contract.md +26 -93
  283. package/pack/generated/claude/skills/devrites-lib/reference/standards/README.md +6 -3
  284. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +43 -34
  285. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +90 -216
  286. package/pack/generated/claude/skills/devrites-lib/reference/standards/anti-patterns.md +1 -1
  287. package/pack/generated/claude/skills/devrites-lib/reference/standards/code-review.md +9 -28
  288. package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +13 -11
  289. package/pack/generated/claude/skills/devrites-lib/reference/standards/core.md +59 -54
  290. package/pack/generated/claude/skills/devrites-lib/reference/standards/hooks.md +3 -5
  291. package/pack/generated/claude/skills/devrites-lib/reference/standards/principles.md +29 -143
  292. package/pack/generated/claude/skills/devrites-lib/reference/standards/release/ship-checklist.md +5 -6
  293. package/pack/generated/claude/skills/devrites-lib/reference/standards/security.md +13 -31
  294. package/pack/generated/claude/skills/devrites-lib/reference/standards/skill-authoring.md +112 -82
  295. package/pack/generated/claude/skills/devrites-lib/reference/standards/spec-grammar.md +71 -45
  296. package/pack/generated/claude/skills/devrites-lib/reference/standards/testing.md +22 -11
  297. package/pack/generated/claude/skills/devrites-lib/reference/standards/tooling.md +15 -24
  298. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +106 -37
  299. package/pack/generated/claude/skills/devrites-prose-craft/SKILL.md +3 -4
  300. package/pack/generated/claude/skills/devrites-source-driven/SKILL.md +3 -4
  301. package/pack/generated/claude/skills/devrites-ux-shape/SKILL.md +3 -3
  302. package/pack/generated/claude/skills/rite/SKILL.md +12 -13
  303. package/pack/generated/claude/skills/rite/reference/menu.md +11 -11
  304. package/pack/generated/claude/skills/rite-adopt/SKILL.md +29 -84
  305. package/pack/generated/claude/skills/rite-adopt/reference/adoption.md +16 -50
  306. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +65 -54
  307. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +24 -17
  308. package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +18 -21
  309. package/pack/generated/claude/skills/rite-build/SKILL.md +28 -34
  310. package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +36 -34
  311. package/pack/generated/claude/skills/rite-build/reference/anti-patterns.md +5 -19
  312. package/pack/generated/claude/skills/rite-build/reference/checkpoint-protocol.md +10 -9
  313. package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +17 -17
  314. package/pack/generated/claude/skills/rite-build/reference/frontend-trigger.md +3 -3
  315. package/pack/generated/claude/skills/rite-build/reference/one-slice-cycle.md +11 -14
  316. package/pack/generated/claude/skills/rite-build/reference/output.md +14 -24
  317. package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +49 -188
  318. package/pack/generated/claude/skills/rite-build/reference/spec-drift-guard.md +1 -1
  319. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +43 -133
  320. package/pack/generated/claude/skills/rite-clarify/SKILL.md +46 -40
  321. package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +4 -10
  322. package/pack/generated/claude/skills/rite-converge/SKILL.md +9 -33
  323. package/pack/generated/claude/skills/rite-converge/reference/convergence-assessment.md +2 -2
  324. package/pack/generated/claude/skills/rite-customize/SKILL.md +34 -50
  325. package/pack/generated/claude/skills/rite-define/SKILL.md +34 -58
  326. package/pack/generated/claude/skills/rite-define/reference/plan-template.md +15 -0
  327. package/pack/generated/claude/skills/rite-doctor/SKILL.md +52 -64
  328. package/pack/generated/claude/skills/rite-dogfood/SKILL.md +1 -2
  329. package/pack/generated/claude/skills/rite-explain/SKILL.md +1 -20
  330. package/pack/generated/claude/skills/rite-frame/SKILL.md +1 -7
  331. package/pack/generated/claude/skills/rite-frame/reference/failure-modes.md +1 -1
  332. package/pack/generated/claude/skills/rite-handoff/SKILL.md +1 -2
  333. package/pack/generated/claude/skills/rite-handoff/reference/handoff-template.md +1 -1
  334. package/pack/generated/claude/skills/rite-learn/SKILL.md +44 -104
  335. package/pack/generated/claude/skills/rite-plan/SKILL.md +14 -26
  336. package/pack/generated/claude/skills/rite-plan/reference/task-breakdown.md +4 -1
  337. package/pack/generated/claude/skills/rite-polish/SKILL.md +20 -28
  338. package/pack/generated/claude/skills/rite-polish/reference/adr-promotion.md +11 -0
  339. package/pack/generated/{codex/skills/rite-ship → claude/skills/rite-polish}/reference/design-memory.md +23 -21
  340. package/pack/generated/claude/skills/rite-polish/reference/ledger.md +62 -0
  341. package/pack/generated/claude/skills/rite-pov/SKILL.md +28 -32
  342. package/pack/generated/claude/skills/rite-pr-feedback/SKILL.md +0 -1
  343. package/pack/generated/claude/skills/rite-pressure-test/SKILL.md +6 -13
  344. package/pack/generated/claude/skills/rite-prototype/SKILL.md +0 -6
  345. package/pack/generated/claude/skills/rite-prove/SKILL.md +73 -68
  346. package/pack/generated/claude/skills/rite-prove/reference/acceptance-proof.md +34 -30
  347. package/pack/generated/claude/skills/rite-prove/reference/test-command-discovery.md +15 -14
  348. package/pack/generated/claude/skills/rite-quick/SKILL.md +5 -19
  349. package/pack/generated/claude/skills/rite-resolve/SKILL.md +4 -21
  350. package/pack/generated/claude/skills/rite-resolve/reference/answer-protocol.md +2 -2
  351. package/pack/generated/claude/skills/rite-review/SKILL.md +34 -57
  352. package/pack/generated/claude/skills/rite-seal/SKILL.md +54 -87
  353. package/pack/generated/claude/skills/rite-seal/reference/anti-patterns.md +2 -2
  354. package/pack/generated/claude/skills/rite-seal/reference/final-evidence.md +31 -56
  355. package/pack/generated/claude/skills/rite-seal/reference/go-no-go.md +27 -51
  356. package/pack/generated/claude/skills/rite-seal/reference/output.md +2 -4
  357. package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +42 -140
  358. package/pack/generated/claude/skills/rite-seal/reference/risk-and-rollback.md +2 -2
  359. package/pack/generated/claude/skills/rite-seal/reference/seal-template.md +17 -28
  360. package/pack/generated/claude/skills/rite-ship/SKILL.md +65 -93
  361. package/pack/generated/claude/skills/rite-ship/reference/anti-patterns.md +4 -1
  362. package/pack/generated/claude/skills/rite-ship/reference/close-out.md +4 -12
  363. package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +86 -48
  364. package/pack/generated/claude/skills/rite-ship/reference/ship-template.md +22 -16
  365. package/pack/generated/claude/skills/rite-spec/SKILL.md +62 -95
  366. package/pack/generated/claude/skills/rite-spec/reference/investigation.md +1 -4
  367. package/pack/generated/claude/skills/rite-spec/reference/question-protocol.md +21 -20
  368. package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +16 -17
  369. package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +47 -49
  370. package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +28 -13
  371. package/pack/generated/claude/skills/rite-status/SKILL.md +30 -88
  372. package/pack/generated/claude/skills/rite-temper/SKILL.md +12 -31
  373. package/pack/generated/claude/skills/rite-upgrade/SKILL.md +86 -101
  374. package/pack/generated/claude/skills/rite-vet/SKILL.md +88 -117
  375. package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +56 -50
  376. package/pack/generated/claude/skills/rite-vet/reference/cross-model.md +15 -39
  377. package/pack/generated/claude/skills/rite-vet/reference/depth.md +2 -2
  378. package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +3 -6
  379. package/pack/generated/claude/skills/rite-zoom-out/SKILL.md +0 -6
  380. package/pack/generated/codex/AGENTS.md +5 -4
  381. package/pack/generated/codex/agents/devrites-code-reviewer.toml +8 -27
  382. package/pack/generated/codex/agents/devrites-devex-reviewer.toml +9 -27
  383. package/pack/generated/codex/agents/devrites-doubt-reviewer.toml +9 -29
  384. package/pack/generated/codex/agents/devrites-evidence-scout.toml +14 -36
  385. package/pack/generated/codex/agents/devrites-frontend-reviewer.toml +8 -24
  386. package/pack/generated/codex/agents/devrites-performance-reviewer.toml +12 -30
  387. package/pack/generated/codex/agents/devrites-plan-drafter.toml +24 -38
  388. package/pack/generated/codex/agents/devrites-plan-reviewer.toml +30 -57
  389. package/pack/generated/codex/agents/devrites-proof-runner.toml +41 -57
  390. package/pack/generated/codex/agents/devrites-retrospector.toml +34 -89
  391. package/pack/generated/codex/agents/devrites-security-auditor.toml +8 -26
  392. package/pack/generated/codex/agents/devrites-simplifier-reviewer.toml +8 -27
  393. package/pack/generated/codex/agents/devrites-slice-wright.toml +44 -71
  394. package/pack/generated/codex/agents/devrites-spec-reviewer.toml +38 -60
  395. package/pack/generated/codex/agents/devrites-strategy-reviewer.toml +9 -28
  396. package/pack/generated/codex/agents/devrites-test-analyst.toml +21 -30
  397. package/pack/generated/codex/agents/devrites-upgrade-planner.toml +52 -81
  398. package/pack/generated/codex/config.toml +7 -0
  399. package/pack/generated/codex/skills/devrites-api-interface/SKILL.md +1 -21
  400. package/pack/generated/codex/skills/devrites-audit/SKILL.md +6 -28
  401. package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +1 -21
  402. package/pack/generated/codex/skills/devrites-debug-recovery/SKILL.md +21 -46
  403. package/pack/generated/codex/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +22 -33
  404. package/pack/generated/codex/skills/devrites-doubt/SKILL.md +4 -25
  405. package/pack/generated/codex/skills/devrites-frontend-craft/SKILL.md +1 -21
  406. package/pack/generated/codex/skills/devrites-frontend-craft/reference/design-references.md +2 -1
  407. package/pack/generated/codex/skills/devrites-interview/SKILL.md +32 -56
  408. package/pack/generated/codex/skills/devrites-lib/SKILL.md +38 -86
  409. package/pack/generated/codex/skills/devrites-lib/reference/candidate-integrity.md +51 -0
  410. package/pack/generated/codex/skills/devrites-lib/reference/intent-map.md +20 -12
  411. package/pack/generated/codex/skills/devrites-lib/reference/orchestration-profiles.md +22 -0
  412. package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +35 -110
  413. package/pack/generated/codex/skills/devrites-lib/reference/reply-contract.md +26 -93
  414. package/pack/generated/codex/skills/devrites-lib/reference/standards/README.md +6 -3
  415. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +43 -34
  416. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +90 -216
  417. package/pack/generated/codex/skills/devrites-lib/reference/standards/anti-patterns.md +1 -1
  418. package/pack/generated/codex/skills/devrites-lib/reference/standards/code-review.md +9 -28
  419. package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +13 -11
  420. package/pack/generated/codex/skills/devrites-lib/reference/standards/core.md +59 -54
  421. package/pack/generated/codex/skills/devrites-lib/reference/standards/hooks.md +3 -5
  422. package/pack/generated/codex/skills/devrites-lib/reference/standards/principles.md +29 -143
  423. package/pack/generated/codex/skills/devrites-lib/reference/standards/release/ship-checklist.md +5 -6
  424. package/pack/generated/codex/skills/devrites-lib/reference/standards/security.md +13 -31
  425. package/pack/generated/codex/skills/devrites-lib/reference/standards/skill-authoring.md +112 -82
  426. package/pack/generated/codex/skills/devrites-lib/reference/standards/spec-grammar.md +71 -45
  427. package/pack/generated/codex/skills/devrites-lib/reference/standards/testing.md +22 -11
  428. package/pack/generated/codex/skills/devrites-lib/reference/standards/tooling.md +15 -24
  429. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +106 -37
  430. package/pack/generated/codex/skills/devrites-prose-craft/SKILL.md +3 -23
  431. package/pack/generated/codex/skills/devrites-source-driven/SKILL.md +3 -23
  432. package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +3 -22
  433. package/pack/generated/codex/skills/rite/SKILL.md +12 -32
  434. package/pack/generated/codex/skills/rite/reference/menu.md +11 -11
  435. package/pack/generated/codex/skills/rite-adopt/SKILL.md +29 -103
  436. package/pack/generated/codex/skills/rite-adopt/reference/adoption.md +16 -50
  437. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +65 -73
  438. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +24 -17
  439. package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +18 -21
  440. package/pack/generated/codex/skills/rite-build/SKILL.md +28 -53
  441. package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +36 -34
  442. package/pack/generated/codex/skills/rite-build/reference/anti-patterns.md +5 -19
  443. package/pack/generated/codex/skills/rite-build/reference/checkpoint-protocol.md +10 -9
  444. package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +17 -17
  445. package/pack/generated/codex/skills/rite-build/reference/frontend-trigger.md +3 -3
  446. package/pack/generated/codex/skills/rite-build/reference/one-slice-cycle.md +11 -14
  447. package/pack/generated/codex/skills/rite-build/reference/output.md +14 -24
  448. package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +49 -188
  449. package/pack/generated/codex/skills/rite-build/reference/spec-drift-guard.md +1 -1
  450. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +43 -133
  451. package/pack/generated/codex/skills/rite-clarify/SKILL.md +46 -59
  452. package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +4 -10
  453. package/pack/generated/codex/skills/rite-converge/SKILL.md +9 -52
  454. package/pack/generated/codex/skills/rite-converge/reference/convergence-assessment.md +2 -2
  455. package/pack/generated/codex/skills/rite-customize/SKILL.md +32 -67
  456. package/pack/generated/codex/skills/rite-define/SKILL.md +34 -77
  457. package/pack/generated/codex/skills/rite-define/reference/plan-template.md +15 -0
  458. package/pack/generated/codex/skills/rite-doctor/SKILL.md +52 -83
  459. package/pack/generated/codex/skills/rite-dogfood/SKILL.md +1 -21
  460. package/pack/generated/codex/skills/rite-explain/SKILL.md +1 -39
  461. package/pack/generated/codex/skills/rite-frame/SKILL.md +1 -26
  462. package/pack/generated/codex/skills/rite-frame/reference/failure-modes.md +1 -1
  463. package/pack/generated/codex/skills/rite-handoff/SKILL.md +1 -21
  464. package/pack/generated/codex/skills/rite-handoff/reference/handoff-template.md +1 -1
  465. package/pack/generated/codex/skills/rite-learn/SKILL.md +44 -123
  466. package/pack/generated/codex/skills/rite-plan/SKILL.md +14 -45
  467. package/pack/generated/codex/skills/rite-plan/reference/task-breakdown.md +4 -1
  468. package/pack/generated/codex/skills/rite-polish/SKILL.md +20 -47
  469. package/pack/generated/codex/skills/rite-polish/reference/adr-promotion.md +11 -0
  470. package/pack/{.claude/skills/rite-ship → generated/codex/skills/rite-polish}/reference/design-memory.md +23 -21
  471. package/pack/generated/codex/skills/rite-polish/reference/ledger.md +62 -0
  472. package/pack/generated/codex/skills/rite-pov/SKILL.md +28 -51
  473. package/pack/generated/codex/skills/rite-pr-feedback/SKILL.md +0 -20
  474. package/pack/generated/codex/skills/rite-pressure-test/SKILL.md +6 -32
  475. package/pack/generated/codex/skills/rite-prototype/SKILL.md +0 -25
  476. package/pack/generated/codex/skills/rite-prove/SKILL.md +73 -87
  477. package/pack/generated/codex/skills/rite-prove/reference/acceptance-proof.md +34 -30
  478. package/pack/generated/codex/skills/rite-prove/reference/test-command-discovery.md +15 -14
  479. package/pack/generated/codex/skills/rite-quick/SKILL.md +5 -38
  480. package/pack/generated/codex/skills/rite-resolve/SKILL.md +4 -40
  481. package/pack/generated/codex/skills/rite-resolve/reference/answer-protocol.md +2 -2
  482. package/pack/generated/codex/skills/rite-review/SKILL.md +34 -76
  483. package/pack/generated/codex/skills/rite-seal/SKILL.md +51 -103
  484. package/pack/generated/codex/skills/rite-seal/reference/anti-patterns.md +2 -2
  485. package/pack/generated/codex/skills/rite-seal/reference/final-evidence.md +31 -56
  486. package/pack/generated/codex/skills/rite-seal/reference/go-no-go.md +27 -51
  487. package/pack/generated/codex/skills/rite-seal/reference/output.md +2 -4
  488. package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +42 -140
  489. package/pack/generated/codex/skills/rite-seal/reference/risk-and-rollback.md +2 -2
  490. package/pack/generated/codex/skills/rite-seal/reference/seal-template.md +17 -28
  491. package/pack/generated/codex/skills/rite-ship/SKILL.md +65 -112
  492. package/pack/generated/codex/skills/rite-ship/reference/anti-patterns.md +4 -1
  493. package/pack/generated/codex/skills/rite-ship/reference/close-out.md +4 -12
  494. package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +86 -48
  495. package/pack/generated/codex/skills/rite-ship/reference/ship-template.md +22 -16
  496. package/pack/generated/codex/skills/rite-spec/SKILL.md +62 -114
  497. package/pack/generated/codex/skills/rite-spec/reference/investigation.md +1 -4
  498. package/pack/generated/codex/skills/rite-spec/reference/question-protocol.md +21 -20
  499. package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +16 -17
  500. package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +47 -49
  501. package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +28 -13
  502. package/pack/generated/codex/skills/rite-status/SKILL.md +30 -107
  503. package/pack/generated/codex/skills/rite-temper/SKILL.md +12 -50
  504. package/pack/generated/codex/skills/rite-upgrade/SKILL.md +86 -120
  505. package/pack/generated/codex/skills/rite-vet/SKILL.md +88 -136
  506. package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +56 -50
  507. package/pack/generated/codex/skills/rite-vet/reference/cross-model.md +15 -39
  508. package/pack/generated/codex/skills/rite-vet/reference/depth.md +2 -2
  509. package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +3 -6
  510. package/pack/generated/codex/skills/rite-zoom-out/SKILL.md +0 -25
  511. package/package.json +6 -5
  512. package/scripts/build-host-artifacts.sh +5 -9
  513. package/scripts/codex-generate.sh +18 -278
  514. package/scripts/install-lib.sh +121 -34
  515. package/uninstall.sh +19 -17
  516. package/update.sh +26 -18
  517. package/docs/engine/agent-contract.md +0 -172
  518. package/docs/extensions.md +0 -178
  519. package/engine/git_guard.go +0 -187
  520. package/engine/git_guard_test.go +0 -283
  521. package/engine/harnessmatrix.go +0 -60
  522. package/engine/hookpolicy.go +0 -113
  523. package/engine/hookpolicy_test.go +0 -160
  524. package/engine/hooks.go +0 -677
  525. package/engine/hooks_agent_dispatch.go +0 -1726
  526. package/engine/hooks_events_test.go +0 -431
  527. package/engine/hooks_workspace.go +0 -1196
  528. package/engine/internal/doctor/doctor.go +0 -306
  529. package/engine/internal/doctor/doctor_test.go +0 -252
  530. package/engine/internal/forge/forge.go +0 -938
  531. package/engine/internal/forge/forge_test.go +0 -576
  532. package/engine/internal/forge/git.go +0 -245
  533. package/engine/internal/forge/liveness_unix.go +0 -48
  534. package/engine/internal/forge/liveness_windows.go +0 -67
  535. package/engine/internal/forge/manifest.go +0 -402
  536. package/engine/internal/harness/compliance.go +0 -96
  537. package/engine/internal/harness/harness.go +0 -301
  538. package/engine/internal/harness/harness_test.go +0 -124
  539. package/engine/internal/iohooks/detach_other.go +0 -11
  540. package/engine/internal/iohooks/detach_unix.go +0 -11
  541. package/engine/internal/iohooks/iohooks.go +0 -839
  542. package/engine/internal/iohooks/iohooks_test.go +0 -561
  543. package/engine/internal/lib/adoption.go +0 -659
  544. package/engine/internal/lib/adoption_test.go +0 -121
  545. package/engine/internal/lib/analyze.go +0 -232
  546. package/engine/internal/lib/archivesearch.go +0 -125
  547. package/engine/internal/lib/archivesearch_test.go +0 -138
  548. package/engine/internal/lib/budget.go +0 -172
  549. package/engine/internal/lib/buildreadiness.go +0 -111
  550. package/engine/internal/lib/checkacceptance.go +0 -176
  551. package/engine/internal/lib/clarifyreturn.go +0 -91
  552. package/engine/internal/lib/clarifyreturn_test.go +0 -123
  553. package/engine/internal/lib/command_other.go +0 -7
  554. package/engine/internal/lib/command_unix.go +0 -24
  555. package/engine/internal/lib/context.go +0 -280
  556. package/engine/internal/lib/conventions.go +0 -449
  557. package/engine/internal/lib/coverage.go +0 -145
  558. package/engine/internal/lib/dispatchwaive.go +0 -31
  559. package/engine/internal/lib/dispatchwaive_test.go +0 -23
  560. package/engine/internal/lib/doubtcoverage.go +0 -78
  561. package/engine/internal/lib/extensions.go +0 -622
  562. package/engine/internal/lib/extensions_test.go +0 -305
  563. package/engine/internal/lib/footprint.go +0 -239
  564. package/engine/internal/lib/gitauthority.go +0 -601
  565. package/engine/internal/lib/gitauthority_test.go +0 -346
  566. package/engine/internal/lib/jsonout.go +0 -129
  567. package/engine/internal/lib/jsonout_test.go +0 -73
  568. package/engine/internal/lib/lanes.go +0 -112
  569. package/engine/internal/lib/learnings.go +0 -397
  570. package/engine/internal/lib/learnings_inject_test.go +0 -77
  571. package/engine/internal/lib/learnings_remediation_test.go +0 -24
  572. package/engine/internal/lib/ledger.go +0 -311
  573. package/engine/internal/lib/ledger_test.go +0 -186
  574. package/engine/internal/lib/mutationgate.go +0 -89
  575. package/engine/internal/lib/observability_test.go +0 -358
  576. package/engine/internal/lib/overrides.go +0 -164
  577. package/engine/internal/lib/overrides_test.go +0 -112
  578. package/engine/internal/lib/preamble.go +0 -159
  579. package/engine/internal/lib/preamble_questions_test.go +0 -10
  580. package/engine/internal/lib/progress.go +0 -210
  581. package/engine/internal/lib/provenance.go +0 -462
  582. package/engine/internal/lib/provenance_test.go +0 -154
  583. package/engine/internal/lib/readiness_contract.json +0 -118
  584. package/engine/internal/lib/readinessartifact.go +0 -533
  585. package/engine/internal/lib/readinessartifact_test.go +0 -422
  586. package/engine/internal/lib/reconcile.go +0 -1496
  587. package/engine/internal/lib/reconcile_test.go +0 -1071
  588. package/engine/internal/lib/recoveryattempts.go +0 -298
  589. package/engine/internal/lib/recoveryattempts_test.go +0 -215
  590. package/engine/internal/lib/reviewers.go +0 -143
  591. package/engine/internal/lib/reviewers_test.go +0 -45
  592. package/engine/internal/lib/reviewerstats.go +0 -199
  593. package/engine/internal/lib/reviewerstats_test.go +0 -104
  594. package/engine/internal/lib/reviewintegrity.go +0 -143
  595. package/engine/internal/lib/reviewintegrity_test.go +0 -103
  596. package/engine/internal/lib/runbook.go +0 -295
  597. package/engine/internal/lib/runbook_context_test.go +0 -182
  598. package/engine/internal/lib/session.go +0 -1020
  599. package/engine/internal/lib/session_test.go +0 -177
  600. package/engine/internal/lib/specparse.go +0 -125
  601. package/engine/internal/lib/specskeleton.go +0 -79
  602. package/engine/internal/lib/specvalidate.go +0 -391
  603. package/engine/internal/lib/specvalidate_test.go +0 -185
  604. package/engine/internal/lib/stuck.go +0 -206
  605. package/engine/internal/lib/templates/conventions_drift.tmpl +0 -6
  606. package/engine/internal/lib/templates/conventions_ledger_header.md +0 -6
  607. package/engine/internal/lib/templates/conventions_orient_header.txt +0 -1
  608. package/engine/internal/lib/testintegrity.go +0 -199
  609. package/engine/internal/lib/testintegrity_test.go +0 -149
  610. package/engine/internal/lib/tickafk.go +0 -86
  611. package/engine/internal/migrate/migrate.go +0 -279
  612. package/engine/internal/migrate/migrate_test.go +0 -157
  613. package/engine/internal/orient/firstrun.go +0 -50
  614. package/engine/internal/orient/firstrun_test.go +0 -72
  615. package/engine/internal/orient/orient.go +0 -69
  616. package/engine/internal/orient/orient_test.go +0 -25
  617. package/engine/internal/profile/profile.go +0 -284
  618. package/engine/internal/profile/profile_test.go +0 -13
  619. package/engine/internal/state/clarify_transition.go +0 -165
  620. package/engine/internal/state/clarify_transition_test.go +0 -130
  621. package/engine/internal/state/snapshot.go +0 -457
  622. package/engine/internal/toolpolicy/classifier.go +0 -533
  623. package/engine/internal/toolpolicy/classifier_test.go +0 -424
  624. package/engine/internal/toolpolicy/git.go +0 -616
  625. package/engine/internal/toolpolicy/scanner.go +0 -382
  626. package/engine/observability_cli_test.go +0 -52
  627. package/engine/profile_test.go +0 -76
  628. package/engine/subagent_orient_context.txt +0 -8
  629. package/engine/testdata/golden/TestParityA1Guard/devrites-edit-allowed.golden +0 -1
  630. package/engine/testdata/golden/TestParityA1Guard/no-window-silent.golden +0 -1
  631. package/engine/testdata/golden/TestParityA1Guard/non-edit-tool.golden +0 -1
  632. package/engine/testdata/golden/TestParityA1Guard/observe-mode-silent.golden +0 -1
  633. package/engine/testdata/golden/TestParityA1Guard/source-edit-enforce-denies.golden +0 -2
  634. package/engine/testdata/golden/TestParityA1Guard/subagent-allowed.golden +0 -1
  635. package/engine/testdata/golden/TestParityAnalyze/noactive.golden +0 -1
  636. package/engine/testdata/golden/TestParityAnalyze/slug=covered.golden +0 -15
  637. package/engine/testdata/golden/TestParityAnalyze/slug=dangling.golden +0 -16
  638. package/engine/testdata/golden/TestParityAnalyze/slug=ghost.golden +0 -1
  639. package/engine/testdata/golden/TestParityAnalyze/slug=noac.golden +0 -15
  640. package/engine/testdata/golden/TestParityAnalyze/slug=order.golden +0 -17
  641. package/engine/testdata/golden/TestParityAnalyze/slug=orphan.golden +0 -16
  642. package/engine/testdata/golden/TestParityAnalyze/slug=uncovered.golden +0 -16
  643. package/engine/testdata/golden/TestParityBudget/default-active.golden +0 -4
  644. package/engine/testdata/golden/TestParityBudget/extra-md.golden +0 -5
  645. package/engine/testdata/golden/TestParityBudget/no-active.golden +0 -1
  646. package/engine/testdata/golden/TestParityBudget/no-feature.golden +0 -1
  647. package/engine/testdata/golden/TestParityBudget/over-advisory.golden +0 -6
  648. package/engine/testdata/golden/TestParityBudget/over-strict.golden +0 -6
  649. package/engine/testdata/golden/TestParityBudget/within.golden +0 -6
  650. package/engine/testdata/golden/TestParityBuildReadiness/arg=approved.golden +0 -2
  651. package/engine/testdata/golden/TestParityBuildReadiness/arg=approvenone.golden +0 -1
  652. package/engine/testdata/golden/TestParityBuildReadiness/arg=await.golden +0 -1
  653. package/engine/testdata/golden/TestParityBuildReadiness/arg=blocked.golden +0 -1
  654. package/engine/testdata/golden/TestParityBuildReadiness/arg=clarifyopen.golden +0 -1
  655. package/engine/testdata/golden/TestParityBuildReadiness/arg=emptystatus.golden +0 -2
  656. package/engine/testdata/golden/TestParityBuildReadiness/arg=ghost.golden +0 -1
  657. package/engine/testdata/golden/TestParityBuildReadiness/arg=legacycontract.golden +0 -1
  658. package/engine/testdata/golden/TestParityBuildReadiness/arg=noapprove.golden +0 -1
  659. package/engine/testdata/golden/TestParityBuildReadiness/arg=noclarify.golden +0 -1
  660. package/engine/testdata/golden/TestParityBuildReadiness/arg=novet.golden +0 -1
  661. package/engine/testdata/golden/TestParityBuildReadiness/arg=stalevet.golden +0 -1
  662. package/engine/testdata/golden/TestParityBuildReadiness/arg=trailhash.golden +0 -2
  663. package/engine/testdata/golden/TestParityBuildReadiness/arg=trailpipe.golden +0 -2
  664. package/engine/testdata/golden/TestParityBuildReadiness/arg=vetnotready.golden +0 -1
  665. package/engine/testdata/golden/TestParityCheckAcceptance/arg=blank-section.golden +0 -1
  666. package/engine/testdata/golden/TestParityCheckAcceptance/arg=empty.golden +0 -1
  667. package/engine/testdata/golden/TestParityCheckAcceptance/arg=flat-dropped.golden +0 -1
  668. package/engine/testdata/golden/TestParityCheckAcceptance/arg=flat-ok.golden +0 -2
  669. package/engine/testdata/golden/TestParityCheckAcceptance/arg=flat-unchecked.golden +0 -1
  670. package/engine/testdata/golden/TestParityCheckAcceptance/arg=id-gap.golden +0 -1
  671. package/engine/testdata/golden/TestParityCheckAcceptance/arg=id-ok.golden +0 -2
  672. package/engine/testdata/golden/TestParityCheckAcceptance/arg=no-seal.golden +0 -1
  673. package/engine/testdata/golden/TestParityCheckAcceptance/arg=no-section.golden +0 -1
  674. package/engine/testdata/golden/TestParityCheckAcceptance/arg=nonexistent.golden +0 -1
  675. package/engine/testdata/golden/TestParityCheckAcceptance.golden +0 -1
  676. package/engine/testdata/golden/TestParityCoverage/arg=flat.golden +0 -7
  677. package/engine/testdata/golden/TestParityCoverage/arg=full.golden +0 -10
  678. package/engine/testdata/golden/TestParityCoverage/arg=nonexistent.golden +0 -1
  679. package/engine/testdata/golden/TestParityCoverage/arg=nospec.golden +0 -1
  680. package/engine/testdata/golden/TestParityCoverage/arg=speconly.golden +0 -9
  681. package/engine/testdata/golden/TestParityCoverage.golden +0 -1
  682. package/engine/testdata/golden/TestParityCursor/bare.golden +0 -3
  683. package/engine/testdata/golden/TestParityCursor/full-afk.golden +0 -6
  684. package/engine/testdata/golden/TestParityCursor/full-hitl.golden +0 -5
  685. package/engine/testdata/golden/TestParityCursor/no-active.golden +0 -1
  686. package/engine/testdata/golden/TestParityCursor/red.golden +0 -5
  687. package/engine/testdata/golden/TestParityCursor/zerogates.golden +0 -5
  688. package/engine/testdata/golden/TestParityDoubtCoverage/arg=doubted.golden +0 -2
  689. package/engine/testdata/golden/TestParityDoubtCoverage/arg=ghost.golden +0 -2
  690. package/engine/testdata/golden/TestParityDoubtCoverage/arg=missing.golden +0 -3
  691. package/engine/testdata/golden/TestParityDoubtCoverage/arg=nodoubt.golden +0 -4
  692. package/engine/testdata/golden/TestParityDoubtCoverage/arg=nolog.golden +0 -2
  693. package/engine/testdata/golden/TestParityDoubtCoverage/arg=nowright.golden +0 -2
  694. package/engine/testdata/golden/TestParityDoubtCoverage.golden +0 -1
  695. package/engine/testdata/golden/TestParityMutationGate/active-slug.golden +0 -3
  696. package/engine/testdata/golden/TestParityMutationGate/explicit-slug.golden +0 -3
  697. package/engine/testdata/golden/TestParityMutationGate/ghost.golden +0 -1
  698. package/engine/testdata/golden/TestParityOrientSilentPath.golden +0 -1
  699. package/engine/testdata/golden/TestParityReconcile/bad-mode.golden +0 -1
  700. package/engine/testdata/golden/TestParityReconcile/check-clean/snapshot.golden +0 -2
  701. package/engine/testdata/golden/TestParityReconcile/check-clean.golden +0 -2
  702. package/engine/testdata/golden/TestParityReconcile/check-no-base.golden +0 -1
  703. package/engine/testdata/golden/TestParityReconcile/check-no-claimed/snapshot.golden +0 -2
  704. package/engine/testdata/golden/TestParityReconcile/check-violation/snapshot.golden +0 -2
  705. package/engine/testdata/golden/TestParityReconcile/check-violation.golden +0 -1
  706. package/engine/testdata/golden/TestParityReconcile/close-window/snapshot.golden +0 -2
  707. package/engine/testdata/golden/TestParityReconcile/close-window.golden +0 -3
  708. package/engine/testdata/golden/TestParityReconcile/not-git.golden +0 -1
  709. package/engine/testdata/golden/TestParityReconcile/snapshot/snapshot.golden +0 -2
  710. package/engine/testdata/golden/TestParityReconcile/snapshot-no-allowlist.golden +0 -1
  711. package/engine/testdata/golden/TestParityReconcile/snapshot.golden +0 -2
  712. package/engine/testdata/golden/TestParityRedwatch/fail-writes-red.golden +0 -2
  713. package/engine/testdata/golden/TestParityRedwatch/non-bash-tool.golden +0 -1
  714. package/engine/testdata/golden/TestParityRedwatch/non-test-command.golden +0 -1
  715. package/engine/testdata/golden/TestParityRedwatch/pass-clears-red.golden +0 -1
  716. package/engine/testdata/golden/TestParityResolve/next-qid.golden +0 -2
  717. package/engine/testdata/golden/TestParityReviewerReadonly/agent-required-devrites-agent-denies.golden +0 -2
  718. package/engine/testdata/golden/TestParityReviewerReadonly/agent-required-non-devrites-allows.golden +0 -1
  719. package/engine/testdata/golden/TestParityReviewerReadonly/agent-required-subagent-type-only-allows.golden +0 -1
  720. package/engine/testdata/golden/TestParityReviewerReadonly/enforce-deny-git-commit.golden +0 -2
  721. package/engine/testdata/golden/TestParityReviewerReadonly/enforce-deny-mutating.golden +0 -2
  722. package/engine/testdata/golden/TestParityReviewerReadonly/non-bash-tool.golden +0 -1
  723. package/engine/testdata/golden/TestParityReviewerReadonly/non-tool-input.golden +0 -1
  724. package/engine/testdata/golden/TestParityReviewerReadonly/observe-mutating-silent.golden +0 -1
  725. package/engine/testdata/golden/TestParityReviewerReadonly/safe-bash-command.golden +0 -1
  726. package/engine/testdata/golden/TestParitySpecValidate/arg=dup.golden +0 -1
  727. package/engine/testdata/golden/TestParitySpecValidate/arg=empty.golden +0 -1
  728. package/engine/testdata/golden/TestParitySpecValidate/arg=flat.golden +0 -2
  729. package/engine/testdata/golden/TestParitySpecValidate/arg=nonexistent.golden +0 -1
  730. package/engine/testdata/golden/TestParitySpecValidate/arg=noscenario.golden +0 -1
  731. package/engine/testdata/golden/TestParitySpecValidate/arg=noshall.golden +0 -1
  732. package/engine/testdata/golden/TestParitySpecValidate/arg=nothen.golden +0 -1
  733. package/engine/testdata/golden/TestParitySpecValidate/arg=valid/spec.md.golden +0 -2
  734. package/engine/testdata/golden/TestParitySpecValidate/arg=valid.golden +0 -2
  735. package/engine/testdata/golden/TestParitySpecValidate.golden +0 -1
  736. package/engine/testdata/golden/TestParityStatusline/full-afk.golden +0 -2
  737. package/engine/testdata/golden/TestParityStatusline/full-hitl.golden +0 -2
  738. package/engine/testdata/golden/TestParityStatusline/no-active.golden +0 -1
  739. package/engine/testdata/golden/TestParityStatusline/nophase.golden +0 -2
  740. package/engine/testdata/golden/TestParityStatusline/red.golden +0 -2
  741. package/engine/testdata/golden/TestParityStuckCheck/bad-cmd.golden +0 -1
  742. package/engine/testdata/golden/TestParityStuckCheck/custom-window-2.golden +0 -2
  743. package/engine/testdata/golden/TestParityStuckCheck/dominant.golden +0 -2
  744. package/engine/testdata/golden/TestParityStuckCheck/few.golden +0 -2
  745. package/engine/testdata/golden/TestParityStuckCheck/ghost.golden +0 -2
  746. package/engine/testdata/golden/TestParityStuckCheck/identical.golden +0 -2
  747. package/engine/testdata/golden/TestParityStuckCheck/no-cmd.golden +0 -1
  748. package/engine/testdata/golden/TestParityStuckCheck/no-slug.golden +0 -1
  749. package/engine/testdata/golden/TestParityStuckCheck/nolog.golden +0 -2
  750. package/engine/testdata/golden/TestParityStuckCheck/pingpong.golden +0 -2
  751. package/engine/testdata/golden/TestParityStuckCheck/varied.golden +0 -2
  752. package/engine/testdata/golden/TestParityStuckCheck/window-04-identical.golden +0 -2
  753. package/engine/testdata/golden/TestParityStuckCheck/window-2.5-varied4.golden +0 -2
  754. package/engine/testdata/golden/TestParityStuckCheck/window-4x-varied4.golden +0 -2
  755. package/engine/testdata/golden/TestParityStuckCheck/window-leadspace-varied4.golden +0 -2
  756. package/engine/testdata/golden/TestParityStuckCheck/window-plus4-identical.golden +0 -2
  757. package/engine/testdata/golden/TestParitySubagentOrient/devrites-agent-subagent-type-key.golden +0 -2
  758. package/engine/testdata/golden/TestParitySubagentOrient/devrites-agent.golden +0 -2
  759. package/engine/testdata/golden/TestParitySubagentOrient/garbage-input.golden +0 -1
  760. package/engine/testdata/golden/TestParitySubagentOrient/non-devrites-agent.golden +0 -1
  761. package/engine/testdata/golden/TestParityTestIntegrity/assertion-dropped.golden +0 -1
  762. package/engine/testdata/golden/TestParityTestIntegrity/clean.golden +0 -2
  763. package/engine/testdata/golden/TestParityTestIntegrity/deleted.golden +0 -1
  764. package/engine/testdata/golden/TestParityTestIntegrity/ghost-workspace.golden +0 -1
  765. package/engine/testdata/golden/TestParityTestIntegrity/not-git.golden +0 -1
  766. package/engine/testdata/golden/TestParityTestIntegrity/skip-added.golden +0 -1
  767. package/engine/testdata/golden/TestParityTickAfk/budget1/state.md.golden +0 -1
  768. package/engine/testdata/golden/TestParityTickAfk/budget1.golden +0 -2
  769. package/engine/testdata/golden/TestParityTickAfk/budget3/state.md.golden +0 -5
  770. package/engine/testdata/golden/TestParityTickAfk/budget3.golden +0 -2
  771. package/engine/testdata/golden/TestParityTickAfk/bulletPipe/state.md.golden +0 -1
  772. package/engine/testdata/golden/TestParityTickAfk/bulletPipe.golden +0 -2
  773. package/engine/testdata/golden/TestParityTickAfk/missingField/state.md.golden +0 -3
  774. package/engine/testdata/golden/TestParityTickAfk/missingField.golden +0 -2
  775. package/engine/testdata/golden/TestParityTickAfk/missingFile.golden +0 -1
  776. package/engine/testdata/golden/TestParityTickAfk/nonNumeric/state.md.golden +0 -1
  777. package/engine/testdata/golden/TestParityTickAfk/nonNumeric.golden +0 -1
  778. package/engine/testdata/golden/TestParityTickAfk/none/state.md.golden +0 -1
  779. package/engine/testdata/golden/TestParityTickAfk/none.golden +0 -2
  780. package/engine/testdata/golden/TestParityWrightScope/agent-required-non-wright.golden +0 -1
  781. package/engine/testdata/golden/TestParityWrightScope/devrites-edit-denied.golden +0 -2
  782. package/engine/testdata/golden/TestParityWrightScope/in-scope-allowed.golden +0 -1
  783. package/engine/testdata/golden/TestParityWrightScope/non-edit-tool.golden +0 -1
  784. package/engine/testdata/golden/TestParityWrightScope/out-of-scope-enforce-denies.golden +0 -2
  785. package/engine/testdata/golden/TestParityWrightScope/out-of-scope-observe-silent.golden +0 -1
  786. package/engine/testdata/golden/TestSpecSkeleton/missing-some.golden +0 -2
  787. package/engine/testdata/golden/TestSpecSkeleton/present-all.golden +0 -2
  788. package/engine/testdata/golden/TestStuckLogHashParity.golden +0 -1
  789. package/engine/tests/adr_0006_clock_seam_test.go +0 -36
  790. package/engine/tests/budget_test.go +0 -88
  791. package/engine/tests/canonical_ac_ids_test.go +0 -44
  792. package/engine/tests/concurrency_cli_test.go +0 -131
  793. package/engine/tests/conventions_test.go +0 -106
  794. package/engine/tests/doctor_cli_test.go +0 -223
  795. package/engine/tests/forge_cli_test.go +0 -463
  796. package/engine/tests/hook_test.go +0 -2778
  797. package/engine/tests/hooks_io_test.go +0 -309
  798. package/engine/tests/json_contract_test.go +0 -224
  799. package/engine/tests/lib_parity_test.go +0 -930
  800. package/engine/tests/migrate_cli_test.go +0 -195
  801. package/engine/tests/parity_analyze_test.go +0 -55
  802. package/engine/tests/parity_buildreadiness_test.go +0 -199
  803. package/engine/tests/parity_learnings_test.go +0 -89
  804. package/engine/tests/parity_mutationgate_test.go +0 -36
  805. package/engine/tests/parity_reconcile_test.go +0 -94
  806. package/engine/tests/parity_testintegrity_test.go +0 -65
  807. package/engine/tests/parity_tickafk_test.go +0 -83
  808. package/engine/validatepack.go +0 -192
  809. package/engine/validatepack_test.go +0 -79
  810. package/engine/validatepackskills.go +0 -181
  811. package/engine/validatepackskills_test.go +0 -171
  812. package/pack/.claude/agents/devrites-forge-judge.md +0 -118
  813. package/pack/.claude/skills/devrites-lib/reference/model-tiers.md +0 -44
  814. package/pack/.claude/skills/devrites-refresh-indexes/SKILL.md +0 -52
  815. package/pack/.claude/skills/rite-build/reference/evidence-standard.md +0 -45
  816. package/pack/.claude/skills/rite-build/reference/forge.md +0 -210
  817. package/pack/.claude/skills/rite-seal/reference/conventions-ledger.md +0 -60
  818. package/pack/.claude/skills/rite-ship/reference/adr-promotion.md +0 -9
  819. package/pack/.claude/skills/rite-ship/reference/ledger.md +0 -56
  820. package/pack/generated/claude/agents/devrites-forge-judge.md +0 -118
  821. package/pack/generated/claude/skills/devrites-lib/reference/model-tiers.md +0 -44
  822. package/pack/generated/claude/skills/devrites-refresh-indexes/SKILL.md +0 -52
  823. package/pack/generated/claude/skills/rite-build/reference/evidence-standard.md +0 -45
  824. package/pack/generated/claude/skills/rite-build/reference/forge.md +0 -210
  825. package/pack/generated/claude/skills/rite-seal/reference/conventions-ledger.md +0 -60
  826. package/pack/generated/claude/skills/rite-ship/reference/adr-promotion.md +0 -9
  827. package/pack/generated/claude/skills/rite-ship/reference/ledger.md +0 -56
  828. package/pack/generated/codex/agents/devrites-forge-judge.toml +0 -128
  829. package/pack/generated/codex/hooks.json +0 -185
  830. package/pack/generated/codex/skills/devrites-api-interface/agents/openai.yaml +0 -2
  831. package/pack/generated/codex/skills/devrites-audit/agents/openai.yaml +0 -2
  832. package/pack/generated/codex/skills/devrites-browser-proof/agents/openai.yaml +0 -2
  833. package/pack/generated/codex/skills/devrites-debug-recovery/agents/openai.yaml +0 -2
  834. package/pack/generated/codex/skills/devrites-doubt/agents/openai.yaml +0 -2
  835. package/pack/generated/codex/skills/devrites-frontend-craft/agents/openai.yaml +0 -2
  836. package/pack/generated/codex/skills/devrites-interview/agents/openai.yaml +0 -2
  837. package/pack/generated/codex/skills/devrites-lib/reference/model-tiers.md +0 -44
  838. package/pack/generated/codex/skills/devrites-prose-craft/agents/openai.yaml +0 -2
  839. package/pack/generated/codex/skills/devrites-refresh-indexes/SKILL.md +0 -71
  840. package/pack/generated/codex/skills/devrites-refresh-indexes/agents/openai.yaml +0 -2
  841. package/pack/generated/codex/skills/devrites-source-driven/agents/openai.yaml +0 -2
  842. package/pack/generated/codex/skills/devrites-ux-shape/agents/openai.yaml +0 -2
  843. package/pack/generated/codex/skills/rite-build/reference/evidence-standard.md +0 -45
  844. package/pack/generated/codex/skills/rite-build/reference/forge.md +0 -210
  845. package/pack/generated/codex/skills/rite-seal/reference/conventions-ledger.md +0 -60
  846. package/pack/generated/codex/skills/rite-ship/reference/adr-promotion.md +0 -9
  847. package/pack/generated/codex/skills/rite-ship/reference/ledger.md +0 -56
  848. package/scripts/build-binaries.sh +0 -75
  849. package/scripts/build-release-tarball.sh +0 -105
  850. package/scripts/check-authority-drift.py +0 -125
  851. package/scripts/check-cross-refs.py +0 -139
  852. package/scripts/check-generated-skill-budget.mjs +0 -42
  853. package/scripts/check-instruction-size-baseline.mjs +0 -88
  854. package/scripts/check-invocation-integrity.py +0 -115
  855. package/scripts/check-no-global-writes.sh +0 -66
  856. package/scripts/check-no-personal-paths.py +0 -50
  857. package/scripts/check-npm-audit.mjs +0 -110
  858. package/scripts/check-reference-governance.mjs +0 -83
  859. package/scripts/check-reply-contract.sh +0 -64
  860. package/scripts/check-rule-uniqueness.sh +0 -45
  861. package/scripts/devrites-detect.sh +0 -176
  862. package/scripts/grade-feature.sh +0 -204
  863. package/scripts/live-hosts/agent-result.schema.json +0 -231
  864. package/scripts/live-hosts/claude.sh +0 -87
  865. package/scripts/live-hosts/codex.sh +0 -85
  866. package/scripts/live-hosts/common.sh +0 -113
  867. package/scripts/live-hosts/fake-host.py +0 -257
  868. package/scripts/live-hosts/host-transport.py +0 -286
  869. package/scripts/npm-audit-exceptions.json +0 -26
  870. package/scripts/pin.sh +0 -249
  871. package/scripts/release-check.sh +0 -75
  872. package/scripts/run-agent-contract-evals.py +0 -1380
  873. package/scripts/run-behavioral-evals.sh +0 -196
  874. package/scripts/run-evals.sh +0 -132
  875. package/scripts/run-live-behavioral-evals.py +0 -1310
  876. package/scripts/run-outcome-evals.sh +0 -454
  877. package/scripts/run-routing-evals.py +0 -342
  878. package/scripts/run-tests.mjs +0 -232
  879. package/scripts/scan-pack-security.py +0 -209
  880. package/scripts/scan-supply-chain-iocs.py +0 -127
  881. package/scripts/skill-pruning-audit.mjs +0 -121
  882. package/scripts/skills-inventory.mjs +0 -125
  883. package/scripts/supply-chain-iocs.json +0 -11
  884. package/scripts/sync-version.sh +0 -54
  885. package/scripts/validate-agent-composition.py +0 -57
  886. package/scripts/validate-command-parity.py +0 -70
  887. package/scripts/validate-frontmatter.py +0 -218
  888. package/scripts/validate-skill-anatomy.py +0 -139
  889. package/scripts/validate-workflow-security.py +0 -184
  890. package/scripts/validate-workspace-schema.py +0 -800
  891. package/scripts/validate.sh +0 -354
  892. package/scripts/workflow_schema.py +0 -69
  893. /package/engine/testdata/fixtures/basic/devrites-root/{features → work}/auth-tokens/decisions.md +0 -0
  894. /package/engine/testdata/fixtures/basic/devrites-root/{features → work}/auth-tokens/plan.md +0 -0
  895. /package/engine/testdata/fixtures/basic/devrites-root/{features → work}/auth-tokens/spec.md +0 -0
  896. /package/engine/testdata/fixtures/basic/devrites-root/{features → work}/auth-tokens/tasks.md +0 -0
  897. /package/engine/testdata/fixtures/basic/devrites-root/{features → work}/search-ranking/spec.md +0 -0
@@ -1,930 +0,0 @@
1
- package main_test
2
-
3
- // Golden + diagnostic tests for the ported devrites-lib commands (issue 08).
4
- //
5
- // Golden: each command is run through the Go binary against a fixture, and its
6
- // stdout + exit code are checked against a recorded golden snapshot (stderr is
7
- // diagnostic, not contract). Snapshots are regenerated with UPDATE_GOLDEN=1.
8
- //
9
- // Diagnostic: a second pass asserts the Go stderr carries the same actionable
10
- // finding substrings a consumer greps for, so the port keeps its diagnostic
11
- // quality even though stderr is excluded from the golden check.
12
-
13
- import (
14
- "bytes"
15
- "errors"
16
- "os"
17
- "os/exec"
18
- "path/filepath"
19
- "testing"
20
- "time"
21
-
22
- "github.com/devrites/devrites/internal/testutil"
23
- )
24
-
25
- // libEnv forces byte-order collation so `sort` in the bash script and
26
- // sort.Strings in Go agree (matters for check-acceptance's id ordering).
27
- var libEnv = []string{"LC_ALL=C", "DEVRITES_ROOT="}
28
-
29
- // libRootEnv points DEVRITES_ROOT at the workspace's .devrites directory so the
30
- // command reads the fixture under <root>/features/<slug>. LC_ALL=C pins byte-order
31
- // collation so id ordering is deterministic.
32
- func libRootEnv(work string) []string {
33
- return []string{"LC_ALL=C", "DEVRITES_ROOT=" + filepath.Join(work, ".devrites")}
34
- }
35
-
36
- // writeFeatureFile writes fixture content to <work>/.devrites/features/<slug>/<name>.
37
- func writeFeatureFile(t *testing.T, work, slug, name, content string) {
38
- t.Helper()
39
- writeFile(t, work, filepath.Join(".devrites/features", slug, name), content)
40
- }
41
-
42
- // makeFeatureDir creates an empty feature directory in the workspace.
43
- func makeFeatureDir(t *testing.T, work, slug string) {
44
- t.Helper()
45
- mkdirAllT(t, work, filepath.Join(".devrites/features", slug))
46
- }
47
-
48
- // writeSpec writes content to <workdir>/<name>/spec.md and returns the subdir name.
49
- func writeSpec(t *testing.T, workdir, name, content string) string {
50
- t.Helper()
51
- dir := filepath.Join(workdir, name)
52
- if err := os.MkdirAll(dir, 0o755); err != nil {
53
- t.Fatal(err)
54
- }
55
- if err := os.WriteFile(filepath.Join(dir, "spec.md"), []byte(content), 0o644); err != nil {
56
- t.Fatal(err)
57
- }
58
- return name
59
- }
60
-
61
- func writeFile(t *testing.T, workdir, rel, content string) {
62
- t.Helper()
63
- testutil.WriteFile(t, filepath.Join(workdir, rel), content)
64
- }
65
-
66
- // runGo runs the built binary in workdir with libEnv, returning stdout, stderr, code.
67
- func runGo(t *testing.T, workdir string, args ...string) (stdout, stderr string, code int) {
68
- t.Helper()
69
- cmd := exec.Command(binPath, args...)
70
- cmd.Dir = workdir
71
- cmd.Env = append(os.Environ(), libEnv...)
72
- var out, errBuf bytes.Buffer
73
- cmd.Stdout = &out
74
- cmd.Stderr = &errBuf
75
- if err := cmd.Run(); err != nil {
76
- var ee *exec.ExitError
77
- if !errors.As(err, &ee) {
78
- t.Fatalf("running %s %v: %v", binPath, args, err)
79
- }
80
- code = ee.ExitCode()
81
- }
82
- return out.String(), errBuf.String(), code
83
- }
84
-
85
- // ---- spec-validate --------------------------------------------------------
86
-
87
- // Spec fixtures cover the well-formed spec plus each malformed shape so the
88
- // golden check exercises every spec-validate verdict.
89
- const (
90
- specValid = `# Spec
91
- ## Acceptance criteria
92
- ### Requirement: Tokens expire after inactivity
93
- The system SHALL reject a session token older than 15 minutes.
94
- #### Scenario: expired token
95
- - [ ] [AC1] **WHEN** a token aged > 15m is presented **THEN** respond 401
96
- #### Scenario: fresh token
97
- - [ ] [AC2] **WHEN** a token aged < 15m is presented **THEN** allow
98
- ### Requirement: Logout revokes the token
99
- Logout MUST invalidate the token server-side.
100
- #### Scenario: replay after logout
101
- - [ ] [AC3] **WHEN** a logged-out token is replayed **THEN** respond 401
102
- `
103
- specFlat = `# Spec
104
- ## Acceptance criteria
105
- - [ ] [AC1] export returns a CSV with a header row
106
- - [ ] [AC2] an empty dataset returns 204
107
- `
108
- specNoShall = `### Requirement: Export behaves nicely
109
- The export produces a file and emails the user.
110
- #### Scenario: happy path
111
- - **WHEN** a user requests an export **THEN** a file is produced
112
- `
113
- specNoScenario = `### Requirement: It works
114
- The system SHALL do the thing.
115
- `
116
- specNoThen = `### Requirement: It works
117
- The system SHALL do the thing.
118
- #### Scenario: half a scenario
119
- - **WHEN** something happens
120
- `
121
- specDup = `### Requirement: Same name
122
- The system SHALL alpha.
123
- #### Scenario: a
124
- - **WHEN** a **THEN** b
125
- ### Requirement: Same name
126
- The system SHALL beta.
127
- #### Scenario: c
128
- - **WHEN** c **THEN** d
129
- `
130
- )
131
-
132
- func TestParitySpecValidate(t *testing.T) {
133
- work := t.TempDir()
134
-
135
- writeSpec(t, work, "valid", specValid)
136
- writeSpec(t, work, "flat", specFlat)
137
- writeSpec(t, work, "noshall", specNoShall)
138
- writeSpec(t, work, "noscenario", specNoScenario)
139
- writeSpec(t, work, "nothen", specNoThen)
140
- writeSpec(t, work, "dup", specDup)
141
- if err := os.MkdirAll(filepath.Join(work, "empty"), 0o755); err != nil {
142
- t.Fatal(err)
143
- }
144
-
145
- // arg is the positional argument passed to both implementations, relative to work.
146
- for _, arg := range []string{
147
- "valid", // well-formed structured spec → exit 0
148
- "flat", // flat-bullet form → exit 0 (no-op)
149
- "noshall", // missing SHALL/MUST → exit 1
150
- "noscenario", // requirement with no scenario → exit 1
151
- "nothen", // scenario missing THEN → exit 1
152
- "dup", // duplicate headers → exit 1
153
- "valid/spec.md", // direct file path → exit 0
154
- "empty", // dir without spec.md → exit 5
155
- "nonexistent", // no such workspace or file → exit 2
156
- } {
157
- c := parityCase{
158
- workdir: work,
159
- env: libEnv,
160
- goArgs: []string{"spec-validate", arg},
161
- }
162
- t.Run("arg="+arg, func(t *testing.T) { c.assertEqual(t) })
163
- }
164
-
165
- // No-argument usage path (exit 2): asserted separately since arg is absent.
166
- (parityCase{
167
- workdir: work,
168
- env: libEnv,
169
- goArgs: []string{"spec-validate"},
170
- }).assertEqual(t)
171
- }
172
-
173
- func TestSpecSkeleton(t *testing.T) {
174
- work := t.TempDir()
175
-
176
- writeSpec(t, work, "present", `# Contract
177
-
178
- ## Problem
179
- done
180
- ## Goal
181
- done
182
- ## Non-goals
183
- done
184
- ## Users / actors
185
- done
186
- ## Requirements
187
- done
188
- ## Acceptance criteria
189
- done
190
- ## Edge Coverage
191
- done
192
- ## Prohibitions (must-NOT)
193
- done
194
- ## Edge cases
195
- done
196
- ## Measurable success
197
- done
198
- ## Scope boundaries
199
- done
200
- `)
201
- writeSpec(t, work, "missing", `# Contract
202
-
203
- ## Problem
204
- done
205
- ## Goal
206
- done
207
- ## Requirements
208
- done
209
- `)
210
-
211
- for _, tc := range []struct {
212
- name string
213
- arg string
214
- }{
215
- {"present-all", "present"},
216
- {"missing-some", "missing/spec.md"},
217
- } {
218
- tc := tc
219
- t.Run(tc.name, func(t *testing.T) {
220
- (parityCase{
221
- workdir: work,
222
- env: libEnv,
223
- goArgs: []string{"spec-skeleton", tc.arg},
224
- }).assertEqual(t)
225
- })
226
- }
227
- }
228
-
229
- // TestSpecValidateDiagnostics asserts the Go stderr carries the same finding
230
- // substrings the legacy spec-validate-test.sh greps for.
231
- func TestSpecValidateDiagnostics(t *testing.T) {
232
- work := t.TempDir()
233
- cases := []struct {
234
- name, content, wantExit1 string
235
- }{
236
- {"noshall", specNoShall, "no SHALL/MUST"},
237
- {"noscenario", specNoScenario, `no "#### Scenario:"`},
238
- {"nothen", specNoThen, "no THEN line"},
239
- {"dup", specDup, "duplicate Requirement header"},
240
- }
241
- for _, tc := range cases {
242
- writeSpec(t, work, tc.name, tc.content)
243
- _, stderr, code := runGo(t, work, "spec-validate", tc.name)
244
- if code != 1 {
245
- t.Errorf("%s: exit=%d, want 1", tc.name, code)
246
- }
247
- if !bytes.Contains([]byte(stderr), []byte(tc.wantExit1)) {
248
- t.Errorf("%s: stderr %q missing %q", tc.name, stderr, tc.wantExit1)
249
- }
250
- }
251
- }
252
-
253
- // ---- check-acceptance -----------------------------------------------------
254
-
255
- func TestParityCheckAcceptance(t *testing.T) {
256
- work := t.TempDir()
257
-
258
- // id mode, all proven → exit 0
259
- writeFile(t, work, "id-ok/spec.md", "## Acceptance criteria\n- [ ] [AC1] a\n- [ ] [AC2] b\n- [ ] [AC3] c\n")
260
- writeFile(t, work, "id-ok/seal.md", "## Acceptance Criteria\n- [x] [AC1] a: evidence t1\n- [x] [AC2] b: evidence t2\n- [x] [AC3] c: evidence t3\n")
261
-
262
- // id mode, one unproven → exit 1
263
- writeFile(t, work, "id-gap/spec.md", "## Acceptance criteria\n- [ ] [AC1] a\n- [ ] [AC2] b\n- [ ] [AC3] c\n")
264
- writeFile(t, work, "id-gap/seal.md", "## Acceptance Criteria\n- [x] [AC1] a: evidence t1\n- [ ] [AC2] b\n- [ ] [AC3] c\n")
265
-
266
- // fallback (no ids), all checked → exit 0
267
- writeFile(t, work, "flat-ok/spec.md", "## Acceptance criteria\n- export returns CSV\n- empty dataset returns 204\n")
268
- writeFile(t, work, "flat-ok/seal.md", "## Acceptance Criteria\n- [x] export returns CSV\n- [x] empty dataset returns 204\n")
269
-
270
- // fallback, one unchecked → exit 1
271
- writeFile(t, work, "flat-unchecked/spec.md", "## Acceptance criteria\n- export returns CSV\n- empty dataset returns 204\n")
272
- writeFile(t, work, "flat-unchecked/seal.md", "## Acceptance Criteria\n- [x] export returns CSV\n- [ ] empty dataset returns 204\n")
273
-
274
- // fallback, seal drops a criterion → exit 1
275
- writeFile(t, work, "flat-dropped/spec.md", "## Acceptance criteria\n- a\n- b\n- c\n")
276
- writeFile(t, work, "flat-dropped/seal.md", "## Acceptance Criteria\n- [x] a\n- [x] b\n")
277
-
278
- // spec has no acceptance section → exit 1
279
- writeFile(t, work, "no-section/spec.md", "# Spec\nsome prose, no criteria heading\n")
280
- writeFile(t, work, "no-section/seal.md", "## Acceptance Criteria\n- [x] a\n")
281
-
282
- // spec has an acceptance heading but only blank lines under it → still
283
- // "nothing to grade" (bash `[ -z ]` after trailing-newline strip), exit 1.
284
- writeFile(t, work, "blank-section/spec.md", "## Acceptance criteria\n\n\n## Notes\nprose\n")
285
- writeFile(t, work, "blank-section/seal.md", "## Acceptance Criteria\n- [x] a\n")
286
-
287
- // missing seal.md → exit 5
288
- writeFile(t, work, "no-seal/spec.md", "## Acceptance criteria\n- [ ] [AC1] a\n")
289
-
290
- // empty dir (missing spec.md) → exit 5
291
- if err := os.MkdirAll(filepath.Join(work, "empty"), 0o755); err != nil {
292
- t.Fatal(err)
293
- }
294
-
295
- for _, arg := range []string{
296
- "id-ok", "id-gap", "flat-ok", "flat-unchecked", "flat-dropped",
297
- "no-section", "blank-section", "no-seal", "empty", "nonexistent",
298
- } {
299
- c := parityCase{
300
- workdir: work,
301
- env: libEnv,
302
- goArgs: []string{"check-acceptance", arg},
303
- }
304
- t.Run("arg="+arg, func(t *testing.T) { c.assertEqual(t) })
305
- }
306
-
307
- // No-argument usage path (exit 2).
308
- (parityCase{
309
- workdir: work,
310
- env: libEnv,
311
- goArgs: []string{"check-acceptance"},
312
- }).assertEqual(t)
313
- }
314
-
315
- // ---- footprint ------------------------------------------------------------
316
- //
317
- // Golden tests: the expected stdout + exit values are asserted inline under
318
- // LC_ALL=C, so the feature stands alone. The invariants a future edit must
319
- // preserve: skip records never count, active-minutes = int((max-min)/60), the
320
- // wright · reviewer · audit · doubt kind order with correct singular/plural
321
- // forms, and the roster 0/1/3 exit taxonomy.
322
-
323
- // goldenCase asserts the built binary's stdout + exit code for one invocation.
324
- type goldenCase struct {
325
- name string
326
- args []string
327
- wantOut string
328
- wantCode int
329
- }
330
-
331
- func (gc goldenCase) assert(t *testing.T, work string) {
332
- t.Helper()
333
- out, _, code := runGo(t, work, gc.args...)
334
- if out != gc.wantOut || code != gc.wantCode {
335
- t.Errorf("%s: got exit=%d out=%q\n want exit=%d out=%q",
336
- gc.name, code, out, gc.wantCode, gc.wantOut)
337
- }
338
- }
339
-
340
- func TestFootprintGolden(t *testing.T) {
341
- work := t.TempDir()
342
-
343
- // render: the deterministic fixed-epoch log from tests/footprint-test.sh.
344
- writeFile(t, work, ".devrites/features/rendered/footprint.log",
345
- "1000 wright 01-list\n1100 wright 02-detail\n"+
346
- "1200 reviewer devrites-code-reviewer\n1200 reviewer devrites-security-auditor\n"+
347
- "1300 reviewer devrites-test-analyst\n")
348
- // single reviewer → the singular "1 subagent (1 reviewer)" + 0-slice path.
349
- writeFile(t, work, ".devrites/features/one/footprint.log", "1000 reviewer spec-reviewer\n")
350
- // audit + doubt → those kinds' pluralization and order.
351
- writeFile(t, work, ".devrites/features/ad/footprint.log",
352
- "1000 wright a\n1000 audit x\n1000 audit y\n1000 doubt z\n")
353
- mkdirAllT(t, work, ".devrites/features/nolog")
354
- writeFile(t, work, ".devrites/features/rc-complete/footprint.log",
355
- "1000 reviewer spec-reviewer\n1000 reviewer code-reviewer\n1000 reviewer test-analyst\n"+
356
- "1000 reviewer frontend-reviewer\n1000 skip security-auditor\n"+
357
- "1000 skip performance-reviewer\n1000 skip devex-reviewer\n")
358
- writeFile(t, work, ".devrites/features/rc-unacc/footprint.log",
359
- "1000 reviewer spec-reviewer\n1000 reviewer code-reviewer\n")
360
- writeFile(t, work, ".devrites/features/rc-skip/footprint.log",
361
- "1000 reviewer spec-reviewer\n1000 reviewer code-reviewer\n1000 skip test-analyst\n"+
362
- "1000 skip frontend-reviewer\n1000 skip security-auditor\n"+
363
- "1000 skip performance-reviewer\n1000 skip devex-reviewer\n")
364
- mkdirAllT(t, work, ".devrites/features/live")
365
-
366
- rosterComplete := " spec-reviewer: dispatched\n code-reviewer: dispatched\n" +
367
- " test-analyst: dispatched\n frontend-reviewer: dispatched\n" +
368
- " security-auditor: skipped\n performance-reviewer: skipped\n" +
369
- " devex-reviewer: skipped\nroster: complete (every reviewer accounted for)\n"
370
- rosterUnacc := " spec-reviewer: dispatched\n code-reviewer: dispatched\n" +
371
- " test-analyst: UNACCOUNTED\n frontend-reviewer: UNACCOUNTED\n" +
372
- " security-auditor: UNACCOUNTED\n performance-reviewer: UNACCOUNTED\n" +
373
- " devex-reviewer: UNACCOUNTED\n" +
374
- "roster: UNACCOUNTED: test-analyst frontend-reviewer security-auditor performance-reviewer devex-reviewer\n"
375
- rosterSkip := " spec-reviewer: dispatched\n code-reviewer: dispatched\n" +
376
- " test-analyst: skipped (always-on: verify carry-forward)\n" +
377
- " frontend-reviewer: skipped\n security-auditor: skipped\n" +
378
- " performance-reviewer: skipped\n devex-reviewer: skipped\n" +
379
- "roster: always-on skipped: test-analyst\n"
380
-
381
- for _, gc := range []goldenCase{
382
- {"render", []string{"footprint", "render", "rendered"},
383
- "Footprint: 5 subagents (2 wright · 3 reviewers) · 2 slices · ~5m active\n", 0},
384
- {"render-singular", []string{"footprint", "render", "one"},
385
- "Footprint: 1 subagent (1 reviewer) · 0 slices · ~0m active\n", 0},
386
- {"render-audit-doubt", []string{"footprint", "render", "ad"},
387
- "Footprint: 4 subagents (1 wright · 2 audits · 1 doubt) · 1 slice · ~0m active\n", 0},
388
- {"render-nolog", []string{"footprint", "render", "nolog"},
389
- "Footprint: n/a (no dispatch records)\n", 0},
390
- {"render-missing-ws", []string{"footprint", "render", "ghost"},
391
- "Footprint: n/a (no dispatch records)\n", 0},
392
- {"roster-complete", []string{"footprint", "roster", "rc-complete"}, rosterComplete, 0},
393
- {"roster-unaccounted", []string{"footprint", "roster", "rc-unacc"}, rosterUnacc, 3},
394
- {"roster-skip-alwayson", []string{"footprint", "roster", "rc-skip"}, rosterSkip, 1},
395
- {"roster-nolog", []string{"footprint", "roster", "nolog"},
396
- "roster: n/a (no dispatch records: fan-out did not run)\n", 0},
397
- {"log-missing-ws", []string{"footprint", "log", "ghost", "wright", "x"}, "", 0},
398
- {"log-usage-no-kind", []string{"footprint", "log", "live"}, "", 2},
399
- {"unknown-subcommand", []string{"footprint", "bogus", "live"}, "", 2},
400
- {"missing-slug", []string{"footprint", "render"}, "", 2},
401
- {"no-args", []string{"footprint"}, "", 2},
402
- } {
403
- t.Run(gc.name, func(t *testing.T) { gc.assert(t, work) })
404
- }
405
-
406
- // The footprint never emits a token/dollar/cost figure: DevRites cannot
407
- // truthfully source one (the same invariant footprint-test.sh guards).
408
- out, _, _ := runGo(t, work, "footprint", "render", "rendered")
409
- for _, banned := range []string{"token", "$", "cost", "usd", "USD"} {
410
- if bytes.Contains([]byte(out), []byte(banned)) {
411
- t.Errorf("render leaked a %q figure: %q", banned, out)
412
- }
413
- }
414
- }
415
-
416
- // TestFootprintLogAppends asserts the side-effect the parity oracle can't (it
417
- // compares only stdout+exit): `log` appends exactly one record and a missing
418
- // workspace is a silent no-op.
419
- func TestFootprintLogAppends(t *testing.T) {
420
- work := t.TempDir()
421
- mkdirAllT(t, work, ".devrites/features/feat")
422
- logp := filepath.Join(work, ".devrites", "features", "feat", "footprint.log")
423
-
424
- if _, _, code := runGo(t, work, "footprint", "log", "feat", "audit", "security"); code != 0 {
425
- t.Fatalf("log exit=%d, want 0", code)
426
- }
427
- if n := fileLines(t, logp); n != 1 {
428
- t.Errorf("after one log: %d lines, want 1", n)
429
- }
430
- runGo(t, work, "footprint", "log", "feat", "wright", "01")
431
- if n := fileLines(t, logp); n != 2 {
432
- t.Errorf("after two logs: %d lines, want 2", n)
433
- }
434
-
435
- // An empty label still writes its trailing space: byte-parity with
436
- // footprint.sh's `printf '%s %s %s\n'`, which always emits three fields.
437
- runGo(t, work, "footprint", "log", "feat", "wright")
438
- if last := lastLine(t, logp); !bytes.HasSuffix([]byte(last), []byte(" wright ")) {
439
- t.Errorf("empty-label record = %q, want a trailing space (`<epoch> wright `)", last)
440
- }
441
-
442
- if _, _, code := runGo(t, work, "footprint", "log", "ghost", "wright", "x"); code != 0 {
443
- t.Errorf("log on a missing workspace: exit=%d, want 0 (never fail the caller)", code)
444
- }
445
- if _, err := os.Stat(filepath.Join(work, ".devrites", "features", "ghost", "footprint.log")); err == nil {
446
- t.Error("log on a missing workspace created a log; it must be a no-op")
447
- }
448
- }
449
-
450
- // ---- evidence-fresh -------------------------------------------------------
451
- //
452
- // Golden tests: expected stdout + exit are asserted inline. File mtimes are set
453
- // explicitly so the freshness comparison is deterministic and independent of
454
- // when the fixtures were written.
455
-
456
- func TestEvidenceFreshGolden(t *testing.T) {
457
- work := t.TempDir()
458
-
459
- old := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
460
- mid := time.Date(2026, 1, 2, 0, 0, 0, 0, time.UTC)
461
- newer := time.Date(2026, 1, 3, 0, 0, 0, 0, time.UTC)
462
-
463
- const okMsg = "evidence-fresh: OK: evidence post-dates every touched file.\n"
464
-
465
- // Primary workspace: evidence + one touched file.
466
- ws := ".devrites/features/ftest"
467
- writeFile(t, work, ws+"/touched-files.md", "# touched\n- `src/app.js`\n")
468
- writeFile(t, work, ws+"/evidence.md", "# evidence\nproof\n")
469
- writeFile(t, work, "src/app.js", "code\n")
470
-
471
- // STALE: the touched file is newer than the proof → exit 3.
472
- chtimeT(t, work, ws+"/evidence.md", old)
473
- chtimeT(t, work, "src/app.js", mid)
474
- (goldenCase{"stale", []string{"evidence-fresh", "ftest"}, "", 3}).assert(t, work)
475
-
476
- // FRESH: the proof now post-dates the code → exit 0.
477
- chtimeT(t, work, ws+"/evidence.md", newer)
478
- (goldenCase{"fresh", []string{"evidence-fresh", "ftest"}, okMsg, 0}).assert(t, work)
479
-
480
- // proof.md is the supported alias for evidence.md. A proof-only workspace
481
- // must pass/fail freshness by the same mtime rule.
482
- writeFile(t, work, ".devrites/features/proofonly/touched-files.md", "# touched\n- `src/proofonly.js`\n")
483
- writeFile(t, work, ".devrites/features/proofonly/proof.md", "# proof\n")
484
- writeFile(t, work, "src/proofonly.js", "x\n")
485
- chtimeT(t, work, "src/proofonly.js", old)
486
- chtimeT(t, work, ".devrites/features/proofonly/proof.md", newer)
487
- (goldenCase{"proof-only-fresh", []string{"evidence-fresh", "proofonly"}, okMsg, 0}).assert(t, work)
488
-
489
- writeFile(t, work, ".devrites/features/proofstale/touched-files.md", "# touched\n- `src/proofstale.js`\n")
490
- writeFile(t, work, ".devrites/features/proofstale/proof.md", "# proof\n")
491
- writeFile(t, work, "src/proofstale.js", "x\n")
492
- chtimeT(t, work, ".devrites/features/proofstale/proof.md", old)
493
- chtimeT(t, work, "src/proofstale.js", newer)
494
- (goldenCase{"proof-only-stale", []string{"evidence-fresh", "proofstale"}, "", 3}).assert(t, work)
495
-
496
- // Default slug resolved from .devrites/ACTIVE, fresh → exit 0.
497
- writeFile(t, work, ".devrites/features/defslug/touched-files.md", "# touched\n- `src/other.js`\n")
498
- writeFile(t, work, ".devrites/features/defslug/evidence.md", "# evidence\n")
499
- writeFile(t, work, "src/other.js", "x\n")
500
- writeFile(t, work, ".devrites/ACTIVE", "defslug\n")
501
- chtimeT(t, work, "src/other.js", old)
502
- chtimeT(t, work, ".devrites/features/defslug/evidence.md", newer)
503
- (goldenCase{"default-slug", []string{"evidence-fresh"}, okMsg, 0}).assert(t, work)
504
-
505
- // An absolute touched path newer than the proof → STALE (exercises the
506
- // absolute-path branch, not just repo-relative resolution).
507
- absPath := filepath.Join(work, "absnew.js")
508
- writeFile(t, work, "absnew.js", "x\n")
509
- writeFile(t, work, ".devrites/features/abs/touched-files.md", "# touched\n- `"+absPath+"`\n")
510
- writeFile(t, work, ".devrites/features/abs/evidence.md", "# evidence\n")
511
- chtimeT(t, work, ".devrites/features/abs/evidence.md", old)
512
- chtimeT(t, work, "absnew.js", newer)
513
- (goldenCase{"absolute-path-stale", []string{"evidence-fresh", "abs"}, "", 3}).assert(t, work)
514
-
515
- // No workspace directory → exit 5.
516
- (goldenCase{"no-workspace", []string{"evidence-fresh", "ghost"}, "", 5}).assert(t, work)
517
-
518
- // Workspace present but no evidence → exit 5.
519
- mkdirAllT(t, work, ".devrites/features/noev")
520
- (goldenCase{"no-evidence", []string{"evidence-fresh", "noev"}, "", 5}).assert(t, work)
521
-
522
- // Proof present, no touched-files.md → nothing to compare, exit 0.
523
- writeFile(t, work, ".devrites/features/notf/evidence.md", "# evidence\n")
524
- (goldenCase{"no-touched-files", []string{"evidence-fresh", "notf"},
525
- "evidence-fresh: no touched-files.md: nothing to compare (treating as fresh).\n", 0}).assert(t, work)
526
- }
527
-
528
- // mkdirAllT creates an (empty) directory under workdir.
529
- func mkdirAllT(t *testing.T, workdir, rel string) {
530
- t.Helper()
531
- if err := os.MkdirAll(filepath.Join(workdir, rel), 0o755); err != nil {
532
- t.Fatal(err)
533
- }
534
- }
535
-
536
- // chtimeT sets a file's mtime (and atime) so freshness comparisons are
537
- // deterministic and identical for both the bash and Go readers.
538
- func chtimeT(t *testing.T, workdir, rel string, mtime time.Time) {
539
- t.Helper()
540
- if err := os.Chtimes(filepath.Join(workdir, rel), mtime, mtime); err != nil {
541
- t.Fatal(err)
542
- }
543
- }
544
-
545
- // fileLines counts newline-terminated lines in a file.
546
- func fileLines(t *testing.T, path string) int {
547
- t.Helper()
548
- b, err := os.ReadFile(path)
549
- if err != nil {
550
- t.Fatal(err)
551
- }
552
- return bytes.Count(b, []byte("\n"))
553
- }
554
-
555
- // lastLine returns the final non-empty line of a file (its trailing newline
556
- // stripped), so a caller can assert the exact bytes of the most recent record.
557
- func lastLine(t *testing.T, path string) string {
558
- t.Helper()
559
- b, err := os.ReadFile(path)
560
- if err != nil {
561
- t.Fatal(err)
562
- }
563
- lines := bytes.Split(bytes.TrimRight(b, "\n"), []byte("\n"))
564
- return string(lines[len(lines)-1])
565
- }
566
-
567
- // ---- coverage -------------------------------------------------------------
568
- //
569
- // Golden: the matrix, the AC id sort, the ";"-joined slices (including the awk
570
- // substring quirk), the UNCOVERED / pending fallbacks, and the exit taxonomy
571
- // are checked against golden snapshots.
572
-
573
- func TestParityCoverage(t *testing.T) {
574
- work := t.TempDir()
575
-
576
- // Mixed coverage + proof, and C-locale AC ordering (AC1, AC10, AC2). The
577
- // "AC1" row also picks up the AC10 slice: the awk match is a substring test
578
- // and the port reproduces it.
579
- writeFeatureFile(t, work, "full", "spec.md",
580
- "## Acceptance criteria\n- [ ] [AC1] alpha\n- [ ] [AC2] beta\n- [ ] [AC10] dec\n")
581
- writeFeatureFile(t, work, "full", "tasks.md",
582
- "## Slice 1: list\n Satisfies: AC1\n## Slice 2: detail\n Satisfies: AC2, AC10\n")
583
- writeFeatureFile(t, work, "full", "seal.md",
584
- "## Acceptance Criteria\n- [x] [AC1] alpha: evidence t1\n- [ ] [AC2] beta\n- [x] [AC10] dec: evidence t3\n")
585
-
586
- // spec only → every AC UNCOVERED + pending.
587
- writeFeatureFile(t, work, "speconly", "spec.md",
588
- "## Acceptance criteria\n- [ ] [AC1] a\n- [ ] [AC2] b\n")
589
-
590
- // flat spec, no [ACn] ids → header + footer, zero rows.
591
- writeFeatureFile(t, work, "flat", "spec.md",
592
- "## Acceptance criteria\n- export returns CSV\n- empty dataset returns 204\n")
593
-
594
- // workspace dir present but no spec.md → exit 2.
595
- makeFeatureDir(t, work, "nospec")
596
-
597
- for _, arg := range []string{
598
- "full", // matrix with mixed proof + the substring quirk
599
- "speconly", // all UNCOVERED / pending
600
- "flat", // no ids → empty matrix body
601
- "nospec", // dir, no spec.md → exit 2
602
- "nonexistent", // no workspace dir → exit 2
603
- } {
604
- c := parityCase{
605
- workdir: work,
606
- env: libRootEnv(work),
607
- goArgs: []string{"coverage", arg},
608
- }
609
- t.Run("arg="+arg, func(t *testing.T) { c.assertEqual(t) })
610
- }
611
-
612
- // No-argument path with no active feature → "no active workspace", exit 2.
613
- (parityCase{
614
- workdir: work,
615
- env: libRootEnv(work),
616
- goArgs: []string{"coverage"},
617
- }).assertEqual(t)
618
- }
619
-
620
- // TestCoverageGolden asserts the exact matrix bytes with an inline expectation
621
- // (fixtures chosen without an AC1/AC10 collision so the golden reads naturally;
622
- // the substring quirk is exercised by TestParityCoverage's "full" fixture).
623
- func TestCoverageGolden(t *testing.T) {
624
- work := t.TempDir()
625
- const base = ".devrites/features/"
626
-
627
- writeFile(t, work, base+"g/spec.md",
628
- "## Acceptance criteria\n- [ ] [AC1] a\n- [ ] [AC2] b\n- [ ] [AC3] c\n")
629
- writeFile(t, work, base+"g/tasks.md",
630
- "## Slice 1: list\n Satisfies: AC1\n## Slice 2: detail\n Satisfies: AC2, AC3\n")
631
- writeFile(t, work, base+"g/seal.md",
632
- "## Acceptance Criteria\n- [x] [AC1] a: evidence t1\n- [x] [AC2] b: evidence t2\n- [ ] [AC3] c\n")
633
-
634
- const wantG = "# Coverage matrix: g\n\n" +
635
- "| AC | Slice(s) | Proven in seal? |\n" +
636
- "|----|----------|-----------------|\n" +
637
- "| AC1 | Slice 1: list | yes |\n" +
638
- "| AC2 | Slice 2: detail | yes |\n" +
639
- "| AC3 | Slice 2: detail | pending |\n\n" +
640
- "_Generated by devrites-engine coverage from spec.md / tasks.md / seal.md. UNCOVERED rows block the analyze gate in /rite-vet (Claude) / $rite-vet (Codex)._\n"
641
- (goldenCase{"full-matrix", []string{"coverage", "g"}, wantG, 0}).assert(t, work)
642
-
643
- // spec only → UNCOVERED / pending fallbacks.
644
- writeFile(t, work, base+"u/spec.md", "## Acceptance criteria\n- [ ] [AC1] a\n")
645
- const wantU = "# Coverage matrix: u\n\n" +
646
- "| AC | Slice(s) | Proven in seal? |\n" +
647
- "|----|----------|-----------------|\n" +
648
- "| AC1 | (UNCOVERED) | pending |\n\n" +
649
- "_Generated by devrites-engine coverage from spec.md / tasks.md / seal.md. UNCOVERED rows block the analyze gate in /rite-vet (Claude) / $rite-vet (Codex)._\n"
650
- (goldenCase{"uncovered", []string{"coverage", "u"}, wantU, 0}).assert(t, work)
651
- }
652
-
653
- // ---- doubt-coverage -------------------------------------------------------
654
- //
655
- // Golden: the decisions.md `doubt: MISSING` short-circuit (checked first), the
656
- // no-log pass, the wright/doubt count line, and the 0/1/2/3 exit taxonomy are
657
- // checked against golden snapshots.
658
-
659
- func TestParityDoubtCoverage(t *testing.T) {
660
- work := t.TempDir()
661
-
662
- // decisions.md MISSING → exit 3, and it wins even over the footprint log.
663
- writeFeatureFile(t, work, "missing", "decisions.md",
664
- "## Decisions stood\n- use flock — doubt: MISSING\n")
665
- writeFeatureFile(t, work, "missing", "footprint.log", "1000 wright 01\n")
666
-
667
- // dir exists, no log / decisions → "no footprint log" pass.
668
- makeFeatureDir(t, work, "nolog")
669
-
670
- // wright dispatch(es), zero doubt → exit 1.
671
- writeFeatureFile(t, work, "nodoubt", "footprint.log",
672
- "1000 wright 01\n1000 reviewer code-reviewer\n1000 wright 02\n")
673
-
674
- // wright + doubt → exit 0.
675
- writeFeatureFile(t, work, "doubted", "footprint.log", "1000 wright 01\n1000 doubt d1\n")
676
-
677
- // zero wright (only reviewers) → exit 0, count line "0 wright · N doubt".
678
- writeFeatureFile(t, work, "nowright", "footprint.log",
679
- "1000 reviewer code-reviewer\n1000 doubt d1\n")
680
-
681
- for _, arg := range []string{
682
- "missing", "nolog",
683
- "nodoubt", "doubted", "nowright",
684
- "ghost", // no workspace at all → "no footprint log" pass
685
- } {
686
- c := parityCase{
687
- workdir: work,
688
- env: libRootEnv(work),
689
- goArgs: []string{"doubt-coverage", arg},
690
- }
691
- t.Run("arg="+arg, func(t *testing.T) { c.assertEqual(t) })
692
- }
693
-
694
- // No-slug usage path → exit 2.
695
- (parityCase{
696
- workdir: work,
697
- env: libRootEnv(work),
698
- goArgs: []string{"doubt-coverage"},
699
- }).assertEqual(t)
700
- }
701
-
702
- // TestDoubtCoverageGolden asserts each verdict's exact stdout inline: the
703
- // SKIPPED / no-log messages and the "no doubt ran" prompt.
704
- func TestDoubtCoverageGolden(t *testing.T) {
705
- work := t.TempDir()
706
- const base = ".devrites/features/"
707
-
708
- writeFile(t, work, base+"miss/decisions.md", "- x — doubt: MISSING\n")
709
- mkdirAllT(t, work, base+"empty")
710
- writeFile(t, work, base+"nd/footprint.log", "1000 wright 01\n1000 wright 02\n")
711
- writeFile(t, work, base+"ok/footprint.log", "1000 wright 01\n1000 doubt d1\n")
712
-
713
- for _, gc := range []goldenCase{
714
- {"skipped", []string{"doubt-coverage", "miss"},
715
- "doubt-coverage: SKIPPED: a '## Decisions stood' entry in decisions.md has doubt: MISSING.\n" +
716
- "A decision was stood and recorded but never doubted. Re-dispatch doubt or escalate.\n", 3},
717
- {"no-log", []string{"doubt-coverage", "empty"},
718
- "doubt-coverage: no footprint log: nothing to assess (pass)\n", 0},
719
- {"no-doubt-ran", []string{"doubt-coverage", "nd"},
720
- "doubt-coverage: 2 wright · 0 doubt\n" +
721
- "doubt-coverage: no doubt dispatched across 2 wright run(s). Either every slice's\n" +
722
- "'Decisions stood' was genuinely empty, or doubt was skipped: verify against decisions.md.\n", 1},
723
- {"doubted", []string{"doubt-coverage", "ok"},
724
- "doubt-coverage: 1 wright · 1 doubt\n", 0},
725
- } {
726
- t.Run(gc.name, func(t *testing.T) { gc.assert(t, work) })
727
- }
728
- }
729
-
730
- // ---- preamble -------------------------------------------------------------
731
- //
732
- // Golden: the workspace-state orientation: the header, verbatim state.md (with
733
- // and without a trailing newline), the fixed artifact-present order, the AFK/HITL
734
- // run mode with verbatim config lines, and the questions-by-gate tally: are
735
- // checked against golden snapshots.
736
-
737
- func TestParityPreamble(t *testing.T) {
738
- // A HITL workspace (no .devrites/AFK) exercising most branches.
739
- hitl := t.TempDir()
740
- writeFeatureFile(t, hitl, "full", "state.md", "- Phase: build\n- Status: running\n- Next step: implement slice 3\n")
741
- writeFeatureFile(t, hitl, "full", "spec.md", "# spec\n")
742
- writeFeatureFile(t, hitl, "full", "plan.md", "# plan\n")
743
- writeFeatureFile(t, hitl, "full", "tasks.md", "# tasks\n")
744
- writeFeatureFile(t, hitl, "full", "questions.md",
745
- "## q-1\nstatus: open\ngate: blocking\n\n"+
746
- "## q-2\nstatus: resolved\ngate: validating\n\n"+
747
- "## q-3\nstatus: open\ngate: advisory\n\n"+
748
- "## q-4\nstatus: open\ngate: blocking\n## Notes\nprose\n")
749
- // questions.md ending on an OPEN q- block (no closing heading): exercises the
750
- // awk END-finalize path.
751
- writeFeatureFile(t, hitl, "openend", "state.md", "- Phase: spec\n")
752
- writeFeatureFile(t, hitl, "openend", "questions.md",
753
- "## q-1\nstatus: resolved\ngate: blocking\n\n## q-2\nstatus: open\ngate: escalating\n")
754
- // state.md with NO trailing newline: `cat` must not add one before the blank line.
755
- writeFeatureFile(t, hitl, "nonl", "state.md", "- Phase: spec")
756
- // A workspace directory with no state.md / questions.md.
757
- makeFeatureDir(t, hitl, "bare")
758
- writeFile(t, hitl, ".devrites/ACTIVE", "full\n")
759
-
760
- for _, arg := range []string{"full", "openend", "nonl", "bare", "ghost"} {
761
- c := parityCase{
762
- workdir: hitl,
763
- env: libRootEnv(hitl),
764
- goArgs: []string{"preamble", arg},
765
- }
766
- t.Run("hitl/"+arg, func(t *testing.T) { c.assertEqual(t) })
767
- }
768
- // No-arg path resolves the slug from ACTIVE.
769
- t.Run("hitl/active", func(t *testing.T) {
770
- (parityCase{workdir: hitl, env: libRootEnv(hitl), goArgs: []string{"preamble"}}).assertEqual(t)
771
- })
772
-
773
- // An AFK workspace: the sentinel plus verbatim (non-comment) config lines.
774
- afk := t.TempDir()
775
- writeFeatureFile(t, afk, "a", "state.md", "- Phase: prove\n")
776
- writeFile(t, afk, ".devrites/AFK", "# afk config\nmax-slices: 3\n\nescalate: true\n")
777
- t.Run("afk/a", func(t *testing.T) {
778
- (parityCase{workdir: afk, env: libRootEnv(afk), goArgs: []string{"preamble", "a"}}).assertEqual(t)
779
- })
780
- }
781
-
782
- // ---- progress -------------------------------------------------------------
783
- //
784
- // Golden: the header rule width, the slice meter (round-half math, ✅ ALL BUILT
785
- // vs the last-built tail), and the flow ribbon (conditional temper/vet, the
786
- // explicit plan and terminal done cursor rules) are checked against golden snapshots.
787
-
788
- func TestParityProgress(t *testing.T) {
789
- work := t.TempDir()
790
-
791
- sliceBlock := "\n## Slice progress\n" +
792
- "- [x] Slice 1: list · built\n" +
793
- "- [x] Slice 2: detail · built\n" +
794
- "- [ ] Slice 3: polish · pending\n" +
795
- "## Next\n- something\n"
796
-
797
- // build phase, 2/3 slices, temper (strategy.md) + vet (eng-review.md) present.
798
- writeFeatureFile(t, work, "mid", "state.md", "- Phase: build"+sliceBlock)
799
- writeFeatureFile(t, work, "mid", "strategy.md", "# strategy\n")
800
- writeFeatureFile(t, work, "mid", "eng-review.md", "# eng-review\n")
801
-
802
- // all built → ✅ ALL BUILT; no temper/vet artifacts → shorter ribbon.
803
- writeFeatureFile(t, work, "allbuilt", "state.md",
804
- "- Phase: build\n## Slice progress\n- [x] Slice 1: a · built\n- [x] Slice 2: b · built\n")
805
-
806
- // no slices at all → meter skipped entirely.
807
- writeFeatureFile(t, work, "noslice", "state.md", "- Phase: spec\n")
808
-
809
- // phase variants exercising the cursor rules.
810
- writeFeatureFile(t, work, "done", "state.md", "- Phase: done\n")
811
- writeFeatureFile(t, work, "plan", "state.md", "- Phase: plan"+sliceBlock)
812
- writeFeatureFile(t, work, "seal", "state.md", "- Phase: seal\n")
813
- // missing Phase → defaults to "spec".
814
- writeFeatureFile(t, work, "nophase", "state.md", "- Status: running\n")
815
-
816
- for _, arg := range []string{"mid", "allbuilt", "noslice", "done", "plan", "seal", "nophase", "ghost"} {
817
- c := parityCase{
818
- workdir: work,
819
- env: libRootEnv(work),
820
- goArgs: []string{"progress", arg},
821
- }
822
- t.Run("arg="+arg, func(t *testing.T) { c.assertEqual(t) })
823
- }
824
- }
825
-
826
- // ---- stuck ----------------------------------------------------------------
827
- //
828
- // Golden: `check` reads only the sha1 column, so a fixture log with controlled
829
- // hash tokens drives every verdict (too-few / identical / ping-pong / dominant /
830
- // varied / custom window) and the 0/3 exit split, checked against golden
831
- // snapshots. `log` is exercised separately (its stdout is empty; its side effect
832
- // carries a nondeterministic timestamp, so only the sha1 column is snapshotted).
833
-
834
- func TestParityStuckCheck(t *testing.T) {
835
- work := t.TempDir()
836
-
837
- // Each record is "<epoch> <tool> <hash>"; check only reads the hash ($3).
838
- rec := func(h string) string { return "1700000000 Bash " + h + "\n" }
839
- writeFeatureFile(t, work, "few", "action.log", rec("a")+rec("a")) // NR < win(4)
840
- writeFeatureFile(t, work, "identical", "action.log", rec("a")+rec("a")+rec("a")+rec("a")) // last 4 identical
841
- writeFeatureFile(t, work, "pingpong", "action.log", rec("a")+rec("b")+rec("a")+rec("b")+rec("a")+rec("b"))
842
- writeFeatureFile(t, work, "dominant", "action.log", rec("a")+rec("a")+rec("a")+rec("a")+rec("a")+rec("a")+rec("b")+rec("c"))
843
- writeFeatureFile(t, work, "varied", "action.log", rec("a")+rec("b")+rec("c")+rec("d")+rec("e"))
844
- writeFeatureFile(t, work, "varied4", "action.log", rec("a")+rec("b")+rec("c")+rec("d")) // 4 distinct
845
- makeFeatureDir(t, work, "nolog")
846
-
847
- type cse struct {
848
- name string
849
- goArgs []string
850
- }
851
- for _, tc := range []cse{
852
- {"few", []string{"check", "few"}},
853
- {"identical", []string{"check", "identical"}},
854
- {"pingpong", []string{"check", "pingpong"}},
855
- {"dominant", []string{"check", "dominant"}},
856
- {"varied", []string{"check", "varied"}},
857
- {"nolog", []string{"check", "nolog"}},
858
- {"ghost", []string{"check", "ghost"}},
859
- {"custom-window-2", []string{"check", "few", "2"}}, // win=2 → last 2 identical → STUCK
860
- // Pathological window tokens: the numeric-string vs string comparison and
861
- // the verbatim `win` echo: edge cases the port must reproduce.
862
- {"window-4x-varied4", []string{"check", "varied4", "4x"}},
863
- {"window-2.5-varied4", []string{"check", "varied4", "2.5"}},
864
- {"window-leadspace-varied4", []string{"check", "varied4", " 4"}},
865
- {"window-04-identical", []string{"check", "identical", "04"}},
866
- {"window-plus4-identical", []string{"check", "identical", "+4"}},
867
- {"no-cmd", nil},
868
- {"no-slug", []string{"check"}},
869
- {"bad-cmd", []string{"bogus", "few"}},
870
- } {
871
- c := parityCase{workdir: work, env: libRootEnv(work), goArgs: append([]string{"stuck"}, tc.goArgs...)}
872
- t.Run(tc.name, func(t *testing.T) { c.assertEqual(t) })
873
- }
874
- }
875
-
876
- // TestStuckLogHashParity proves the `log` side effect: it appends a record whose
877
- // sha1 column is deterministic given the logged target, so that column is
878
- // snapshotted (the epoch column is nondeterministic and excluded by reading only
879
- // field 3). A second log appends a second record, and logging to a missing
880
- // workspace is a silent no-op.
881
- func TestStuckLogHashParity(t *testing.T) {
882
- field3 := func(t *testing.T, path string) string {
883
- t.Helper()
884
- fields := bytes.Fields(bytes.TrimRight(readFileT(t, path), "\n"))
885
- if len(fields) < 3 {
886
- t.Fatalf("log line has <3 fields: %q", string(readFileT(t, path)))
887
- }
888
- return string(fields[2])
889
- }
890
-
891
- // The new-schema features layout under DEVRITES_ROOT.
892
- gw := t.TempDir()
893
- mkdirAllT(t, gw, ".devrites/features/feat")
894
- goLog := filepath.Join(gw, ".devrites/features/feat/action.log")
895
- runArgv(t, gw, libRootEnv(gw), "", binPath, "stuck", "log", "feat", "Bash", "src/a.js")
896
- goHash := field3(t, goLog)
897
-
898
- // Snapshot the sha1 column (the epoch column is masked by reading only field 3).
899
- assertGoldenKey(t, t.Name(), goHash)
900
- if len(goHash) != 40 {
901
- t.Errorf("sha1 hex = %q, want 40 chars", goHash)
902
- }
903
-
904
- // A second log appends a second record.
905
- runArgv(t, gw, libRootEnv(gw), "", binPath, "stuck", "log", "feat", "Edit", "src/b.js")
906
- if n := fileLines(t, goLog); n != 2 {
907
- t.Errorf("after two logs: %d lines, want 2", n)
908
- }
909
- // Logging to a missing workspace is a no-op (never fails the caller).
910
- if _, code := runArgv(t, gw, libRootEnv(gw), "", binPath, "stuck", "log", "ghost", "Bash", "x"); code != 0 {
911
- t.Errorf("log on missing workspace: exit=%d, want 0", code)
912
- }
913
- if isFileT(filepath.Join(gw, ".devrites/features/ghost/action.log")) {
914
- t.Error("log on missing workspace created a file; must be a no-op")
915
- }
916
- }
917
-
918
- func readFileT(t *testing.T, path string) []byte {
919
- t.Helper()
920
- b, err := os.ReadFile(path)
921
- if err != nil {
922
- t.Fatal(err)
923
- }
924
- return b
925
- }
926
-
927
- func isFileT(path string) bool {
928
- fi, err := os.Stat(path)
929
- return err == nil && !fi.IsDir()
930
- }