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
@@ -0,0 +1,358 @@
1
+ package lib
2
+
3
+ import (
4
+ "bytes"
5
+ "encoding/json"
6
+ "os"
7
+ "path/filepath"
8
+ "strings"
9
+ "testing"
10
+ "time"
11
+
12
+ "github.com/devrites/devrites/internal/reason"
13
+ "github.com/devrites/devrites/internal/state"
14
+ )
15
+
16
+ const observabilityOtherRunID = "drv-run-v1:fedcba9876543210fedcba9876543210"
17
+
18
+ func makeObservabilityWorkspace(t *testing.T) (string, string) {
19
+ t.Helper()
20
+ root := filepath.Join(t.TempDir(), ".devrites")
21
+ work := filepath.Join(root, "work", "demo")
22
+ if err := os.MkdirAll(work, 0o755); err != nil {
23
+ t.Fatal(err)
24
+ }
25
+ if err := os.WriteFile(filepath.Join(root, "ACTIVE"), []byte("demo\n"), 0o644); err != nil {
26
+ t.Fatal(err)
27
+ }
28
+ return root, work
29
+ }
30
+
31
+ func appendObservabilityEvent(
32
+ t *testing.T,
33
+ root, runID, timestamp, name string,
34
+ boundary EventBoundary,
35
+ reasonID reason.ID,
36
+ outcome EventOutcome,
37
+ phase state.Phase,
38
+ ) EventV1 {
39
+ t.Helper()
40
+ event := NewEventV1(boundary, name, reasonID)
41
+ event.TS = timestamp
42
+ event.RunID = runID
43
+ event.RootSource = RootSourceExplicit
44
+ event.Workspace = ".devrites/work/demo"
45
+ event.PhaseBefore = phase
46
+ event.PhaseAfter = phase
47
+ event.Outcome = outcome
48
+ event.Host = HostCodex
49
+ if err := AppendEventV1(root, event); err != nil {
50
+ t.Fatal(err)
51
+ }
52
+ return event
53
+ }
54
+
55
+ func TestTimelineReportAnswersWorkflowQuestionsWithoutRawText(t *testing.T) {
56
+ root, _ := makeObservabilityWorkspace(t)
57
+ legacy := `{"ts":"2026-07-23T11:59:00Z","event":"auq","question":"PRIVATE_QUESTION","answer":"PRIVATE_ANSWER"}` + "\n"
58
+ if err := os.WriteFile(
59
+ filepath.Join(root, "timeline.jsonl"),
60
+ []byte(legacy+"not-json\n"),
61
+ 0o644,
62
+ ); err != nil {
63
+ t.Fatal(err)
64
+ }
65
+
66
+ start := appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:00:00Z",
67
+ "run-started", BoundaryAgentDispatch, reason.RootSelected, OutcomeRecorded, state.PhaseSpec)
68
+ start.ExecutionMode = ExecutionNamed
69
+ start.GuardStrength = GuardObserved
70
+ rewriteLastObservabilityEvent(t, root, start)
71
+
72
+ appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:01:00Z",
73
+ "retry", BoundaryAgentDispatch, reason.AgentResultMalformed, OutcomeWarning, state.PhaseBuild)
74
+ appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:02:00Z",
75
+ "readiness", BoundaryLifecycleGate, reason.GateReadinessMissing, OutcomeBlocked, state.PhaseBuild)
76
+ appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:03:00Z",
77
+ "run-interrupted", BoundaryHookGuard, reason.HookStopUnsurfacedHumanGate, OutcomeBlocked, state.PhaseBuild)
78
+ appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:04:00Z",
79
+ "run-resumed", BoundaryAgentDispatch, reason.HookAllowApproved, OutcomeAllowed, state.PhaseBuild)
80
+ appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:05:00Z",
81
+ "evidence-stale", BoundaryLifecycleGate, reason.GateReadinessMissing, OutcomeWarning, state.PhaseProve)
82
+ degraded := appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:06:00Z",
83
+ "degraded", BoundaryAgentDispatch, reason.AgentUnavailable, OutcomeUnavailable, state.PhaseProve)
84
+ degraded.ExecutionMode = ExecutionGeneric
85
+ degraded.GuardStrength = GuardUnavailable
86
+ rewriteLastObservabilityEvent(t, root, degraded)
87
+ appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:07:00Z",
88
+ "run-finished", BoundaryLifecycleGate, reason.GateSealMissing, OutcomeBlocked, state.PhaseSeal)
89
+
90
+ var stdout, stderr bytes.Buffer
91
+ if code := Timeline(root, []string{"report", "--run", testRunID, "--json"}, &stdout, &stderr); code != 0 {
92
+ t.Fatalf("report code=%d stderr=%q", code, stderr.String())
93
+ }
94
+ var report observabilityReport
95
+ if err := json.Unmarshal(stdout.Bytes(), &report); err != nil {
96
+ t.Fatal(err)
97
+ }
98
+ if report.Schema != observabilityReportSchema || report.Events != 8 ||
99
+ !report.TraceStarted || !report.TraceFinished || report.DurationSeconds != 420 {
100
+ t.Fatalf("trace summary=%+v", report)
101
+ }
102
+ if report.Retries != 1 || report.HumanWaits != 1 ||
103
+ report.Interruptions != 1 || report.Resumes != 1 ||
104
+ report.LinkedResumes != 1 || report.OpenInterruptions != 0 {
105
+ t.Fatalf("recovery summary=%+v", report)
106
+ }
107
+ if report.LastFailedGateReason != reason.GateSealMissing ||
108
+ report.LastFailedGatePhase != state.PhaseSeal ||
109
+ report.StaleEvidence != 1 || report.Degradations != 1 ||
110
+ report.FinalOutcome != string(OutcomeBlocked) {
111
+ t.Fatalf("gate/outcome summary=%+v", report)
112
+ }
113
+ if report.PhaseDurations[string(state.PhaseSpec)] != 60 ||
114
+ report.PhaseDurations[string(state.PhaseBuild)] != 240 ||
115
+ report.PhaseDurations[string(state.PhaseProve)] != 120 {
116
+ t.Fatalf("phase durations=%v", report.PhaseDurations)
117
+ }
118
+ if report.TelemetryRead.LegacyIgnored != 1 || report.TelemetryRead.CorruptIgnored != 1 {
119
+ t.Fatalf("compatibility summary=%+v", report.TelemetryRead)
120
+ }
121
+ if strings.Contains(stdout.String(), "PRIVATE_QUESTION") ||
122
+ strings.Contains(stdout.String(), "PRIVATE_ANSWER") {
123
+ t.Fatalf("report exposed legacy raw text: %s", stdout.String())
124
+ }
125
+ }
126
+
127
+ // appendObservabilityEvent writes both telemetry owners. Tests occasionally
128
+ // need to change typed fields after construction, so replace only the final
129
+ // matching row in each owner with another validated v1 row.
130
+ func rewriteLastObservabilityEvent(t *testing.T, root string, event EventV1) {
131
+ t.Helper()
132
+ if err := ValidateEventV1(event); err != nil {
133
+ t.Fatal(err)
134
+ }
135
+ encoded, err := json.Marshal(event)
136
+ if err != nil {
137
+ t.Fatal(err)
138
+ }
139
+ for _, path := range []string{
140
+ filepath.Join(root, "timeline.jsonl"),
141
+ filepath.Join(root, "work", "demo", "events.jsonl"),
142
+ } {
143
+ data, err := os.ReadFile(path)
144
+ if err != nil {
145
+ t.Fatal(err)
146
+ }
147
+ lines := bytes.Split(bytes.TrimSuffix(data, []byte("\n")), []byte("\n"))
148
+ lines[len(lines)-1] = encoded
149
+ if err := os.WriteFile(path, append(bytes.Join(lines, []byte("\n")), '\n'), 0o644); err != nil {
150
+ t.Fatal(err)
151
+ }
152
+ }
153
+ }
154
+
155
+ func TestTimelineReportBoundsTailAndDegradesOnOversizedRows(t *testing.T) {
156
+ root, _ := makeObservabilityWorkspace(t)
157
+ event := appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:00:00Z",
158
+ "run-started", BoundaryAgentDispatch, reason.RootSelected, OutcomeRecorded, state.PhaseBuild)
159
+ encoded, err := json.Marshal(event)
160
+ if err != nil {
161
+ t.Fatal(err)
162
+ }
163
+ prefix := bytes.Repeat([]byte("PRIVATE_OLD_DATA"), int(telemetryTailBytes/16)+100)
164
+ data := append(prefix, '\n')
165
+ data = append(data, encoded...)
166
+ data = append(data, '\n')
167
+ if err := os.WriteFile(filepath.Join(root, "timeline.jsonl"), data, 0o644); err != nil {
168
+ t.Fatal(err)
169
+ }
170
+ events, stats := readTelemetryTail(filepath.Join(root, "timeline.jsonl"))
171
+ if len(events) != 1 || !stats.TailTruncated || stats.ReadDegraded {
172
+ t.Fatalf("bounded tail events=%d stats=%+v", len(events), stats)
173
+ }
174
+
175
+ data = append(encoded, '\n')
176
+ data = append(data, bytes.Repeat([]byte("x"), telemetryMaxLineBytes+1)...)
177
+ data = append(data, '\n')
178
+ if err := os.WriteFile(filepath.Join(root, "timeline.jsonl"), data, 0o644); err != nil {
179
+ t.Fatal(err)
180
+ }
181
+ var stdout, stderr bytes.Buffer
182
+ if code := Timeline(root, []string{"report", "--run", testRunID, "--json"}, &stdout, &stderr); code != 0 {
183
+ t.Fatalf("oversized report code=%d stderr=%q", code, stderr.String())
184
+ }
185
+ var report observabilityReport
186
+ if err := json.Unmarshal(stdout.Bytes(), &report); err != nil {
187
+ t.Fatal(err)
188
+ }
189
+ if report.Events != 1 || !report.TelemetryRead.ReadDegraded {
190
+ t.Fatalf("oversized row did not degrade report only: %+v", report)
191
+ }
192
+ }
193
+
194
+ func TestTelemetryAppendStopsAtLocalStorageBound(t *testing.T) {
195
+ root, _ := makeObservabilityWorkspace(t)
196
+ path := filepath.Join(root, "timeline.jsonl")
197
+ if err := os.WriteFile(path, bytes.Repeat([]byte("x"), int(telemetryMaxStorageBytes)), 0o644); err != nil {
198
+ t.Fatal(err)
199
+ }
200
+ before, err := os.Stat(path)
201
+ if err != nil {
202
+ t.Fatal(err)
203
+ }
204
+ event := NewEventV1(BoundaryAgentDispatch, "run-started", reason.RootSelected)
205
+ event.TS = "2026-07-23T12:00:00Z"
206
+ event.RunID = testRunID
207
+ event.RootSource = RootSourceExplicit
208
+ event.Workspace = ".devrites/work/demo"
209
+ event.Outcome = OutcomeRecorded
210
+ if err := AppendEventV1(root, event); err == nil ||
211
+ !strings.Contains(err.Error(), "retention bound") {
212
+ t.Fatalf("bounded append err=%v", err)
213
+ }
214
+ after, err := os.Stat(path)
215
+ if err != nil || after.Size() != before.Size() {
216
+ t.Fatalf("bounded append changed file: before=%d after=%d err=%v", before.Size(), after.Size(), err)
217
+ }
218
+ }
219
+
220
+ func TestTimelinePurgeTouchesOnlySelectedV1Telemetry(t *testing.T) {
221
+ root, work := makeObservabilityWorkspace(t)
222
+ appendObservabilityEvent(t, root, testRunID, "2026-07-23T12:00:00Z",
223
+ "run-started", BoundaryAgentDispatch, reason.RootSelected, OutcomeRecorded, state.PhaseBuild)
224
+ appendObservabilityEvent(t, root, observabilityOtherRunID, "2026-07-23T13:00:00Z",
225
+ "run-started", BoundaryAgentDispatch, reason.RootSelected, OutcomeRecorded, state.PhaseBuild)
226
+ legacy := []byte(`{"ts":"2026-07-23T10:00:00Z","event":"auq","question":"legacy stays"}` + "\n")
227
+ for _, path := range []string{
228
+ filepath.Join(root, "timeline.jsonl"),
229
+ filepath.Join(work, "events.jsonl"),
230
+ } {
231
+ f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0o644)
232
+ if err != nil {
233
+ t.Fatal(err)
234
+ }
235
+ if _, err := f.Write(legacy); err != nil {
236
+ f.Close()
237
+ t.Fatal(err)
238
+ }
239
+ if err := f.Close(); err != nil {
240
+ t.Fatal(err)
241
+ }
242
+ }
243
+ correctness := map[string][]byte{
244
+ "state.md": []byte("state-sentinel\n"),
245
+ "questions.md": []byte("questions-sentinel\n"),
246
+ "evidence.md": []byte("evidence-sentinel\n"),
247
+ "recovery-attempts.jsonl": []byte("recovery-sentinel\n"),
248
+ "decisions.md": []byte("decisions-sentinel\n"),
249
+ ".wright-allowlist": []byte("scope-sentinel\n"),
250
+ }
251
+ for name, content := range correctness {
252
+ if err := os.WriteFile(filepath.Join(work, name), content, 0o644); err != nil {
253
+ t.Fatal(err)
254
+ }
255
+ }
256
+
257
+ var stdout, stderr bytes.Buffer
258
+ if code := Timeline(root, []string{"purge", "--run", testRunID}, &stdout, &stderr); code != 0 {
259
+ t.Fatalf("purge code=%d stdout=%q stderr=%q", code, stdout.String(), stderr.String())
260
+ }
261
+ if !strings.Contains(stdout.String(), "purged 2 v1 event(s) from 2 telemetry file(s)") {
262
+ t.Fatalf("purge summary=%q", stdout.String())
263
+ }
264
+ for _, path := range []string{
265
+ filepath.Join(root, "timeline.jsonl"),
266
+ filepath.Join(work, "events.jsonl"),
267
+ } {
268
+ data, err := os.ReadFile(path)
269
+ if err != nil {
270
+ t.Fatal(err)
271
+ }
272
+ if strings.Contains(string(data), testRunID) ||
273
+ !strings.Contains(string(data), observabilityOtherRunID) ||
274
+ !strings.Contains(string(data), "legacy stays") {
275
+ t.Fatalf("purge scope wrong for %s: %s", path, data)
276
+ }
277
+ }
278
+ for name, content := range correctness {
279
+ got, err := os.ReadFile(filepath.Join(work, name))
280
+ if err != nil || !bytes.Equal(got, content) {
281
+ t.Fatalf("purge changed correctness file %s: got=%q err=%v", name, got, err)
282
+ }
283
+ }
284
+
285
+ stdout.Reset()
286
+ stderr.Reset()
287
+ if code := Timeline(root, []string{"purge", "--before", "2026-07-23T14:00:00Z"}, &stdout, &stderr); code != 0 {
288
+ t.Fatalf("time purge code=%d stdout=%q stderr=%q", code, stdout.String(), stderr.String())
289
+ }
290
+ for _, path := range []string{
291
+ filepath.Join(root, "timeline.jsonl"),
292
+ filepath.Join(work, "events.jsonl"),
293
+ } {
294
+ data, err := os.ReadFile(path)
295
+ if err != nil {
296
+ t.Fatal(err)
297
+ }
298
+ if strings.Contains(string(data), observabilityOtherRunID) ||
299
+ !strings.Contains(string(data), "legacy stays") {
300
+ t.Fatalf("time purge interpreted legacy or kept old v1 row in %s: %s", path, data)
301
+ }
302
+ }
303
+ }
304
+
305
+ func TestTimelinePurgeSelectorsAndSymlinkSafety(t *testing.T) {
306
+ root, _ := makeObservabilityWorkspace(t)
307
+ var stdout, stderr bytes.Buffer
308
+ if code := Timeline(root, []string{"purge"}, &stdout, &stderr); code != 2 {
309
+ t.Fatalf("selector-free purge code=%d", code)
310
+ }
311
+
312
+ outside := filepath.Join(t.TempDir(), "outside.jsonl")
313
+ if err := os.WriteFile(outside, []byte("outside-sentinel\n"), 0o644); err != nil {
314
+ t.Fatal(err)
315
+ }
316
+ if err := os.Symlink(outside, filepath.Join(root, "timeline.jsonl")); err != nil {
317
+ t.Skipf("symlinks unavailable: %v", err)
318
+ }
319
+ stdout.Reset()
320
+ stderr.Reset()
321
+ if code := Timeline(root, []string{"purge", "--before", "2026-07-24T00:00:00Z"}, &stdout, &stderr); code != 1 {
322
+ t.Fatalf("symlink purge code=%d stderr=%q", code, stderr.String())
323
+ }
324
+ got, err := os.ReadFile(outside)
325
+ if err != nil || string(got) != "outside-sentinel\n" {
326
+ t.Fatalf("purge followed telemetry symlink: got=%q err=%v", got, err)
327
+ }
328
+ }
329
+
330
+ func TestProgressShowsV1FactsWithoutChangingLifecycle(t *testing.T) {
331
+ root, work := makeObservabilityWorkspace(t)
332
+ stateText := "| Key | Value |\n| --- | --- |\n| phase | build |\n| status | running |\n"
333
+ if err := os.WriteFile(filepath.Join(work, "state.md"), []byte(stateText), 0o644); err != nil {
334
+ t.Fatal(err)
335
+ }
336
+ event := appendObservabilityEvent(t, root, testRunID, time.Now().UTC().Format(time.RFC3339),
337
+ "readiness", BoundaryLifecycleGate, reason.GateReadinessMissing, OutcomeBlocked, state.PhaseBuild)
338
+ event.ExecutionMode = ExecutionGeneric
339
+ rewriteLastObservabilityEvent(t, root, event)
340
+
341
+ before, err := os.ReadFile(filepath.Join(work, "state.md"))
342
+ if err != nil {
343
+ t.Fatal(err)
344
+ }
345
+ var stdout bytes.Buffer
346
+ if code := Progress(root, []string{"demo"}, &stdout, &bytes.Buffer{}); code != 0 {
347
+ t.Fatalf("progress code=%d", code)
348
+ }
349
+ for _, want := range []string{"rite-build", "Obs obs mode:generic", "gate:DRV-GATE-READINESS-MISSING", "degraded:1"} {
350
+ if !strings.Contains(stdout.String(), want) {
351
+ t.Fatalf("progress missing %q:\n%s", want, stdout.String())
352
+ }
353
+ }
354
+ after, err := os.ReadFile(filepath.Join(work, "state.md"))
355
+ if err != nil || !bytes.Equal(before, after) {
356
+ t.Fatalf("observability display changed lifecycle state: err=%v", err)
357
+ }
358
+ }
@@ -1,14 +1,12 @@
1
1
  package lib
2
2
 
3
3
  import (
4
- "bytes"
5
4
  "encoding/json"
6
5
  "fmt"
7
6
  "go/parser"
8
7
  "go/token"
9
8
  "io"
10
9
  "os"
11
- "os/exec"
12
10
  "path/filepath"
13
11
  "regexp"
14
12
  "sort"
@@ -20,6 +18,8 @@ import (
20
18
  // the standard parser, and Python/Rust use their import declaration syntax.
21
19
  var (
22
20
  quotedModule = regexp.MustCompile(`\b(?:from|import|require)[[:space:]]*(?:\([[:space:]]*)?['"]([^'"]+)['"]`)
21
+ cssImport = regexp.MustCompile(`(?i)@import[[:space:]]+(?:url\([[:space:]]*)?(?:['"]([^'"]+)['"]|([^[:space:]);]+))`)
22
+ remoteImport = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9+.-]*:`)
23
23
  pythonImport = regexp.MustCompile(`^\+?[[:space:]]*import[[:space:]]+([A-Za-z0-9_./-]+)`)
24
24
  pythonFrom = regexp.MustCompile(`^\+?[[:space:]]*from[[:space:]]+([A-Za-z0-9_./-]+)[[:space:]]+import\b`)
25
25
  rustUse = regexp.MustCompile(`^[[:space:]]*(?:pub(?:\([^)]*\))?[[:space:]]+)?use[[:space:]]+(?:::)?(?:r#)?([A-Za-z_][A-Za-z0-9_]*)(?:::|[[:space:]]+as\b|[[:space:]]*;)`)
@@ -56,6 +56,7 @@ type packageResolver struct {
56
56
 
57
57
  var packageResolvers = []packageResolver{
58
58
  {extensions: " .js .jsx .mjs .cjs .ts .tsx .mts .cts .svelte .vue ", extract: quotedModulesFromAddedLines, resolve: resolveJavaScriptImport},
59
+ {extensions: " .css ", extract: cssModulesFromAddedLines, resolve: resolveCSSImport},
59
60
  {extensions: " .go ", extract: goModulesFromAddedLinesForSource, resolve: resolveGoImport},
60
61
  {extensions: " .py .pyi ", extract: pythonModulesFromAddedLines, resolve: resolvePythonImport},
61
62
  {extensions: " .rs ", extract: rustModulesFromAddedLines, resolve: resolveRustImport},
@@ -63,13 +64,12 @@ var packageResolvers = []packageResolver{
63
64
 
64
65
  var fallbackPackageResolver = packageResolver{extract: quotedModulesFromAddedLines, resolve: resolveGenericImport}
65
66
 
66
- // PackageExistence catches hallucinated or typo-squatted dependencies: every new
67
- // third-party import in the slice diff must be DECLARED in a project manifest, not
68
- // merely imported. It is deterministic and offline: it checks the manifest, not a
69
- // package registry. The workspace is <root>/features/<slug>.
67
+ // PackageExistence checks that every new third-party import in the slice diff is
68
+ // declared in a project manifest. It works offline and does not query a package
69
+ // registry. The workspace is <root>/features/<slug>.
70
70
  //
71
71
  // 0 clean, nothing to check, or skipped (not a git repo / no manifest)
72
- // 2 no active workspace
72
+ // 2 no active workspace or missing/corrupt baseline state
73
73
  // 3 an imported package is not declared in any manifest
74
74
  func PackageExistence(root string, args []string, stdout, stderr io.Writer) int {
75
75
  slug := slugOrActive(root, args)
@@ -89,12 +89,12 @@ func PackageExistence(root string, args []string, stdout, stderr io.Writer) int
89
89
  fmt.Fprintln(stderr, "package-existence: not a git repo: skipped.")
90
90
  return 0
91
91
  }
92
- ref := "HEAD"
93
- if b, err := os.ReadFile(filepath.Join(d, ".reconcile-base")); err == nil {
94
- if t := strings.TrimSpace(string(b)); t != "" {
95
- ref = t
96
- }
92
+ trees, err := captureSliceTreeRange(gitRoot, root, d)
93
+ if err != nil {
94
+ fmt.Fprintf(stderr, "package-existence: cannot capture slice range: %v\n", err)
95
+ return 2
97
96
  }
97
+ defer trees.cleanup()
98
98
 
99
99
  var rootManifests []string
100
100
  for _, m := range manifestFiles {
@@ -104,7 +104,11 @@ func PackageExistence(root string, args []string, stdout, stderr io.Writer) int
104
104
  }
105
105
  }
106
106
 
107
- imports := extractImportedPackages(gitRoot, ref)
107
+ imports, err := extractImportedPackages(gitRoot, trees.base, trees.current, trees.env)
108
+ if err != nil {
109
+ fmt.Fprintf(stderr, "package-existence: cannot inspect slice imports: %v\n", err)
110
+ return 2
111
+ }
108
112
  hasManifest := len(rootManifests) > 0
109
113
  findings := map[string]struct{}{}
110
114
  for _, imported := range imports {
@@ -136,7 +140,7 @@ func PackageExistence(root string, args []string, stdout, stderr io.Writer) int
136
140
  for _, pkg := range packages {
137
141
  fmt.Fprintf(stderr, " - %s: imported but not declared in any manifest\n", pkg)
138
142
  }
139
- fmt.Fprintln(stderr, "An undeclared import is how hallucinated/typo-squatted packages slip in. Confirm the name on the registry before trusting it.")
143
+ fmt.Fprintln(stderr, "Check each package name in its registry before trusting it. Undeclared imports may be misspelled, typo-squatted, or nonexistent.")
140
144
  return 3
141
145
  }
142
146
  fmt.Fprintln(stdout, "package-existence: OK: every new third-party import is declared in a manifest.")
@@ -144,35 +148,54 @@ func PackageExistence(root string, args []string, stdout, stderr io.Writer) int
144
148
  }
145
149
 
146
150
  // extractImportedPackages retains the source file and raw specifier for each
147
- // import added by the diff so workspace and alias resolution can use that
148
- // provenance before the specifier is reduced to a top-level package name.
149
- func extractImportedPackages(gitRoot, ref string) []importedModule {
150
- out, err := exec.Command("git", "-C", gitRoot, "diff", "--name-only", "-z", ref, "--").Output()
151
+ // import introduced between two immutable trees. CSS is parsed from complete
152
+ // baseline/current files so block-comment state from unchanged lines is
153
+ // preserved; other languages retain the established added-line extraction.
154
+ func extractImportedPackages(gitRoot, baseTree, currentTree string, env []string) ([]importedModule, error) {
155
+ paths, err := changedTreePaths(gitRoot, env, baseTree, currentTree)
151
156
  if err != nil {
152
- return nil
157
+ return nil, err
153
158
  }
159
+
154
160
  var imports []importedModule
155
- for rawPath := range bytes.SplitSeq(out, []byte{0}) {
156
- if len(rawPath) == 0 {
157
- continue
158
- }
159
- sourcePath := filepath.Clean(string(rawPath))
160
- diff, err := exec.Command("git", "-C", gitRoot, "diff", "--unified=0", ref, "--", sourcePath).Output()
161
+ for _, sourcePath := range paths {
162
+ currentSource, currentExists, err := treeFileContent(gitRoot, env, currentTree, sourcePath)
161
163
  if err != nil {
164
+ return nil, err
165
+ }
166
+ if !currentExists {
162
167
  continue
163
168
  }
164
- var addedLines []string
165
- for _, line := range splitLinesNoTrailing(diff) {
166
- if !strings.HasPrefix(line, "+") || strings.HasPrefix(line, "+++") {
167
- continue
169
+
170
+ var specifiers []string
171
+ if strings.EqualFold(filepath.Ext(sourcePath), ".css") {
172
+ baselineSource, _, err := treeFileContent(gitRoot, env, baseTree, sourcePath)
173
+ if err != nil {
174
+ return nil, err
175
+ }
176
+ specifiers = addedCSSModules(baselineSource, currentSource)
177
+ } else {
178
+ diff, err := reconcileGitOutput(
179
+ gitRoot,
180
+ env,
181
+ "diff", "--unified=0", "--no-renames", baseTree, currentTree, "--", sourcePath,
182
+ )
183
+ if err != nil {
184
+ return nil, err
185
+ }
186
+ var addedLines []string
187
+ for _, line := range splitLinesNoTrailing(diff) {
188
+ if strings.HasPrefix(line, "+") && !strings.HasPrefix(line, "+++") {
189
+ addedLines = append(addedLines, strings.TrimPrefix(line, "+"))
190
+ }
168
191
  }
169
- addedLines = append(addedLines, strings.TrimPrefix(line, "+"))
192
+ specifiers = importedModulesFromAddedLines(gitRoot, sourcePath, addedLines)
170
193
  }
171
- for _, specifier := range importedModulesFromAddedLines(gitRoot, sourcePath, addedLines) {
194
+ for _, specifier := range specifiers {
172
195
  imports = append(imports, importedModule{sourcePath: sourcePath, specifier: specifier})
173
196
  }
174
197
  }
175
- return imports
198
+ return imports, nil
176
199
  }
177
200
 
178
201
  func importedModulesFromAddedLines(gitRoot, sourcePath string, lines []string) []string {
@@ -202,6 +225,17 @@ func resolveJavaScriptImport(gitRoot, sourcePath, specifier string) packageResol
202
225
  }
203
226
  }
204
227
 
228
+ func resolveCSSImport(gitRoot, sourcePath, specifier string) packageResolution {
229
+ specifier = strings.TrimSpace(specifier)
230
+ if remoteImport.MatchString(specifier) || strings.HasPrefix(specifier, "//") {
231
+ return packageResolution{ignored: true}
232
+ }
233
+ if cssSourceRelativePathExists(gitRoot, sourcePath, specifier) {
234
+ return packageResolution{resolved: true}
235
+ }
236
+ return resolveJavaScriptImport(gitRoot, sourcePath, specifier)
237
+ }
238
+
205
239
  func resolveGoImport(gitRoot, sourcePath, specifier string) packageResolution {
206
240
  if isGoStandardLibrary(specifier) {
207
241
  return packageResolution{ignored: true}
@@ -228,9 +262,9 @@ func resolveRustImport(gitRoot, sourcePath, specifier string) packageResolution
228
262
  return packageResolution{name: crate, resolved: resolved, manifestFound: manifestFound}
229
263
  }
230
264
 
231
- // resolveGenericImport keeps quoted imports in unregistered source types in the
232
- // shared pipeline. It deliberately fails closed: without ecosystem semantics,
233
- // text in an unrelated manifest cannot safely prove that an import is declared.
265
+ // resolveGenericImport sends quoted imports from unregistered source types
266
+ // through the shared pipeline. Without ecosystem rules, a nearby manifest is
267
+ // recorded but cannot prove that the import is declared.
234
268
  func resolveGenericImport(gitRoot, sourcePath, specifier string) packageResolution {
235
269
  pkg := normalizeImportedPackage(specifier)
236
270
  if pkg == "" {
@@ -250,6 +284,88 @@ func quotedModulesFromAddedLines(_, _ string, lines []string) []string {
250
284
  return modules
251
285
  }
252
286
 
287
+ func cssModulesFromAddedLines(_, _ string, lines []string) []string {
288
+ return cssModulesFromSource([]byte(strings.Join(lines, "\n")))
289
+ }
290
+
291
+ func addedCSSModules(baseline, current []byte) []string {
292
+ baselineCounts := map[string]int{}
293
+ for _, module := range cssModulesFromSource(baseline) {
294
+ baselineCounts[module]++
295
+ }
296
+ var added []string
297
+ for _, module := range cssModulesFromSource(current) {
298
+ if baselineCounts[module] > 0 {
299
+ baselineCounts[module]--
300
+ continue
301
+ }
302
+ added = append(added, module)
303
+ }
304
+ return added
305
+ }
306
+
307
+ func cssModulesFromSource(source []byte) []string {
308
+ activeSource := stripCSSComments(string(source))
309
+ var modules []string
310
+ for _, match := range cssImport.FindAllStringSubmatch(activeSource, -1) {
311
+ if len(match) < 3 {
312
+ continue
313
+ }
314
+ module := match[1]
315
+ if module == "" {
316
+ module = match[2]
317
+ }
318
+ modules = append(modules, module)
319
+ }
320
+ return modules
321
+ }
322
+
323
+ func stripCSSComments(source string) string {
324
+ var active strings.Builder
325
+ active.Grow(len(source))
326
+ inComment := false
327
+ for i := 0; i < len(source); {
328
+ switch {
329
+ case !inComment && i+1 < len(source) && source[i] == '/' && source[i+1] == '*':
330
+ inComment = true
331
+ active.WriteString(" ")
332
+ i += 2
333
+ case inComment && i+1 < len(source) && source[i] == '*' && source[i+1] == '/':
334
+ inComment = false
335
+ active.WriteString(" ")
336
+ i += 2
337
+ case inComment:
338
+ if source[i] == '\n' {
339
+ active.WriteByte('\n')
340
+ } else {
341
+ active.WriteByte(' ')
342
+ }
343
+ i++
344
+ default:
345
+ active.WriteByte(source[i])
346
+ i++
347
+ }
348
+ }
349
+ return active.String()
350
+ }
351
+
352
+ func cssSourceRelativePathExists(gitRoot, sourcePath, specifier string) bool {
353
+ localSpecifier := specifier
354
+ if index := strings.IndexAny(localSpecifier, "?#"); index >= 0 {
355
+ localSpecifier = localSpecifier[:index]
356
+ }
357
+ if localSpecifier == "" {
358
+ return false
359
+ }
360
+ candidate := filepath.Join(
361
+ gitRoot,
362
+ filepath.Dir(filepath.FromSlash(sourcePath)),
363
+ filepath.FromSlash(localSpecifier),
364
+ )
365
+ info, err := os.Stat(candidate)
366
+ return err == nil && !info.IsDir()
367
+ }
368
+
253
369
  func goModulesFromAddedLinesForSource(gitRoot, sourcePath string, lines []string) []string {
254
370
  return goModulesFromAddedLines(filepath.Join(gitRoot, sourcePath), lines)
255
371
  }