devrites 3.0.7 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +82 -50
  3. package/SECURITY.md +31 -29
  4. package/docs/adr/0001-go-engine-as-control-plane.md +1 -1
  5. package/docs/adr/0002-dual-host-harness.md +1 -1
  6. package/docs/adr/0004-state-schema-phases-sections.md +1 -2
  7. package/docs/adr/0006-clock-seam-and-engine-ci-gates.md +3 -4
  8. package/docs/adr/0009-prebuild-decision-coverage-and-readiness.md +67 -0
  9. package/docs/adr/0010-agent-first-fresh-context-orchestration.md +71 -0
  10. package/docs/adr/0011-define-plan-transition-rights.md +28 -0
  11. package/docs/adr/0012-semantic-workspace-upgrades.md +77 -0
  12. package/docs/adr/README.md +4 -0
  13. package/docs/agents/triage-labels.md +7 -7
  14. package/docs/architecture.md +179 -141
  15. package/docs/cli.md +47 -12
  16. package/docs/command-map.md +61 -38
  17. package/docs/engine/agent-contract.md +92 -15
  18. package/docs/engine/commands.md +248 -72
  19. package/docs/engine/state-schema.md +52 -23
  20. package/docs/engine/workspace-schema.md +103 -15
  21. package/docs/extensions.md +1 -1
  22. package/docs/flow.md +86 -51
  23. package/docs/harness-compliance.md +29 -5
  24. package/docs/orchestration.md +107 -79
  25. package/docs/quick-reference.md +11 -3
  26. package/docs/release.md +4 -3
  27. package/docs/skills.md +67 -38
  28. package/docs/usage.md +84 -39
  29. package/engine/cmd/releasepack/main.go +219 -0
  30. package/engine/cmd/releasepack/main_test.go +170 -0
  31. package/engine/commands.go +170 -23
  32. package/engine/git_guard.go +187 -0
  33. package/engine/git_guard_test.go +283 -0
  34. package/engine/hookpolicy.go +53 -55
  35. package/engine/hookpolicy_test.go +91 -1
  36. package/engine/hooks.go +296 -75
  37. package/engine/hooks_events_test.go +276 -6
  38. package/engine/hooks_workspace.go +640 -159
  39. package/engine/internal/devritespaths/paths.go +65 -10
  40. package/engine/internal/devritespaths/paths_test.go +110 -0
  41. package/engine/internal/doctor/doctor.go +153 -23
  42. package/engine/internal/doctor/doctor_test.go +74 -0
  43. package/engine/internal/forge/forge.go +940 -0
  44. package/engine/internal/forge/forge_test.go +576 -0
  45. package/engine/internal/forge/git.go +245 -0
  46. package/engine/internal/forge/liveness_unix.go +48 -0
  47. package/engine/internal/forge/liveness_windows.go +67 -0
  48. package/engine/internal/forge/manifest.go +402 -0
  49. package/engine/internal/gate/gate.go +90 -71
  50. package/engine/internal/gate/gate_test.go +71 -2
  51. package/engine/internal/harness/compliance.go +18 -24
  52. package/engine/internal/harness/harness.go +37 -44
  53. package/engine/internal/harness/harness_test.go +21 -5
  54. package/engine/internal/install/install.go +486 -38
  55. package/engine/internal/install/install_test.go +383 -10
  56. package/engine/internal/iohooks/iohooks.go +350 -59
  57. package/engine/internal/iohooks/iohooks_test.go +421 -1
  58. package/engine/internal/lib/buildreadiness.go +43 -18
  59. package/engine/internal/lib/clarifyreturn.go +91 -0
  60. package/engine/internal/lib/clarifyreturn_test.go +123 -0
  61. package/engine/internal/lib/context.go +54 -15
  62. package/engine/internal/lib/cursor_compat_test.go +8 -0
  63. package/engine/internal/lib/extensions.go +2 -3
  64. package/engine/internal/lib/gitauthority.go +601 -0
  65. package/engine/internal/lib/gitauthority_test.go +346 -0
  66. package/engine/internal/lib/jsonout.go +25 -11
  67. package/engine/internal/lib/jsonout_test.go +16 -0
  68. package/engine/internal/lib/lanes.go +14 -8
  69. package/engine/internal/lib/observability_test.go +358 -0
  70. package/engine/internal/lib/packageexistence.go +151 -35
  71. package/engine/internal/lib/packageexistence_test.go +163 -0
  72. package/engine/internal/lib/progress.go +11 -9
  73. package/engine/internal/lib/provenance.go +462 -0
  74. package/engine/internal/lib/provenance_test.go +154 -0
  75. package/engine/internal/lib/readiness_contract.json +118 -0
  76. package/engine/internal/lib/readinessartifact.go +533 -0
  77. package/engine/internal/lib/readinessartifact_test.go +422 -0
  78. package/engine/internal/lib/reconcile.go +712 -88
  79. package/engine/internal/lib/reconcile_test.go +335 -16
  80. package/engine/internal/lib/recoveryattempts.go +298 -0
  81. package/engine/internal/lib/recoveryattempts_test.go +215 -0
  82. package/engine/internal/lib/resolve.go +23 -19
  83. package/engine/internal/lib/runbook_context_test.go +20 -0
  84. package/engine/internal/lib/session.go +701 -9
  85. package/engine/internal/lib/session_test.go +80 -13
  86. package/engine/internal/lib/testintegrity.go +33 -37
  87. package/engine/internal/lib/testintegrity_test.go +63 -1
  88. package/engine/internal/migrate/migrate.go +81 -1
  89. package/engine/internal/migrate/migrate_test.go +22 -1
  90. package/engine/internal/reason/reason.go +180 -0
  91. package/engine/internal/reason/reason_test.go +35 -0
  92. package/engine/internal/rootfacts/facts.go +466 -0
  93. package/engine/internal/rootfacts/facts_test.go +306 -0
  94. package/engine/internal/safepath/safepath.go +55 -0
  95. package/engine/internal/safepath/safepath_test.go +69 -0
  96. package/engine/internal/safepath/safepath_windows_test.go +26 -0
  97. package/engine/internal/state/clarify_transition.go +165 -0
  98. package/engine/internal/state/clarify_transition_test.go +130 -0
  99. package/engine/internal/state/cmd/workflowmanifest/main.go +12 -8
  100. package/engine/internal/state/cursor.go +58 -0
  101. package/engine/internal/state/cursor_test.go +42 -1
  102. package/engine/internal/state/feature.go +35 -48
  103. package/engine/internal/state/schema.go +90 -37
  104. package/engine/internal/state/snapshot.go +18 -2
  105. package/engine/internal/state/state_test.go +187 -7
  106. package/engine/internal/state/status.go +48 -11
  107. package/engine/internal/state/workflow_manifest.json +231 -50
  108. package/engine/internal/toolpolicy/classifier.go +533 -0
  109. package/engine/internal/toolpolicy/classifier_test.go +424 -0
  110. package/engine/internal/toolpolicy/git.go +616 -0
  111. package/engine/internal/toolpolicy/scanner.go +382 -0
  112. package/engine/main.go +160 -77
  113. package/engine/observability_cli_test.go +52 -0
  114. package/engine/root_routing_test.go +277 -0
  115. package/engine/testdata/golden/TestParityBuildReadiness/arg=approved.golden +1 -1
  116. package/engine/testdata/golden/TestParityBuildReadiness/arg=emptystatus.golden +1 -1
  117. package/engine/testdata/golden/TestParityBuildReadiness/arg=legacycontract.golden +1 -0
  118. package/engine/testdata/golden/TestParityBuildReadiness/arg=noclarify.golden +1 -0
  119. package/engine/testdata/golden/TestParityBuildReadiness/arg=novet.golden +1 -0
  120. package/engine/testdata/golden/TestParityBuildReadiness/arg=stalevet.golden +1 -0
  121. package/engine/testdata/golden/TestParityBuildReadiness/arg=trailhash.golden +1 -1
  122. package/engine/testdata/golden/TestParityBuildReadiness/arg=trailpipe.golden +1 -1
  123. package/engine/testdata/golden/TestParityBuildReadiness/arg=vetnotready.golden +1 -0
  124. package/engine/testdata/golden/TestParityProgress/arg=allbuilt.golden +1 -1
  125. package/engine/testdata/golden/TestParityProgress/arg=done.golden +1 -1
  126. package/engine/testdata/golden/TestParityProgress/arg=mid.golden +1 -1
  127. package/engine/testdata/golden/TestParityProgress/arg=nophase.golden +1 -1
  128. package/engine/testdata/golden/TestParityProgress/arg=noslice.golden +1 -1
  129. package/engine/testdata/golden/TestParityProgress/arg=plan.golden +1 -1
  130. package/engine/testdata/golden/TestParityProgress/arg=seal.golden +1 -1
  131. package/engine/testdata/golden/TestParityReconcile/check-clean.golden +1 -1
  132. package/engine/testdata/golden/TestParityReconcile/inline-fallback.golden +1 -0
  133. package/engine/testdata/golden/TestParityReconcile/snapshot-no-allowlist.golden +1 -0
  134. package/engine/testdata/golden/TestParityWrightScope/devrites-edit-denied.golden +2 -0
  135. package/engine/testdata/golden/TestParityWrightScope/out-of-scope-enforce-denies.golden +1 -1
  136. package/engine/tests/adr_0011_define_plan_test.go +30 -0
  137. package/engine/tests/budget_test.go +19 -8
  138. package/engine/tests/concurrency_cli_test.go +7 -1
  139. package/engine/tests/doctor_cli_test.go +148 -2
  140. package/engine/tests/forge_cli_test.go +463 -0
  141. package/engine/tests/gate_test.go +63 -8
  142. package/engine/tests/hook_test.go +260 -8
  143. package/engine/tests/hooks_io_test.go +94 -3
  144. package/engine/tests/json_contract_test.go +127 -2
  145. package/engine/tests/migrate_cli_test.go +2 -2
  146. package/engine/tests/parity_buildreadiness_test.go +167 -10
  147. package/engine/tests/parity_learnings_test.go +16 -17
  148. package/engine/tests/parity_reconcile_test.go +20 -17
  149. package/engine/tests/parity_resolve_test.go +12 -11
  150. package/engine/tests/parity_test.go +21 -17
  151. package/pack/.claude/agents/devrites-code-reviewer.md +62 -48
  152. package/pack/.claude/agents/devrites-devex-reviewer.md +69 -53
  153. package/pack/.claude/agents/devrites-doubt-reviewer.md +29 -22
  154. package/pack/.claude/agents/devrites-evidence-scout.md +69 -0
  155. package/pack/.claude/agents/devrites-forge-judge.md +74 -61
  156. package/pack/.claude/agents/devrites-frontend-reviewer.md +48 -39
  157. package/pack/.claude/agents/devrites-performance-reviewer.md +49 -40
  158. package/pack/.claude/agents/devrites-plan-drafter.md +73 -0
  159. package/pack/.claude/agents/devrites-plan-reviewer.md +80 -47
  160. package/pack/.claude/agents/devrites-proof-runner.md +74 -0
  161. package/pack/.claude/agents/devrites-retrospector.md +48 -45
  162. package/pack/.claude/agents/devrites-security-auditor.md +46 -36
  163. package/pack/.claude/agents/devrites-simplifier-reviewer.md +50 -46
  164. package/pack/.claude/agents/devrites-slice-wright.md +153 -165
  165. package/pack/.claude/agents/devrites-spec-reviewer.md +34 -32
  166. package/pack/.claude/agents/devrites-strategy-reviewer.md +63 -34
  167. package/pack/.claude/agents/devrites-test-analyst.md +40 -30
  168. package/pack/.claude/agents/devrites-upgrade-planner.md +100 -0
  169. package/pack/.claude/settings.json +2 -1
  170. package/pack/.claude/skills/devrites-audit/SKILL.md +40 -61
  171. package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +24 -13
  172. package/pack/.claude/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
  173. package/pack/.claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
  174. package/pack/.claude/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
  175. package/pack/.claude/skills/devrites-doubt/SKILL.md +25 -17
  176. package/pack/.claude/skills/devrites-interview/SKILL.md +53 -52
  177. package/pack/.claude/skills/devrites-lib/SKILL.md +12 -9
  178. package/pack/.claude/skills/devrites-lib/reference/intent-map.md +4 -2
  179. package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
  180. package/pack/.claude/skills/devrites-lib/reference/reply-contract.md +8 -1
  181. package/pack/.claude/skills/devrites-lib/reference/standards/README.md +38 -55
  182. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
  183. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +200 -190
  184. package/pack/.claude/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
  185. package/pack/.claude/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
  186. package/pack/.claude/skills/devrites-lib/reference/standards/code-review.md +16 -52
  187. package/pack/.claude/skills/devrites-lib/reference/standards/coding-style.md +2 -10
  188. package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
  189. package/pack/.claude/skills/devrites-lib/reference/standards/core.md +23 -18
  190. package/pack/.claude/skills/devrites-lib/reference/standards/deprecation.md +17 -57
  191. package/pack/.claude/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
  192. package/pack/.claude/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
  193. package/pack/.claude/skills/devrites-lib/reference/standards/hooks.md +3 -14
  194. package/pack/.claude/skills/devrites-lib/reference/standards/patterns.md +9 -25
  195. package/pack/.claude/skills/devrites-lib/reference/standards/performance.md +0 -9
  196. package/pack/.claude/skills/devrites-lib/reference/standards/principles.md +1 -3
  197. package/pack/.claude/skills/devrites-lib/reference/standards/security.md +17 -7
  198. package/pack/.claude/skills/devrites-lib/reference/standards/testing.md +1 -27
  199. package/pack/.claude/skills/devrites-lib/reference/standards/tooling.md +46 -50
  200. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +40 -10
  201. package/pack/.claude/skills/devrites-source-driven/SKILL.md +23 -22
  202. package/pack/.claude/skills/rite/SKILL.md +10 -6
  203. package/pack/.claude/skills/rite/reference/menu.md +13 -7
  204. package/pack/.claude/skills/rite-adopt/SKILL.md +33 -37
  205. package/pack/.claude/skills/rite-autocomplete/SKILL.md +33 -28
  206. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +21 -21
  207. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
  208. package/pack/.claude/skills/rite-build/SKILL.md +35 -30
  209. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +41 -39
  210. package/pack/.claude/skills/rite-build/reference/evidence-standard.md +10 -0
  211. package/pack/.claude/skills/rite-build/reference/forge.md +186 -156
  212. package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +4 -3
  213. package/pack/.claude/skills/rite-build/reference/phase-contract.md +96 -175
  214. package/pack/.claude/skills/rite-build/reference/spec-drift-guard.md +10 -4
  215. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +129 -134
  216. package/pack/.claude/skills/rite-clarify/SKILL.md +90 -0
  217. package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +61 -0
  218. package/pack/.claude/skills/rite-converge/SKILL.md +35 -25
  219. package/pack/.claude/skills/rite-define/SKILL.md +58 -32
  220. package/pack/.claude/skills/rite-define/reference/gates.md +16 -15
  221. package/pack/.claude/skills/rite-define/reference/plan-template.md +18 -8
  222. package/pack/.claude/skills/rite-frame/reference/failure-modes.md +22 -24
  223. package/pack/.claude/skills/rite-plan/SKILL.md +47 -16
  224. package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +4 -0
  225. package/pack/.claude/skills/rite-polish/SKILL.md +27 -23
  226. package/pack/.claude/skills/rite-prototype/SKILL.md +25 -26
  227. package/pack/.claude/skills/rite-prove/SKILL.md +27 -17
  228. package/pack/.claude/skills/rite-resolve/SKILL.md +12 -11
  229. package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +3 -0
  230. package/pack/.claude/skills/rite-review/SKILL.md +37 -28
  231. package/pack/.claude/skills/rite-seal/reference/phase-contract.md +27 -92
  232. package/pack/.claude/skills/rite-seal/reference/risk-and-rollback.md +13 -0
  233. package/pack/.claude/skills/rite-ship/reference/design-memory.md +31 -36
  234. package/pack/.claude/skills/rite-spec/SKILL.md +84 -135
  235. package/pack/.claude/skills/rite-spec/reference/investigation.md +37 -33
  236. package/pack/.claude/skills/rite-spec/reference/question-protocol.md +6 -2
  237. package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +25 -24
  238. package/pack/.claude/skills/rite-spec/reference/spec-template.md +9 -2
  239. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +13 -3
  240. package/pack/.claude/skills/rite-temper/SKILL.md +62 -47
  241. package/pack/.claude/skills/rite-temper/reference/review-dimensions.md +24 -22
  242. package/pack/.claude/skills/rite-upgrade/SKILL.md +125 -0
  243. package/pack/.claude/skills/rite-vet/SKILL.md +114 -113
  244. package/pack/.claude/skills/rite-vet/reference/artifacts.md +50 -9
  245. package/pack/.claude/skills/rite-vet/reference/review-axes.md +39 -37
  246. package/pack/generated/claude/agents/devrites-code-reviewer.md +62 -48
  247. package/pack/generated/claude/agents/devrites-devex-reviewer.md +69 -53
  248. package/pack/generated/claude/agents/devrites-doubt-reviewer.md +29 -22
  249. package/pack/generated/claude/agents/devrites-evidence-scout.md +69 -0
  250. package/pack/generated/claude/agents/devrites-forge-judge.md +74 -61
  251. package/pack/generated/claude/agents/devrites-frontend-reviewer.md +48 -39
  252. package/pack/generated/claude/agents/devrites-performance-reviewer.md +49 -40
  253. package/pack/generated/claude/agents/devrites-plan-drafter.md +73 -0
  254. package/pack/generated/claude/agents/devrites-plan-reviewer.md +80 -47
  255. package/pack/generated/claude/agents/devrites-proof-runner.md +74 -0
  256. package/pack/generated/claude/agents/devrites-retrospector.md +48 -45
  257. package/pack/generated/claude/agents/devrites-security-auditor.md +46 -36
  258. package/pack/generated/claude/agents/devrites-simplifier-reviewer.md +50 -46
  259. package/pack/generated/claude/agents/devrites-slice-wright.md +153 -165
  260. package/pack/generated/claude/agents/devrites-spec-reviewer.md +34 -32
  261. package/pack/generated/claude/agents/devrites-strategy-reviewer.md +63 -34
  262. package/pack/generated/claude/agents/devrites-test-analyst.md +40 -30
  263. package/pack/generated/claude/agents/devrites-upgrade-planner.md +100 -0
  264. package/pack/generated/claude/settings.json +2 -1
  265. package/pack/generated/claude/skills/devrites-audit/SKILL.md +40 -61
  266. package/pack/generated/claude/skills/devrites-debug-recovery/SKILL.md +24 -13
  267. package/pack/generated/claude/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
  268. package/pack/generated/claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
  269. package/pack/generated/claude/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
  270. package/pack/generated/claude/skills/devrites-doubt/SKILL.md +25 -17
  271. package/pack/generated/claude/skills/devrites-interview/SKILL.md +53 -52
  272. package/pack/generated/claude/skills/devrites-lib/SKILL.md +12 -9
  273. package/pack/generated/claude/skills/devrites-lib/reference/intent-map.md +4 -2
  274. package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
  275. package/pack/generated/claude/skills/devrites-lib/reference/reply-contract.md +8 -1
  276. package/pack/generated/claude/skills/devrites-lib/reference/standards/README.md +38 -55
  277. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
  278. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +200 -190
  279. package/pack/generated/claude/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
  280. package/pack/generated/claude/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
  281. package/pack/generated/claude/skills/devrites-lib/reference/standards/code-review.md +16 -52
  282. package/pack/generated/claude/skills/devrites-lib/reference/standards/coding-style.md +2 -10
  283. package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
  284. package/pack/generated/claude/skills/devrites-lib/reference/standards/core.md +23 -18
  285. package/pack/generated/claude/skills/devrites-lib/reference/standards/deprecation.md +17 -57
  286. package/pack/generated/claude/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
  287. package/pack/generated/claude/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
  288. package/pack/generated/claude/skills/devrites-lib/reference/standards/hooks.md +3 -14
  289. package/pack/generated/claude/skills/devrites-lib/reference/standards/patterns.md +9 -25
  290. package/pack/generated/claude/skills/devrites-lib/reference/standards/performance.md +0 -9
  291. package/pack/generated/claude/skills/devrites-lib/reference/standards/principles.md +1 -3
  292. package/pack/generated/claude/skills/devrites-lib/reference/standards/security.md +17 -7
  293. package/pack/generated/claude/skills/devrites-lib/reference/standards/testing.md +1 -27
  294. package/pack/generated/claude/skills/devrites-lib/reference/standards/tooling.md +46 -50
  295. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +40 -10
  296. package/pack/generated/claude/skills/devrites-source-driven/SKILL.md +23 -22
  297. package/pack/generated/claude/skills/rite/SKILL.md +10 -6
  298. package/pack/generated/claude/skills/rite/reference/menu.md +13 -7
  299. package/pack/generated/claude/skills/rite-adopt/SKILL.md +33 -37
  300. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +33 -28
  301. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +21 -21
  302. package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
  303. package/pack/generated/claude/skills/rite-build/SKILL.md +35 -30
  304. package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +41 -39
  305. package/pack/generated/claude/skills/rite-build/reference/evidence-standard.md +10 -0
  306. package/pack/generated/claude/skills/rite-build/reference/forge.md +186 -156
  307. package/pack/generated/claude/skills/rite-build/reference/one-slice-cycle.md +4 -3
  308. package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +96 -175
  309. package/pack/generated/claude/skills/rite-build/reference/spec-drift-guard.md +10 -4
  310. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +129 -134
  311. package/pack/generated/claude/skills/rite-clarify/SKILL.md +90 -0
  312. package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +61 -0
  313. package/pack/generated/claude/skills/rite-converge/SKILL.md +35 -25
  314. package/pack/generated/claude/skills/rite-define/SKILL.md +58 -32
  315. package/pack/generated/claude/skills/rite-define/reference/gates.md +16 -15
  316. package/pack/generated/claude/skills/rite-define/reference/plan-template.md +18 -8
  317. package/pack/generated/claude/skills/rite-frame/reference/failure-modes.md +22 -24
  318. package/pack/generated/claude/skills/rite-plan/SKILL.md +47 -16
  319. package/pack/generated/claude/skills/rite-plan/reference/task-breakdown.md +4 -0
  320. package/pack/generated/claude/skills/rite-polish/SKILL.md +27 -23
  321. package/pack/generated/claude/skills/rite-prototype/SKILL.md +25 -26
  322. package/pack/generated/claude/skills/rite-prove/SKILL.md +27 -17
  323. package/pack/generated/claude/skills/rite-resolve/SKILL.md +12 -11
  324. package/pack/generated/claude/skills/rite-resolve/reference/answer-protocol.md +3 -0
  325. package/pack/generated/claude/skills/rite-review/SKILL.md +37 -28
  326. package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +27 -92
  327. package/pack/generated/claude/skills/rite-seal/reference/risk-and-rollback.md +13 -0
  328. package/pack/generated/claude/skills/rite-ship/reference/design-memory.md +31 -36
  329. package/pack/generated/claude/skills/rite-spec/SKILL.md +84 -135
  330. package/pack/generated/claude/skills/rite-spec/reference/investigation.md +37 -33
  331. package/pack/generated/claude/skills/rite-spec/reference/question-protocol.md +6 -2
  332. package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +25 -24
  333. package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +9 -2
  334. package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +13 -3
  335. package/pack/generated/claude/skills/rite-temper/SKILL.md +62 -47
  336. package/pack/generated/claude/skills/rite-temper/reference/review-dimensions.md +24 -22
  337. package/pack/generated/claude/skills/rite-upgrade/SKILL.md +125 -0
  338. package/pack/generated/claude/skills/rite-vet/SKILL.md +114 -113
  339. package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +50 -9
  340. package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +39 -37
  341. package/pack/generated/codex/AGENTS.md +5 -2
  342. package/pack/generated/codex/agents/devrites-code-reviewer.toml +69 -47
  343. package/pack/generated/codex/agents/devrites-devex-reviewer.toml +75 -51
  344. package/pack/generated/codex/agents/devrites-doubt-reviewer.toml +35 -20
  345. package/pack/generated/codex/agents/devrites-evidence-scout.toml +75 -0
  346. package/pack/generated/codex/agents/devrites-forge-judge.toml +80 -59
  347. package/pack/generated/codex/agents/devrites-frontend-reviewer.toml +54 -37
  348. package/pack/generated/codex/agents/devrites-performance-reviewer.toml +55 -38
  349. package/pack/generated/codex/agents/devrites-plan-drafter.toml +79 -0
  350. package/pack/generated/codex/agents/devrites-plan-reviewer.toml +82 -47
  351. package/pack/generated/codex/agents/devrites-proof-runner.toml +80 -0
  352. package/pack/generated/codex/agents/devrites-retrospector.toml +54 -43
  353. package/pack/generated/codex/agents/devrites-security-auditor.toml +53 -35
  354. package/pack/generated/codex/agents/devrites-simplifier-reviewer.toml +56 -44
  355. package/pack/generated/codex/agents/devrites-slice-wright.toml +159 -163
  356. package/pack/generated/codex/agents/devrites-spec-reviewer.toml +40 -30
  357. package/pack/generated/codex/agents/devrites-strategy-reviewer.toml +65 -34
  358. package/pack/generated/codex/agents/devrites-test-analyst.toml +46 -28
  359. package/pack/generated/codex/agents/devrites-upgrade-planner.toml +106 -0
  360. package/pack/generated/codex/hooks.json +4 -14
  361. package/pack/generated/codex/skills/devrites-api-interface/SKILL.md +7 -3
  362. package/pack/generated/codex/skills/devrites-audit/SKILL.md +47 -64
  363. package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +7 -3
  364. package/pack/generated/codex/skills/devrites-debug-recovery/SKILL.md +31 -16
  365. package/pack/generated/codex/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
  366. package/pack/generated/codex/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
  367. package/pack/generated/codex/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
  368. package/pack/generated/codex/skills/devrites-doubt/SKILL.md +32 -20
  369. package/pack/generated/codex/skills/devrites-frontend-craft/SKILL.md +7 -3
  370. package/pack/generated/codex/skills/devrites-interview/SKILL.md +60 -55
  371. package/pack/generated/codex/skills/devrites-lib/SKILL.md +19 -12
  372. package/pack/generated/codex/skills/devrites-lib/reference/intent-map.md +4 -2
  373. package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
  374. package/pack/generated/codex/skills/devrites-lib/reference/reply-contract.md +8 -1
  375. package/pack/generated/codex/skills/devrites-lib/reference/standards/README.md +38 -55
  376. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
  377. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +200 -190
  378. package/pack/generated/codex/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
  379. package/pack/generated/codex/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
  380. package/pack/generated/codex/skills/devrites-lib/reference/standards/code-review.md +16 -52
  381. package/pack/generated/codex/skills/devrites-lib/reference/standards/coding-style.md +2 -10
  382. package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
  383. package/pack/generated/codex/skills/devrites-lib/reference/standards/core.md +23 -18
  384. package/pack/generated/codex/skills/devrites-lib/reference/standards/deprecation.md +17 -57
  385. package/pack/generated/codex/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
  386. package/pack/generated/codex/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
  387. package/pack/generated/codex/skills/devrites-lib/reference/standards/hooks.md +3 -14
  388. package/pack/generated/codex/skills/devrites-lib/reference/standards/patterns.md +9 -25
  389. package/pack/generated/codex/skills/devrites-lib/reference/standards/performance.md +0 -9
  390. package/pack/generated/codex/skills/devrites-lib/reference/standards/principles.md +1 -3
  391. package/pack/generated/codex/skills/devrites-lib/reference/standards/security.md +17 -7
  392. package/pack/generated/codex/skills/devrites-lib/reference/standards/testing.md +1 -27
  393. package/pack/generated/codex/skills/devrites-lib/reference/standards/tooling.md +46 -50
  394. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +40 -10
  395. package/pack/generated/codex/skills/devrites-prose-craft/SKILL.md +7 -3
  396. package/pack/generated/codex/skills/devrites-refresh-indexes/SKILL.md +7 -3
  397. package/pack/generated/codex/skills/devrites-source-driven/SKILL.md +29 -24
  398. package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +7 -3
  399. package/pack/generated/codex/skills/rite/SKILL.md +21 -13
  400. package/pack/generated/codex/skills/rite/reference/menu.md +13 -7
  401. package/pack/generated/codex/skills/rite-adopt/SKILL.md +40 -40
  402. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +40 -31
  403. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +21 -21
  404. package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
  405. package/pack/generated/codex/skills/rite-build/SKILL.md +42 -33
  406. package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +41 -39
  407. package/pack/generated/codex/skills/rite-build/reference/evidence-standard.md +10 -0
  408. package/pack/generated/codex/skills/rite-build/reference/forge.md +186 -156
  409. package/pack/generated/codex/skills/rite-build/reference/one-slice-cycle.md +4 -3
  410. package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +96 -175
  411. package/pack/generated/codex/skills/rite-build/reference/spec-drift-guard.md +10 -4
  412. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +129 -134
  413. package/pack/generated/codex/skills/rite-clarify/SKILL.md +106 -0
  414. package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +61 -0
  415. package/pack/generated/codex/skills/rite-converge/SKILL.md +42 -28
  416. package/pack/generated/codex/skills/rite-customize/SKILL.md +7 -3
  417. package/pack/generated/codex/skills/rite-define/SKILL.md +65 -35
  418. package/pack/generated/codex/skills/rite-define/reference/gates.md +16 -15
  419. package/pack/generated/codex/skills/rite-define/reference/plan-template.md +18 -8
  420. package/pack/generated/codex/skills/rite-doctor/SKILL.md +7 -3
  421. package/pack/generated/codex/skills/rite-dogfood/SKILL.md +7 -3
  422. package/pack/generated/codex/skills/rite-explain/SKILL.md +7 -3
  423. package/pack/generated/codex/skills/rite-frame/SKILL.md +7 -3
  424. package/pack/generated/codex/skills/rite-frame/reference/failure-modes.md +22 -24
  425. package/pack/generated/codex/skills/rite-handoff/SKILL.md +7 -3
  426. package/pack/generated/codex/skills/rite-learn/SKILL.md +7 -3
  427. package/pack/generated/codex/skills/rite-plan/SKILL.md +54 -19
  428. package/pack/generated/codex/skills/rite-plan/reference/task-breakdown.md +5 -1
  429. package/pack/generated/codex/skills/rite-polish/SKILL.md +34 -26
  430. package/pack/generated/codex/skills/rite-pov/SKILL.md +7 -3
  431. package/pack/generated/codex/skills/rite-pr-feedback/SKILL.md +7 -3
  432. package/pack/generated/codex/skills/rite-pressure-test/SKILL.md +7 -3
  433. package/pack/generated/codex/skills/rite-prototype/SKILL.md +32 -29
  434. package/pack/generated/codex/skills/rite-prove/SKILL.md +34 -20
  435. package/pack/generated/codex/skills/rite-quick/SKILL.md +7 -3
  436. package/pack/generated/codex/skills/rite-resolve/SKILL.md +19 -14
  437. package/pack/generated/codex/skills/rite-resolve/reference/answer-protocol.md +3 -0
  438. package/pack/generated/codex/skills/rite-review/SKILL.md +44 -31
  439. package/pack/generated/codex/skills/rite-seal/SKILL.md +7 -3
  440. package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +27 -92
  441. package/pack/generated/codex/skills/rite-seal/reference/risk-and-rollback.md +13 -0
  442. package/pack/generated/codex/skills/rite-ship/SKILL.md +7 -3
  443. package/pack/generated/codex/skills/rite-ship/reference/design-memory.md +31 -36
  444. package/pack/generated/codex/skills/rite-spec/SKILL.md +91 -138
  445. package/pack/generated/codex/skills/rite-spec/reference/investigation.md +37 -33
  446. package/pack/generated/codex/skills/rite-spec/reference/question-protocol.md +6 -2
  447. package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +25 -24
  448. package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +9 -2
  449. package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +13 -3
  450. package/pack/generated/codex/skills/rite-status/SKILL.md +7 -3
  451. package/pack/generated/codex/skills/rite-temper/SKILL.md +69 -50
  452. package/pack/generated/codex/skills/rite-temper/reference/review-dimensions.md +24 -22
  453. package/pack/generated/codex/skills/rite-upgrade/SKILL.md +141 -0
  454. package/pack/generated/codex/skills/rite-upgrade/agents/openai.yaml +2 -0
  455. package/pack/generated/codex/skills/rite-vet/SKILL.md +121 -116
  456. package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +50 -9
  457. package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +40 -38
  458. package/pack/generated/codex/skills/rite-zoom-out/SKILL.md +7 -3
  459. package/package.json +1 -1
  460. package/scripts/build-release-tarball.sh +32 -15
  461. package/scripts/check-authority-drift.py +125 -0
  462. package/scripts/check-instruction-size-baseline.mjs +19 -11
  463. package/scripts/check-invocation-integrity.py +2 -0
  464. package/scripts/codex-generate.sh +69 -33
  465. package/scripts/grade-feature.sh +121 -40
  466. package/scripts/live-hosts/agent-result.schema.json +230 -0
  467. package/scripts/live-hosts/claude.sh +87 -0
  468. package/scripts/live-hosts/codex.sh +81 -0
  469. package/scripts/live-hosts/common.sh +113 -0
  470. package/scripts/live-hosts/fake-host.py +264 -0
  471. package/scripts/live-hosts/host-transport.py +287 -0
  472. package/scripts/release-check.sh +5 -1
  473. package/scripts/run-agent-contract-evals.py +1380 -0
  474. package/scripts/run-behavioral-evals.sh +24 -30
  475. package/scripts/run-evals.sh +1 -5
  476. package/scripts/run-live-behavioral-evals.py +1274 -144
  477. package/scripts/run-outcome-evals.sh +445 -88
  478. package/scripts/run-tests.mjs +30 -2
  479. package/scripts/skills-inventory.mjs +1 -1
  480. package/scripts/validate-workflow-security.py +39 -20
  481. package/scripts/validate-workspace-schema.py +362 -10
  482. package/scripts/validate.sh +21 -15
  483. package/engine/testdata/golden/TestParityWrightScope/devrites-edit-allowed.golden +0 -1
  484. /package/engine/testdata/golden/{TestParityReconcile/check-no-claimed.golden → TestParityBuildReadiness/arg=clarifyopen.golden} +0 -0
@@ -10,9 +10,11 @@ import (
10
10
  )
11
11
 
12
12
  type jsonEnvelope struct {
13
+ Schema string `json:"schema"`
13
14
  Command string `json:"command"`
14
15
  OK bool `json:"ok"`
15
16
  ExitCode int `json:"exitCode"`
17
+ ReasonID string `json:"reason_id"`
16
18
  }
17
19
 
18
20
  func TestJSONContractCommandsEmitExactlyOneEnvelope(t *testing.T) {
@@ -41,6 +43,9 @@ func TestJSONContractCommandsEmitExactlyOneEnvelope(t *testing.T) {
41
43
  if env.Command == "" {
42
44
  t.Fatalf("missing command in envelope: %s", out)
43
45
  }
46
+ if env.Schema != "devrites-command/v1" {
47
+ t.Fatalf("schema=%q\n%s", env.Schema, out)
48
+ }
44
49
  if env.ExitCode != code {
45
50
  t.Fatalf("envelope exitCode=%d process exit=%d\n%s", env.ExitCode, code, out)
46
51
  }
@@ -51,6 +56,73 @@ func TestJSONContractCommandsEmitExactlyOneEnvelope(t *testing.T) {
51
56
  }
52
57
  }
53
58
 
59
+ func TestLifecycleGateJSONCarriesRuleOwnedReasonID(t *testing.T) {
60
+ root := newWorkspace(t)
61
+ for _, tc := range []struct {
62
+ command string
63
+ want string
64
+ }{
65
+ {"readiness", "DRV-GATE-READINESS-MISSING"},
66
+ {"seal", "DRV-GATE-SEAL-MISSING"},
67
+ } {
68
+ t.Run(tc.command, func(t *testing.T) {
69
+ out, _, code := runDevrites(t, root, tc.command, "auth-tokens", "--json")
70
+ if code != 3 {
71
+ t.Fatalf("%s exit=%d\n%s", tc.command, code, out)
72
+ }
73
+ var env jsonEnvelope
74
+ decodeExactlyOneJSON(t, out, &env)
75
+ if env.ReasonID != tc.want {
76
+ t.Fatalf("%s reason_id=%q, want %q\n%s", tc.command, env.ReasonID, tc.want, out)
77
+ }
78
+ })
79
+ }
80
+ }
81
+
82
+ func TestLifecycleGateAppendsRootRelativeV1Provenance(t *testing.T) {
83
+ root := newWorkspace(t)
84
+ _, _, _ = runDevrites(t, root, "readiness", "auth-tokens", "--json")
85
+ raw, err := os.ReadFile(filepath.Join(root, "timeline.jsonl"))
86
+ if err != nil {
87
+ t.Fatal(err)
88
+ }
89
+ if strings.Contains(string(raw), filepath.Dir(root)) {
90
+ t.Fatalf("timeline retained an absolute project path:\n%s", raw)
91
+ }
92
+ var boundaries []string
93
+ for _, line := range strings.Split(strings.TrimSpace(string(raw)), "\n") {
94
+ var event struct {
95
+ Schema string `json:"schema"`
96
+ Boundary string `json:"boundary"`
97
+ RootSource string `json:"root_source"`
98
+ Workspace string `json:"workspace"`
99
+ ReasonID string `json:"reason_id"`
100
+ Evidence []string `json:"evidence_paths"`
101
+ }
102
+ if json.Unmarshal([]byte(line), &event) != nil || event.Schema != "devrites-event/v1" {
103
+ continue
104
+ }
105
+ boundaries = append(boundaries, event.Boundary)
106
+ if event.RootSource != "DEVRITES_ROOT" {
107
+ t.Fatalf("non-canonical root/workspace provenance: %+v", event)
108
+ }
109
+ if event.Boundary == "lifecycle-gate" && event.Workspace != ".devrites/features/auth-tokens" {
110
+ t.Fatalf("gate workspace provenance: %+v", event)
111
+ }
112
+ if event.Boundary == "root-selection" && event.Workspace != "" {
113
+ t.Fatalf("root selection invented an inactive workspace: %+v", event)
114
+ }
115
+ for _, path := range event.Evidence {
116
+ if filepath.IsAbs(path) || strings.HasPrefix(path, "..") {
117
+ t.Fatalf("non-relative evidence %q", path)
118
+ }
119
+ }
120
+ }
121
+ if strings.Join(boundaries, ",") != "root-selection,lifecycle-gate" {
122
+ t.Fatalf("boundaries=%v\n%s", boundaries, raw)
123
+ }
124
+ }
125
+
54
126
  func TestContextShowJSONReportsActiveWorkspace(t *testing.T) {
55
127
  root := newWorkspace(t)
56
128
  if err := os.WriteFile(filepath.Join(root, "ACTIVE"), []byte("auth-tokens\n"), 0o644); err != nil {
@@ -63,18 +135,32 @@ func TestContextShowJSONReportsActiveWorkspace(t *testing.T) {
63
135
  var got struct {
64
136
  Root string `json:"root"`
65
137
  Project string `json:"project"`
138
+ LexicalRoot string `json:"lexicalRoot"`
139
+ RootSelection string `json:"rootSelection"`
66
140
  ActiveWorkspace string `json:"activeWorkspace"`
67
141
  Source string `json:"source"`
68
- HostCommands struct {
142
+ Git struct {
143
+ TopLevel string `json:"topLevel"`
144
+ LinkedWorktree bool `json:"linkedWorktree"`
145
+ Submodule bool `json:"submodule"`
146
+ } `json:"git"`
147
+ HostCommands struct {
69
148
  Claude string `json:"claude"`
70
149
  Codex string `json:"codex"`
71
150
  } `json:"hostCommands"`
72
151
  Status []any `json:"status"`
73
152
  }
74
153
  decodeExactlyOneJSON(t, out, &got)
75
- if got.Root != root || got.Project != filepath.Dir(root) {
154
+ wantRoot, err := filepath.EvalSymlinks(root)
155
+ if err != nil {
156
+ t.Fatal(err)
157
+ }
158
+ if got.Root != wantRoot || got.Project != filepath.Dir(wantRoot) {
76
159
  t.Fatalf("wrong roots: %+v", got)
77
160
  }
161
+ if got.LexicalRoot != root || got.RootSelection != "DEVRITES_ROOT" {
162
+ t.Fatalf("wrong root provenance: %+v", got)
163
+ }
78
164
  if got.ActiveWorkspace != filepath.Join(".devrites", "features", "auth-tokens") || got.Source != "ACTIVE" {
79
165
  t.Fatalf("wrong active workspace: %+v", got)
80
166
  }
@@ -86,6 +172,45 @@ func TestContextShowJSONReportsActiveWorkspace(t *testing.T) {
86
172
  }
87
173
  }
88
174
 
175
+ func TestContextShowJSONCarriesCanonicalRootHazards(t *testing.T) {
176
+ root := newWorkspace(t)
177
+ if err := os.WriteFile(filepath.Join(root, "ACTIVE"), []byte("ghost\n"), 0o644); err != nil {
178
+ t.Fatal(err)
179
+ }
180
+ out, errOut, code := runDevrites(t, root, "context", "show", "--json")
181
+ if code != 0 {
182
+ t.Fatalf("context show exit=%d stderr=%s", code, errOut)
183
+ }
184
+ var got struct {
185
+ RootSelection string `json:"rootSelection"`
186
+ Status []struct {
187
+ ID string `json:"id"`
188
+ Remediation string `json:"remediation"`
189
+ } `json:"status"`
190
+ }
191
+ decodeExactlyOneJSON(t, out, &got)
192
+ if got.RootSelection != "DEVRITES_ROOT" || len(got.Status) != 1 ||
193
+ got.Status[0].ID != "DRV-ACTIVE-STALE" || !strings.Contains(got.Status[0].Remediation, "rm -f") {
194
+ t.Fatalf("context root status = %+v\n%s", got, out)
195
+ }
196
+ }
197
+
198
+ func TestContextShowSeparatesRootAndWorkspaceSelection(t *testing.T) {
199
+ root := newWorkspace(t)
200
+ out, errOut, code := runDevrites(t, root, "context", "show", "--json")
201
+ if code != 0 {
202
+ t.Fatalf("context show exit=%d stderr=%s", code, errOut)
203
+ }
204
+ var got struct {
205
+ RootSelection string `json:"rootSelection"`
206
+ Source string `json:"source"`
207
+ }
208
+ decodeExactlyOneJSON(t, out, &got)
209
+ if got.RootSelection != "DEVRITES_ROOT" || got.Source != "none" {
210
+ t.Fatalf("root/workspace selections are conflated: %+v", got)
211
+ }
212
+ }
213
+
89
214
  func decodeExactlyOneJSON(t *testing.T, text string, v any) {
90
215
  t.Helper()
91
216
  dec := json.NewDecoder(strings.NewReader(text))
@@ -1,6 +1,6 @@
1
1
  package main_test
2
2
 
3
- // Issue 06: `migrate` workspace normalization at the CLI seam.
3
+ // CLI coverage for Issue 06: `migrate` workspace normalization.
4
4
 
5
5
  import (
6
6
  "os"
@@ -71,7 +71,7 @@ func TestMigrateNormalizesCanonicalWorkSchema(t *testing.T) {
71
71
  if !strings.Contains(string(readme), "phase: temper") {
72
72
  t.Errorf("README.md phase not derived from state.md\n%s", readme)
73
73
  }
74
- if !strings.Contains(string(readme), "schemaVersion: 1") {
74
+ if !strings.Contains(string(readme), "schemaVersion: 2") {
75
75
  t.Errorf("README.md missing schemaVersion\n%s", readme)
76
76
  }
77
77
  for _, unwanted := range []string{"feature.md", "proof.md", "status.md"} {
@@ -1,36 +1,135 @@
1
1
  package main_test
2
2
 
3
- // TestParityBuildReadiness checks the build-readiness gate's stdout + exit code
3
+ // TestParityBuildReadiness checks the build-readiness gate's stdout and exit code
4
4
  // against the golden snapshot for each state.md fixture.
5
5
 
6
- import "testing"
6
+ import (
7
+ "fmt"
8
+ "os"
9
+ "path/filepath"
10
+ "strings"
11
+ "testing"
12
+
13
+ "github.com/devrites/devrites/internal/lib"
14
+ )
7
15
 
8
16
  func TestParityBuildReadiness(t *testing.T) {
9
17
  work := t.TempDir()
10
18
 
11
- // Status halts (stderr-only messages; parity is stdout + exit code).
19
+ // Status halts write only to stderr; parity covers stdout and the exit code.
12
20
  writeFeatureFile(t, work, "await", "state.md", "- Status: awaiting_human\n") // exit 3
13
21
  writeFeatureFile(t, work, "blocked", "state.md", "- Status: blocked\n") // exit 4
14
22
 
15
- // Ready: plan approved + status.
16
- writeFeatureFile(t, work, "approved", "state.md", "- Plan approved: 2024-01-01\n- Status: running\n") // exit 0
23
+ writeReadyArtifacts := func(slug string) {
24
+ t.Helper()
25
+ writeCoverageArtifacts(t, work, slug)
26
+ for name, body := range map[string]string{
27
+ "architecture.md": "# Architecture\n\nExisting layer.\n",
28
+ "plan.md": "# Plan\n\nOne slice.\n",
29
+ "tasks.md": "# Tasks\n\n## SLICE-001\nBuild.\n",
30
+ "traceability.md": "# Traceability\n\nAC-001 -> SLICE-001.\n",
31
+ "test-plan.md": `# Test plan
32
+
33
+ DevRites contract: devrites.readiness-artifacts.v2
34
+
35
+ ## Build-entry preflight
36
+ | Gate | Command | Cwd | Expected | Prerequisites | Provenance to recapture |
37
+ | --- | --- | --- | --- | --- | --- |
38
+ | unit | go test ./... | engine | exit 0 | none | go version |
39
+
40
+ ## Per-gap test requirements
41
+ | ID | Path / flow | Test file | Asserts | Kind | Slice | Priority |
42
+ | --- | --- | --- | --- | --- | --- | --- |
43
+ | T1 | flow | flow_test.go | request → success | unit | SLICE-001 | P1 |
44
+
45
+ ## Acceptance → test map
46
+ - AC-001 → T1
47
+ `,
48
+ } {
49
+ writeFeatureFile(t, work, slug, name, body)
50
+ }
51
+ root := filepath.Join(work, ".devrites")
52
+ digest, err := lib.ReadinessInputDigest(root, slug, "engineering")
53
+ if err != nil {
54
+ t.Fatal(err)
55
+ }
56
+ writeFeatureFile(t, work, slug, "eng-review.md", fmt.Sprintf(`# Eng review
57
+
58
+ DevRites contract: devrites.readiness-artifacts.v2
59
+ Implementation readiness: READY
60
+ Readiness inputs SHA-256: %s
61
+
62
+ ## 2a. Build-entry preflight
63
+ | Gate | Command + cwd | Tool/version | Prerequisite owner | Full provenance inputs | Fixture/smoke | Verdict |
64
+ | --- | --- | --- | --- | --- | --- | --- |
65
+ | unit | go test ./... | go | none | go.mod | focused | pass |
66
+
67
+ ## 2b. Implementation readiness
68
+ | Surface | Requirement/decision | Boundary/wiring | Slice | Proof | Verdict |
69
+ | --- | --- | --- | --- | --- | --- |
70
+ | flow | AC-001 | existing | SLICE-001 | T1 | ready |
71
+
72
+ ## 4. Failure modes
73
+ | New codepath | Realistic failure | Test? | Handling? | Silent? | Verdict |
74
+ | --- | --- | --- | --- | --- | --- |
75
+ | flow | invalid | yes | yes | no | ok |
76
+
77
+ ## 7. Completion summary
78
+ - Ready.
79
+ `, digest))
80
+ }
81
+
82
+ // A ready feature has an approved plan, running status, and current
83
+ // clarification and vet artifacts.
84
+ for _, slug := range []string{"approved", "trailpipe", "trailhash", "emptystatus"} {
85
+ writeReadyArtifacts(slug)
86
+ }
87
+ writeFeatureFile(t, work, "approved", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 0
17
88
 
18
89
  // Plan not approved: missing line, or the literal "none".
90
+ writeCoverageArtifacts(t, work, "noapprove")
91
+ writeCoverageArtifacts(t, work, "approvenone")
19
92
  writeFeatureFile(t, work, "noapprove", "state.md", "- Status: running\n") // exit 2
20
93
  writeFeatureFile(t, work, "approvenone", "state.md", "- Plan approved: none\n- Status: running\n") // exit 2
21
94
 
22
95
  // field() strip: a trailing " | none" / " # note" annotation is trimmed off
23
96
  // Status before the case match, so both stay "running" and reach OK.
24
- writeFeatureFile(t, work, "trailpipe", "state.md", "- Plan approved: 2024-01-01\n- Status: running | none\n") // exit 0
25
- writeFeatureFile(t, work, "trailhash", "state.md", "- Plan approved: 2024-01-01\n- Status: running # note\n") // exit 0
97
+ writeFeatureFile(t, work, "trailpipe", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running | none\n") // exit 0
98
+ writeFeatureFile(t, work, "trailhash", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running # note\n") // exit 0
99
+
100
+ // An empty Status with an approved plan renders as "running".
101
+ writeFeatureFile(t, work, "emptystatus", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: \n") // exit 0
102
+
103
+ // A plan cannot build without an explicit closed clarification scan and a
104
+ // successful engineering-readiness verdict. These are objective routes, not
105
+ // human questions.
106
+ writeFeatureFile(t, work, "noclarify", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 6
107
+
108
+ writeFeatureFile(t, work, "clarifyopen", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 6
109
+ writeFeatureFile(t, work, "clarifyopen", "brief.md", "# Brief\n\nOutcome.\n")
110
+ writeFeatureFile(t, work, "clarifyopen", "spec.md", "# Spec\n\nAC-001.\n")
111
+ writeFeatureFile(t, work, "clarifyopen", "decision-coverage.md", "# Decision coverage\n\n- Decision coverage: NEEDS CLARIFICATION\n")
26
112
 
27
- // Empty Status value + plan approved status renders as "running".
28
- writeFeatureFile(t, work, "emptystatus", "state.md", "- Plan approved: 2024-01-01\n- Status: \n") // exit 0
113
+ writeFeatureFile(t, work, "novet", "state.md", "- Phase: plan\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 7
114
+ writeCoverageArtifacts(t, work, "novet")
115
+
116
+ writeFeatureFile(t, work, "vetnotready", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 7
117
+ writeCoverageArtifacts(t, work, "vetnotready")
118
+ writeFeatureFile(t, work, "vetnotready", "eng-review.md", "# Engineering review\n\n- Implementation readiness: NEEDS REPLAN\n")
119
+
120
+ writeReadyArtifacts("stalevet")
121
+ writeFeatureFile(t, work, "stalevet", "state.md", "- Phase: plan\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 7
122
+
123
+ writeCoverageArtifacts(t, work, "legacycontract")
124
+ writeFeatureFile(t, work, "legacycontract", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 8
125
+ legacyCoverage := filepath.Join(work, ".devrites", "features", "legacycontract", "decision-coverage.md")
126
+ replaceInFile(t, legacyCoverage, "DevRites contract: devrites.readiness-artifacts.v2\n", "")
29
127
 
30
128
  // "ghost" is intentionally never created → no workspace/state.md (exit 5).
31
129
  for _, arg := range []string{
32
130
  "await", "blocked", "approved", "noapprove", "approvenone",
33
- "trailpipe", "trailhash", "emptystatus", "ghost",
131
+ "trailpipe", "trailhash", "emptystatus", "noclarify", "clarifyopen",
132
+ "novet", "vetnotready", "stalevet", "legacycontract", "ghost",
34
133
  } {
35
134
  c := parityCase{
36
135
  workdir: work,
@@ -40,3 +139,61 @@ func TestParityBuildReadiness(t *testing.T) {
40
139
  t.Run("arg="+arg, func(t *testing.T) { c.assertEqual(t) })
41
140
  }
42
141
  }
142
+
143
+ func replaceInFile(t *testing.T, path, old, replacement string) {
144
+ t.Helper()
145
+ data, err := os.ReadFile(path)
146
+ if err != nil {
147
+ t.Fatal(err)
148
+ }
149
+ body := string(data)
150
+ if strings.Count(body, old) != 1 {
151
+ t.Fatalf("%s: expected exactly one %q", path, old)
152
+ }
153
+ if err := os.WriteFile(path, []byte(strings.Replace(body, old, replacement, 1)), 0o644); err != nil {
154
+ t.Fatal(err)
155
+ }
156
+ }
157
+
158
+ func writeCoverageArtifacts(t *testing.T, work, slug string) {
159
+ t.Helper()
160
+ writeFeatureFile(t, work, slug, "brief.md", "# Brief\n\nOutcome.\n")
161
+ writeFeatureFile(t, work, slug, "spec.md", "# Spec\n\n## Acceptance criteria\n- AC-001 succeeds.\n")
162
+ writeFeatureFile(t, work, slug, "decisions.md", "# Decisions\n\nNo open product decisions.\n")
163
+ writeFeatureFile(t, work, slug, "assumptions.md", "# Assumptions\n\nNo material assumptions.\n")
164
+ writeFeatureFile(t, work, slug, "questions.md", "# Questions\n\nNone.\n")
165
+ root := filepath.Join(work, ".devrites")
166
+ digest, err := lib.ReadinessInputDigest(root, slug, "coverage")
167
+ if err != nil {
168
+ t.Fatal(err)
169
+ }
170
+ writeFeatureFile(t, work, slug, "decision-coverage.md", fmt.Sprintf(`# Decision coverage
171
+
172
+ DevRites contract: devrites.readiness-artifacts.v2
173
+ Decision coverage: CLEAR
174
+ Coverage inputs SHA-256: %s
175
+
176
+ ## Topology
177
+ | Surface | Kind | Related IDs | Evidence |
178
+ | --- | --- | --- | --- |
179
+ | flow | behavior | AC-001 | spec.md |
180
+
181
+ ## Coverage matrix
182
+ | Surface | Dimension | Status | Canonical reference | Owner / validation gate | Consequence if wrong |
183
+ | --- | --- | --- | --- | --- | --- |
184
+ | flow | behavior | closed | AC-001 | rite-prove | failure |
185
+
186
+ ## Assumption audit
187
+ | Assumption | Evidence | Confidence | Owner | Validation | Consequence if wrong |
188
+ | --- | --- | --- | --- | --- | --- |
189
+ | none | n/a | high | n/a | n/a | n/a |
190
+
191
+ ## Residual uncertainty
192
+ | Item | Why nonblocking | Owner | Validation gate |
193
+ | --- | --- | --- | --- |
194
+ | none | n/a | n/a | n/a |
195
+
196
+ ## Readiness verdict
197
+ No unresolved decision remains.
198
+ `, digest))
199
+ }
@@ -1,10 +1,9 @@
1
1
  package main_test
2
2
 
3
3
  // TestParityLearnings checks the learnings command against the golden snapshots.
4
- // learnings state is ROOT-LEVEL, read from DEVRITES_ROOT=work/.devrites when the
5
- // case runs in workdir=work with libRootEnv(work). The mine/nudge pipelines are
6
- // deterministic from fixtures. Fixture counts are DISTINCT (3 vs 2) so ordering
7
- // never depends on a platform-specific tie-break.
4
+ // Learning state lives at the root selected by DEVRITES_ROOT. The mine and nudge
5
+ // fixtures use counts of 3 and 2 so sorting never depends on a platform-specific
6
+ // tie.
8
7
 
9
8
  import (
10
9
  "path/filepath"
@@ -14,10 +13,11 @@ import (
14
13
  func TestParityLearnings(t *testing.T) {
15
14
  learn := func(a ...string) []string { return append([]string{"learnings"}, a...) }
16
15
 
17
- // --- add: fresh workspace. bash creates the ledger + a dated entry; Go then
18
- // appends a second entry. Only stdout ("learnings: recorded.") + exit 0 are the
19
- // contract: the dated file line is a nondeterministic side effect, not stdout.
16
+ // Add to a fresh workspace. Bash creates the ledger and a dated entry, then Go
17
+ // appends another. Only stdout ("learnings: recorded.") and exit 0 belong to
18
+ // the contract because the dated file entry is nondeterministic.
20
19
  addw := t.TempDir()
20
+ mkdirAllT(t, addw, ".devrites")
21
21
  t.Run("add", func(t *testing.T) {
22
22
  (parityCase{
23
23
  workdir: addw, env: libRootEnv(addw),
@@ -25,7 +25,7 @@ func TestParityLearnings(t *testing.T) {
25
25
  }).assertEqual(t)
26
26
  })
27
27
 
28
- // --- list: a pre-written ledger; both sides cat the same file verbatim.
28
+ // List a prepared ledger. Both implementations print the file unchanged.
29
29
  listw := t.TempDir()
30
30
  writeFile(t, listw, filepath.Join(".devrites", "learnings.md"),
31
31
  "# DevRites learnings ledger\n\n"+
@@ -38,10 +38,9 @@ func TestParityLearnings(t *testing.T) {
38
38
  }).assertEqual(t)
39
39
  })
40
40
 
41
- // --- mine + nudge: two archived features. The shared "recurring finding" bullet
42
- // normalizes identically across features despite differing numbers/paths (the sed
43
- // id/path/number stripping), giving count 3; the "second dead end" bullet gives
44
- // count 2. Distinct counts ⇒ deterministic order on any `sort`.
41
+ // Mine and nudge use two archived features. Normalization strips IDs, paths,
42
+ // and numbers, so "recurring finding" has count 3 and "second dead end" has
43
+ // count 2. The distinct counts keep sort order stable.
45
44
  arch := t.TempDir()
46
45
  writeFile(t, arch, filepath.Join(".devrites", "archive", "feat-a", "decisions.md"),
47
46
  "# decisions for feat-a\n"+
@@ -55,7 +54,7 @@ func TestParityLearnings(t *testing.T) {
55
54
  "- second dead end: retry backoff exceeded 9 attempts\n"+
56
55
  "- a one-off dismiss note about the flaky linter run\n")
57
56
 
58
- // mine: default archive (bash .devrites/archive, Go <root>/archive: same dir).
57
+ // Both implementations resolve the default archive to the same directory.
59
58
  t.Run("mine", func(t *testing.T) {
60
59
  (parityCase{
61
60
  workdir: arch, env: libRootEnv(arch),
@@ -63,8 +62,8 @@ func TestParityLearnings(t *testing.T) {
63
62
  }).assertEqual(t)
64
63
  })
65
64
 
66
- // mine: no archive. An explicit relative path both sides resolve against workdir,
67
- // so the path embedded in the message is identical for bash and Go.
65
+ // Both implementations resolve an explicit relative path against workdir, so
66
+ // the missing path in the message is identical.
68
67
  t.Run("mine-no-archive", func(t *testing.T) {
69
68
  (parityCase{
70
69
  workdir: arch, env: libRootEnv(arch),
@@ -72,7 +71,7 @@ func TestParityLearnings(t *testing.T) {
72
71
  }).assertEqual(t)
73
72
  })
74
73
 
75
- // nudge: >=2 features + a class recurring 3x + no review marker the nudge line.
74
+ // Two features, three occurrences, and no review marker produce a nudge.
76
75
  t.Run("nudge", func(t *testing.T) {
77
76
  (parityCase{
78
77
  workdir: arch, env: libRootEnv(arch),
@@ -80,7 +79,7 @@ func TestParityLearnings(t *testing.T) {
80
79
  }).assertEqual(t)
81
80
  })
82
81
 
83
- // --- unknown cmd: usage to stderr, exit 2 (stdout empty on both sides).
82
+ // An unknown command writes usage to stderr and exits 2 without stdout.
84
83
  t.Run("unknown", func(t *testing.T) {
85
84
  (parityCase{
86
85
  workdir: arch, env: libRootEnv(arch),
@@ -2,14 +2,15 @@ package main_test
2
2
 
3
3
  import (
4
4
  "fmt"
5
+ "strings"
5
6
  "testing"
6
7
  )
7
8
 
8
9
  // TestParityReconcile checks reconcile against the golden snapshots: snapshot
9
- // captures the worktree as a tree object, check diffs it and flags source changes
10
- // outside the claimed manifest. Runs git in a real repo, so stdout + exit are
11
- // captured from the live command. The .devrites/ bookkeeping is skipped by the
12
- // gate, so it never affects the verdict.
10
+ // captures the worktree as a tree object, check diffs it and flags changes
11
+ // outside the orchestrator-authored allowlist, and close ends the retained
12
+ // post-slice baseline. It runs Git in a real repository, so stdout and exit are
13
+ // captured from the live command.
13
14
  func TestParityReconcile(t *testing.T) {
14
15
  requireGit(t)
15
16
 
@@ -25,7 +26,12 @@ func TestParityReconcile(t *testing.T) {
25
26
  }
26
27
  // snapshot is also a setup step for the check-* cases, so it snapshots under a
27
28
  // distinct key to avoid colliding with check's golden in the same subtest.
28
- snapshot := func(t *testing.T, work string) {
29
+ snapshot := func(t *testing.T, work string, allowed ...string) {
30
+ body := ""
31
+ if len(allowed) > 0 {
32
+ body = strings.Join(allowed, "\n") + "\n"
33
+ }
34
+ writeFeatureFile(t, work, "feat", ".wright-allowlist", body)
29
35
  out, code := runArgv(t, work, libRootEnv(work), "", binPath, "reconcile", "snapshot", "feat")
30
36
  assertGoldenKey(t, t.Name()+"/snapshot", fmt.Sprintf("exit %d\n%s", code, out))
31
37
  }
@@ -38,38 +44,35 @@ func TestParityReconcile(t *testing.T) {
38
44
 
39
45
  t.Run("check-clean", func(t *testing.T) {
40
46
  work := newRepo(t)
41
- snapshot(t, work)
47
+ snapshot(t, work, "src/a.js")
42
48
  writeFile(t, work, "src/a.js", "console.log(999)\n") // the wright's change
43
- writeFeatureFile(t, work, "feat", ".reconcile-claimed", "src/a.js\n")
44
49
  check(t, work)
45
50
  })
46
51
 
47
52
  t.Run("check-violation", func(t *testing.T) {
48
53
  work := newRepo(t)
49
- snapshot(t, work)
54
+ snapshot(t, work, "src/a.js")
50
55
  writeFile(t, work, "src/a.js", "console.log(999)\n")
51
- writeFile(t, work, "src/b.js", "console.log(888)\n") // NOT claimed -> A1 breach
52
- writeFeatureFile(t, work, "feat", ".reconcile-claimed", "src/a.js\n")
56
+ writeFile(t, work, "src/b.js", "console.log(888)\n") // Outside the allowlist; an A1 breach.
53
57
  check(t, work)
54
58
  })
55
59
 
56
60
  t.Run("check-no-base", func(t *testing.T) {
57
61
  work := newRepo(t)
58
- writeFeatureFile(t, work, "feat", ".reconcile-claimed", "src/a.js\n")
59
- check(t, work) // no snapshot -> exit 6
62
+ check(t, work) // No snapshot, so exit 6.
60
63
  })
61
64
 
62
- t.Run("check-no-claimed", func(t *testing.T) {
65
+ t.Run("snapshot-no-allowlist", func(t *testing.T) {
63
66
  work := newRepo(t)
64
- snapshot(t, work)
65
- check(t, work) // base present, no claimed -> exit 6
67
+ out, code := runArgv(t, work, libRootEnv(work), "", binPath, "reconcile", "snapshot", "feat")
68
+ assertGolden(t, out, code)
66
69
  })
67
70
 
68
71
  t.Run("inline-fallback", func(t *testing.T) {
69
72
  work := newRepo(t)
70
73
  snapshot(t, work)
71
- writeFeatureFile(t, work, "feat", ".reconcile-inline", "")
72
- check(t, work) // gate skipped -> exit 0
74
+ out, code := runArgv(t, work, libRootEnv(work), "", binPath, "reconcile", "close", "feat")
75
+ assertGolden(t, out, code)
73
76
  })
74
77
 
75
78
  t.Run("not-git", func(t *testing.T) {
@@ -7,8 +7,8 @@ import (
7
7
  "testing"
8
8
  )
9
9
 
10
- // Golden snapshot for resolve: it MUTATES questions.md + state.md. Each case
11
- // snapshots the command's stdout + exit code and, for the mutating cases, the
10
+ // Golden snapshots for resolve include its changes to questions.md and state.md.
11
+ // Each case records stdout and the exit code. Mutating cases also record the
12
12
  // resulting file bytes. The two nondeterministic timestamp fields (answered_at
13
13
  // and the Log entry) are masked out before the file content is snapshotted so the
14
14
  // golden is deterministic across runs.
@@ -45,8 +45,8 @@ const resolveState = `- Status: awaiting_human
45
45
  `
46
46
 
47
47
  func TestParityResolve(t *testing.T) {
48
- // setup writes the fixtures into a Go tree (.devrites/features/feat) and returns
49
- // the workspace root.
48
+ // setup writes fixtures under .devrites/features/feat and returns the
49
+ // workspace root.
50
50
  setup := func(t *testing.T, questions, state string) (gwork string) {
51
51
  t.Helper()
52
52
  gwork = t.TempDir()
@@ -55,7 +55,7 @@ func TestParityResolve(t *testing.T) {
55
55
  writeFile(t, gwork, filepath.Join(".devrites", "ACTIVE"), "feat\n")
56
56
  return gwork
57
57
  }
58
- // run executes resolve in gwork and snapshots its stdout + exit code under the
58
+ // run executes resolve in gwork and snapshots stdout and the exit code under the
59
59
  // current subtest's golden.
60
60
  run := func(t *testing.T, gwork string, args ...string) {
61
61
  t.Helper()
@@ -124,16 +124,17 @@ answer: prior
124
124
  })
125
125
 
126
126
  t.Run("no-workspace", func(t *testing.T) {
127
- // Bare tree: no ACTIVE, no questions.md -> exit 2.
127
+ // A bare tree with no explicit root, ACTIVE, or questions.md exits 2.
128
+ // Pointing DEVRITES_ROOT at the nonexistent .devrites child would instead
129
+ // be an explicit unsafe-root refusal, which is a different contract.
128
130
  gwork := t.TempDir()
129
- run(t, gwork, "q-1", "x")
131
+ out, code := runArgv(t, gwork, libEnv, "", binPath, "resolve", "q-1", "x")
132
+ assertGolden(t, out, code)
130
133
  })
131
134
 
132
135
  t.Run("next-qid", func(t *testing.T) {
133
- // Read-only: computes the next qid for an explicit questions.md path.
134
- // DEVRITES_NOW pins the clock so the golden is stable across day
135
- // boundaries: without it the qid tracks the real date and the snapshot
136
- // fails every day but the one it was recorded on (ADR-0006, clock seam).
136
+ // DEVRITES_NOW fixes the date used by next-qid so the snapshot stays stable.
137
+ // See ADR-0006.
137
138
  dir := t.TempDir()
138
139
  writeFile(t, dir, "questions.md", "## q-2024-01-01-001\nstatus: open\n")
139
140
  qpath := filepath.Join(dir, "questions.md")