openlanes 3.0.1 → 3.1.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 (319) hide show
  1. checksums.yaml +4 -4
  2. data/Brewfile +42 -0
  3. data/agents/bb8-resolver.md +49 -0
  4. data/agents/c3po-operator.md +4 -0
  5. data/agents/chewie-verifier.md +85 -0
  6. data/agents/hansolo-reviewer.md +20 -15
  7. data/agents/lando-broker.md +81 -19
  8. data/agents/leah-researcher.md +6 -6
  9. data/agents/luke-backend.md +41 -20
  10. data/agents/{palpatine-planner.md → luthen-rael-planner.md} +15 -13
  11. data/agents/palpatine-risk-assessor.md +112 -0
  12. data/agents/r2d2-mechanic.md +5 -1
  13. data/agents/rey-frontend.md +38 -19
  14. data/agents/yoda-writer.md +7 -7
  15. data/evals/cases/chewie-verifier/verify-medium/fail/plan/plan.md +7 -0
  16. data/evals/cases/chewie-verifier/verify-medium/fail/plan/pull-requests.md +10 -0
  17. data/evals/cases/chewie-verifier/verify-medium/fail/plan/spec.md +5 -0
  18. data/evals/cases/chewie-verifier/verify-medium/fail/plan/verification/1/final.png +0 -0
  19. data/evals/cases/chewie-verifier/verify-medium/fail/plan/verification/1/report.md +7 -0
  20. data/evals/cases/chewie-verifier/verify-medium/fail/repo/bin/greet +1 -0
  21. data/evals/cases/chewie-verifier/verify-medium/fail/run.json +1 -0
  22. data/evals/cases/chewie-verifier/verify-medium/pass/plan/plan.md +7 -0
  23. data/evals/cases/chewie-verifier/verify-medium/pass/plan/pull-requests.md +10 -0
  24. data/evals/cases/chewie-verifier/verify-medium/pass/plan/spec.md +5 -0
  25. data/evals/cases/chewie-verifier/verify-medium/pass/plan/verification/1/final.png +0 -0
  26. data/evals/cases/chewie-verifier/verify-medium/pass/plan/verification/1/report.md +14 -0
  27. data/evals/cases/chewie-verifier/verify-medium/pass/plan/verification/1/step-01.png +0 -0
  28. data/evals/cases/chewie-verifier/verify-medium/pass/repo/bin/greet +1 -0
  29. data/evals/cases/chewie-verifier/verify-medium/pass/run.json +1 -0
  30. data/evals/cases/chewie-verifier/verify-medium.yml +48 -0
  31. data/evals/cases/hansolo-reviewer/coverage-minimum/fail/plan/implementation-plan.md +5 -0
  32. data/evals/cases/hansolo-reviewer/coverage-minimum/fail/plan/plan.md +3 -0
  33. data/evals/cases/hansolo-reviewer/coverage-minimum/fail/plan/pull-requests.md +12 -0
  34. data/evals/cases/hansolo-reviewer/coverage-minimum/fail/plan/spec.md +5 -0
  35. data/evals/cases/hansolo-reviewer/coverage-minimum/fail/repo/lib/cart.rb +10 -0
  36. data/evals/cases/hansolo-reviewer/coverage-minimum/fail/repo/spec/cart_spec.rb +9 -0
  37. data/evals/cases/hansolo-reviewer/coverage-minimum/fail/run.json +1 -0
  38. data/evals/cases/hansolo-reviewer/coverage-minimum/pass/plan/implementation-plan.md +5 -0
  39. data/evals/cases/hansolo-reviewer/coverage-minimum/pass/plan/plan.md +3 -0
  40. data/evals/cases/hansolo-reviewer/coverage-minimum/pass/plan/pull-requests.md +15 -0
  41. data/evals/cases/hansolo-reviewer/coverage-minimum/pass/plan/spec.md +5 -0
  42. data/evals/cases/hansolo-reviewer/coverage-minimum/pass/repo/lib/cart.rb +10 -0
  43. data/evals/cases/hansolo-reviewer/coverage-minimum/pass/repo/spec/cart_spec.rb +9 -0
  44. data/evals/cases/hansolo-reviewer/coverage-minimum/pass/run.json +1 -0
  45. data/evals/cases/hansolo-reviewer/coverage-minimum.yml +76 -0
  46. data/evals/cases/luthen-rael-planner/plan-deep/fail/plan/plan.md +8 -0
  47. data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep/pass/plan/plan.md +2 -2
  48. data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep.yml +1 -1
  49. data/evals/cases/luthen-rael-planner/plan-fast/fail/plan/plan.md +12 -0
  50. data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/pass/plan/plan.md +2 -2
  51. data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast.yml +1 -1
  52. data/evals/cases/palpatine-risk-assessor/risk-medium/fail/plan/plan.md +20 -0
  53. data/evals/cases/palpatine-risk-assessor/risk-medium/fail/plan/pull-requests.md +5 -0
  54. data/evals/cases/palpatine-risk-assessor/risk-medium/fail/plan/spec.md +5 -0
  55. data/evals/cases/palpatine-risk-assessor/risk-medium/fail/repo/db/migrate/20261020120000_drop_legacy_email.rb +5 -0
  56. data/evals/cases/palpatine-risk-assessor/risk-medium/fail/run.json +1 -0
  57. data/evals/cases/palpatine-risk-assessor/risk-medium/pass/plan/plan.md +25 -0
  58. data/evals/cases/palpatine-risk-assessor/risk-medium/pass/plan/pull-requests.md +5 -0
  59. data/evals/cases/palpatine-risk-assessor/risk-medium/pass/plan/spec.md +5 -0
  60. data/evals/cases/palpatine-risk-assessor/risk-medium/pass/repo/db/migrate/20261020120000_drop_legacy_email.rb +5 -0
  61. data/evals/cases/palpatine-risk-assessor/risk-medium/pass/run.json +1 -0
  62. data/evals/cases/palpatine-risk-assessor/risk-medium.yml +47 -0
  63. data/evals/cases/yoda-writer/spec-medium/pass/plan/spec.md +1 -1
  64. data/lib/openlanes/adapters/base.rb +18 -4
  65. data/lib/openlanes/adapters/capabilities.rb +29 -0
  66. data/lib/openlanes/adapters/claude.rb +14 -11
  67. data/lib/openlanes/adapters/codex.rb +9 -0
  68. data/lib/openlanes/adapters/pi.rb +10 -0
  69. data/lib/openlanes/adapters/stream.rb +145 -1
  70. data/lib/openlanes/adapters.rb +7 -0
  71. data/lib/openlanes/agents/agent.rb +4 -3
  72. data/lib/openlanes/agents/roster.rb +14 -2
  73. data/lib/openlanes/agents/routing.rb +43 -3
  74. data/lib/openlanes/apps/definition.rb +152 -0
  75. data/lib/openlanes/apps/framing.rb +114 -0
  76. data/lib/openlanes/apps/listing.rb +60 -0
  77. data/lib/openlanes/apps/ports.rb +168 -0
  78. data/lib/openlanes/apps/probe.rb +63 -0
  79. data/lib/openlanes/apps/process_spec.rb +39 -0
  80. data/lib/openlanes/apps/runner.rb +174 -0
  81. data/lib/openlanes/apps/status.rb +62 -0
  82. data/lib/openlanes/apps/supervisor.rb +277 -0
  83. data/lib/openlanes/apps/watcher.rb +50 -0
  84. data/lib/openlanes/apps.rb +41 -0
  85. data/lib/openlanes/cli/api/api.rb +10 -0
  86. data/lib/openlanes/cli/api/subcommands/docs.rb +63 -0
  87. data/lib/openlanes/cli/app/app.rb +31 -0
  88. data/lib/openlanes/cli/app/subcommands/start.rb +114 -0
  89. data/lib/openlanes/cli/app/subcommands/status.rb +38 -0
  90. data/lib/openlanes/cli/app/subcommands/stop.rb +44 -0
  91. data/lib/openlanes/cli/base.rb +89 -16
  92. data/lib/openlanes/cli/coverage/coverage.rb +68 -0
  93. data/lib/openlanes/cli/create/create.rb +11 -265
  94. data/lib/openlanes/cli/eval/eval.rb +4 -1
  95. data/lib/openlanes/cli/init/init.rb +39 -2
  96. data/lib/openlanes/cli/linear/subcommands/import.rb +1 -1
  97. data/lib/openlanes/cli/linear/subcommands/projects.rb +1 -1
  98. data/lib/openlanes/cli/list_plans/list_plans.rb +8 -2
  99. data/lib/openlanes/cli/mail/subcommands/ack.rb +52 -0
  100. data/lib/openlanes/cli/mail/subcommands/render.rb +31 -0
  101. data/lib/openlanes/cli/mail/subcommands/send.rb +26 -0
  102. data/lib/openlanes/cli/resync/subcommands/dirs.rb +53 -12
  103. data/lib/openlanes/cli/resync/subcommands/prs.rb +8 -69
  104. data/lib/openlanes/cli/review/review.rb +72 -0
  105. data/lib/openlanes/cli/run/run.rb +22 -486
  106. data/lib/openlanes/cli/setup/setup.rb +51 -0
  107. data/lib/openlanes/cli/start/start.rb +7 -51
  108. data/lib/openlanes/cli/state/state.rb +1 -1
  109. data/lib/openlanes/cli/state/subcommands/resume.rb +61 -0
  110. data/lib/openlanes/cli/state/subcommands/sign.rb +1 -1
  111. data/lib/openlanes/cli/unblock/unblock.rb +11 -205
  112. data/lib/openlanes/cli/web/web.rb +84 -8
  113. data/lib/openlanes/cli/worktree/worktree.rb +1 -1
  114. data/lib/openlanes/cli/worktree/worktree_prune.rb +77 -0
  115. data/lib/openlanes/cli.rb +37 -2
  116. data/lib/openlanes/coverage/cobertura.rb +49 -0
  117. data/lib/openlanes/coverage/config.rb +194 -0
  118. data/lib/openlanes/coverage/istanbul.rb +31 -0
  119. data/lib/openlanes/coverage/lcov.rb +38 -0
  120. data/lib/openlanes/coverage/report.rb +71 -0
  121. data/lib/openlanes/coverage/simplecov.rb +70 -0
  122. data/lib/openlanes/coverage.rb +33 -0
  123. data/lib/openlanes/engine/agent_locks.rb +231 -0
  124. data/lib/openlanes/engine/arbitration.rb +25 -0
  125. data/lib/openlanes/engine/board.rb +36 -5
  126. data/lib/openlanes/engine/conversions.rb +160 -0
  127. data/lib/openlanes/engine/coverage_gate.rb +217 -0
  128. data/lib/openlanes/engine/dispatcher.rb +1175 -117
  129. data/lib/openlanes/engine/event_journal/replay.rb +96 -0
  130. data/lib/openlanes/engine/event_journal.rb +148 -0
  131. data/lib/openlanes/engine/extensions.rb +271 -0
  132. data/lib/openlanes/engine/merging.rb +459 -0
  133. data/lib/openlanes/engine/narrator.rb +6 -6
  134. data/lib/openlanes/engine/plan_locks.rb +114 -0
  135. data/lib/openlanes/engine/pr_outcomes.rb +161 -0
  136. data/lib/openlanes/engine/pr_watch.rb +83 -0
  137. data/lib/openlanes/engine/progress_log.rb +12 -120
  138. data/lib/openlanes/engine/quality_question.rb +125 -0
  139. data/lib/openlanes/engine/rebase.rb +200 -0
  140. data/lib/openlanes/engine/run_workflow.rb +776 -0
  141. data/lib/openlanes/engine/runner.rb +186 -15
  142. data/lib/openlanes/engine/start_workflow.rb +77 -0
  143. data/lib/openlanes/engine/state_file.rb +101 -34
  144. data/lib/openlanes/engine/tally.rb +1 -1
  145. data/lib/openlanes/engine/verification/app_session.rb +104 -0
  146. data/lib/openlanes/engine/verification/driver.rb +314 -0
  147. data/lib/openlanes/engine/verification/outcome.rb +516 -0
  148. data/lib/openlanes/engine/verification/report.rb +95 -0
  149. data/lib/openlanes/engine/verification/round.rb +100 -0
  150. data/lib/openlanes/engine/verification/screenshots.rb +120 -0
  151. data/lib/openlanes/engine/verification.rb +57 -0
  152. data/lib/openlanes/engine.rb +30 -1
  153. data/lib/openlanes/execution/boundary.rb +212 -0
  154. data/lib/openlanes/execution/child.rb +4 -2
  155. data/lib/openlanes/execution/clock.rb +36 -6
  156. data/lib/openlanes/execution/control.rb +32 -0
  157. data/lib/openlanes/execution/executor.rb +114 -35
  158. data/lib/openlanes/execution/process_start.rb +63 -0
  159. data/lib/openlanes/execution/prompt.rb +223 -34
  160. data/lib/openlanes/execution/transcript.rb +159 -8
  161. data/lib/openlanes/execution.rb +21 -0
  162. data/lib/openlanes/lifecycle/adoption.rb +25 -8
  163. data/lib/openlanes/lifecycle/aging.rb +166 -0
  164. data/lib/openlanes/lifecycle/allocator.rb +216 -0
  165. data/lib/openlanes/lifecycle/brief.rb +32 -2
  166. data/lib/openlanes/lifecycle/completion.rb +12 -6
  167. data/lib/openlanes/lifecycle/create_workflow.rb +272 -0
  168. data/lib/openlanes/lifecycle/creator.rb +17 -13
  169. data/lib/openlanes/lifecycle/lanes.rb +1 -1
  170. data/lib/openlanes/lifecycle/resync.rb +170 -42
  171. data/lib/openlanes/lifecycle/unblock_workflow.rb +234 -0
  172. data/lib/openlanes/lifecycle/unblocker.rb +76 -2
  173. data/lib/openlanes/lifecycle.rb +37 -1
  174. data/lib/openlanes/linear/mapping.rb +4 -1
  175. data/lib/openlanes/linear/unit.rb +1 -1
  176. data/lib/openlanes/live/chat.rb +60 -11
  177. data/lib/openlanes/live/choice_converter.rb +166 -0
  178. data/lib/openlanes/live/choice_judge.rb +109 -0
  179. data/lib/openlanes/live/claims.rb +9 -1
  180. data/lib/openlanes/live/command.rb +13 -10
  181. data/lib/openlanes/live/commands.rb +217 -30
  182. data/lib/openlanes/live/copilot/slash.rb +82 -0
  183. data/lib/openlanes/live/copilot.rb +38 -4
  184. data/lib/openlanes/live/event_bus/base.rb +52 -0
  185. data/lib/openlanes/live/event_bus/memory_bus.rb +14 -0
  186. data/lib/openlanes/live/event_bus/redis_bus.rb +10 -0
  187. data/lib/openlanes/live/event_bus/transaction.rb +27 -0
  188. data/lib/openlanes/live/event_bus.rb +29 -0
  189. data/lib/openlanes/live/interviewer.rb +146 -0
  190. data/lib/openlanes/live/keys.rb +56 -0
  191. data/lib/openlanes/live/mail.rb +143 -0
  192. data/lib/openlanes/live/memory_store.rb +12 -1
  193. data/lib/openlanes/live/news.rb +61 -0
  194. data/lib/openlanes/live/node.rb +20 -0
  195. data/lib/openlanes/live/outage.rb +225 -0
  196. data/lib/openlanes/live/outage_report.rb +89 -0
  197. data/lib/openlanes/live/publisher.rb +42 -2
  198. data/lib/openlanes/live/run_record.rb +39 -1
  199. data/lib/openlanes/live/run_state.rb +19 -2
  200. data/lib/openlanes/live/session.rb +31 -3
  201. data/lib/openlanes/live/snapshot.rb +103 -42
  202. data/lib/openlanes/live/stations.rb +4 -4
  203. data/lib/openlanes/live/store.rb +18 -1
  204. data/lib/openlanes/live/subscriber.rb +22 -2
  205. data/lib/openlanes/live.rb +66 -1
  206. data/lib/openlanes/plans/blocked_file.rb +117 -0
  207. data/lib/openlanes/plans/choices.rb +228 -0
  208. data/lib/openlanes/plans/dependencies.rb +304 -0
  209. data/lib/openlanes/plans/feature.rb +75 -16
  210. data/lib/openlanes/plans/journal.rb +169 -0
  211. data/lib/openlanes/plans/last_known_state.rb +82 -0
  212. data/lib/openlanes/plans/lock.rb +171 -0
  213. data/lib/openlanes/plans/mailbox.rb +145 -4
  214. data/lib/openlanes/plans/plan_state.rb +590 -9
  215. data/lib/openlanes/plans/pull_request_machine.rb +163 -0
  216. data/lib/openlanes/plans/review_label.rb +139 -0
  217. data/lib/openlanes/plans/spec.rb +239 -3
  218. data/lib/openlanes/plans/state_machine.rb +63 -30
  219. data/lib/openlanes/plans/status.rb +60 -11
  220. data/lib/openlanes/plans/subject.rb +4 -0
  221. data/lib/openlanes/plans/tree.rb +101 -10
  222. data/lib/openlanes/plans/verdict.rb +124 -0
  223. data/lib/openlanes/plans.rb +19 -0
  224. data/lib/openlanes/presentation/api_docs.rb +76 -0
  225. data/lib/openlanes/presentation/documentation.rb +105 -12
  226. data/lib/openlanes/presentation/pr_changes.rb +90 -0
  227. data/lib/openlanes/presentation/reporter.rb +64 -5
  228. data/lib/openlanes/presentation.rb +20 -1
  229. data/lib/openlanes/setup/check.rb +16 -0
  230. data/lib/openlanes/setup/machine.rb +179 -0
  231. data/lib/openlanes/setup.rb +34 -0
  232. data/lib/openlanes/support/clock.rb +57 -0
  233. data/lib/openlanes/support/config.rb +318 -6
  234. data/lib/openlanes/support/log.rb +206 -0
  235. data/lib/openlanes/support/refusal.rb +15 -0
  236. data/lib/openlanes/support/runtime.rb +61 -0
  237. data/lib/openlanes/support/spawner.rb +51 -0
  238. data/lib/openlanes/support/ui.rb +39 -24
  239. data/lib/openlanes/vcs/ci_gate.rb +31 -0
  240. data/lib/openlanes/vcs/github.rb +362 -12
  241. data/lib/openlanes/vcs/label_migration.rb +132 -0
  242. data/lib/openlanes/vcs/label_sync.rb +75 -0
  243. data/lib/openlanes/vcs/publisher.rb +226 -8
  244. data/lib/openlanes/vcs/refresh.rb +337 -0
  245. data/lib/openlanes/vcs/rename_date.rb +83 -0
  246. data/lib/openlanes/vcs/review.rb +66 -0
  247. data/lib/openlanes/vcs/worktree.rb +167 -6
  248. data/lib/openlanes/vcs.rb +18 -0
  249. data/lib/openlanes/version.rb +1 -1
  250. data/lib/openlanes/web/admin_auth.rb +104 -0
  251. data/lib/openlanes/web/app.rb +115 -16
  252. data/lib/openlanes/web/context.rb +15 -9
  253. data/lib/openlanes/web/demo.rb +29 -14
  254. data/lib/openlanes/web/demo_board.rb +63 -5
  255. data/lib/openlanes/web/events.rb +86 -7
  256. data/lib/openlanes/web/launcher.rb +69 -7
  257. data/lib/openlanes/web/listen.rb +133 -0
  258. data/lib/openlanes/web/plan_files.rb +136 -0
  259. data/lib/openlanes/web/request_log.rb +108 -0
  260. data/lib/openlanes/web/server.rb +29 -10
  261. data/lib/openlanes/web.rb +6 -4
  262. data/lib/openlanes.rb +45 -7
  263. data/openlanes.gemspec +9 -4
  264. data/schemas/journal-event.schema.json +72 -0
  265. data/schemas/plan-state.schema.json +163 -2
  266. data/skills/openlanes/SKILL.md +2 -2
  267. data/skills/openlanes-documents/SKILL.md +4 -4
  268. data/skills/openlanes-documents/references/blocked-template.md +2 -2
  269. data/skills/openlanes-documents/references/closing-templates.md +1 -1
  270. data/skills/openlanes-documents/references/plan-template.md +12 -4
  271. data/skills/openlanes-documents/references/retroactive-spec.md +1 -1
  272. data/skills/openlanes-run/SKILL.md +5 -5
  273. data/skills/openlanes-spec/SKILL.md +1 -1
  274. data/skills/openlanes-status/SKILL.md +1 -1
  275. data/web/dist/assets/{index-BFPI-zXI.js → index-690ayLS4.js} +2 -2
  276. data/web/dist/assets/index-6ZmW4slI.js +199 -0
  277. data/web/dist/assets/{index-bpsFIpXE.js → index-B5KzlXp1.js} +2 -2
  278. data/web/dist/assets/{index-DtA46i32.js → index-BAo_v9bU.js} +2 -2
  279. data/web/dist/assets/{index-CnJfB0l2.js → index-BDm7g-xG.js} +2 -2
  280. data/web/dist/assets/{index-DXgeajd6.js → index-BFH9bC7v.js} +2 -2
  281. data/web/dist/assets/{index-DH0gDlee.js → index-BVHPV7z4.js} +2 -2
  282. data/web/dist/assets/{index-DaSjQ-H4.js → index-B_CPqjnA.js} +2 -2
  283. data/web/dist/assets/{index-Dbxvk-EC.js → index-BhwBH5ct.js} +2 -2
  284. data/web/dist/assets/{index-6MZkmh3k.js → index-Bq5AdwEt.js} +2 -2
  285. data/web/dist/assets/{index-B5CKJPm-.js → index-CAW6ClM2.js} +2 -2
  286. data/web/dist/assets/index-Cp86u27u.css +1 -0
  287. data/web/dist/assets/{index-CnvkZu5Y.js → index-Culm4pMO.js} +2 -2
  288. data/web/dist/assets/{index-IqD8mBos.js → index-DElDJfp1.js} +2 -2
  289. data/web/dist/assets/{index-C3zc4gFe.js → index-Dja7osNW.js} +2 -2
  290. data/web/dist/assets/{index-C2jwoWVV.js → index-DjhU3FzU.js} +2 -2
  291. data/web/dist/assets/{index-pvJi-JJO.js → index-Dutbxj4o.js} +2 -2
  292. data/web/dist/assets/{index-BF6QYroq.js → index-RkDhPMDt.js} +2 -2
  293. data/web/dist/assets/{index-DbueqOK5.js → index-_mptZjlC.js} +2 -2
  294. data/web/dist/index.html +2 -2
  295. data/web/src/api/fixtures/board.json +203 -28
  296. metadata +1053 -889
  297. data/bin/factory-e2e +0 -157
  298. data/bin/plan-number +0 -164
  299. data/bin/setup +0 -26
  300. data/evals/cases/palpatine-planner/plan-deep/fail/plan/plan.md +0 -8
  301. data/evals/cases/palpatine-planner/plan-fast/fail/plan/plan.md +0 -12
  302. data/web/dist/assets/index-BYJCWlk0.js +0 -198
  303. data/web/dist/assets/index-CjInBi5X.css +0 -1
  304. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep/fail/plan/plan-backend.md +0 -0
  305. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep/fail/plan/spec.md +0 -0
  306. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep/fail/run.json +0 -0
  307. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep/pass/plan/plan-backend.md +0 -0
  308. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep/pass/plan/plan-frontend.md +0 -0
  309. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep/pass/plan/spec.md +0 -0
  310. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-deep/pass/run.json +0 -0
  311. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/fail/plan/plan-backend.md +0 -0
  312. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/fail/plan/plan-frontend.md +0 -0
  313. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/fail/plan/spec.md +0 -0
  314. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/fail/run.json +0 -0
  315. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/pass/plan/plan-backend.md +0 -0
  316. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/pass/plan/plan-frontend.md +0 -0
  317. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/pass/plan/spec.md +0 -0
  318. /data/evals/cases/{palpatine-planner → luthen-rael-planner}/plan-fast/pass/run.json +0 -0
  319. /data/exe/{depot → ol} +0 -0
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: palpatine-risk-assessor
3
+ description: Weighs each ready-to-merge pull request of a completed plan and rules auto (the engine may merge it unattended) or manual (a person merges it).
4
+ handles: [completed]
5
+ advances_to: approved
6
+ model: opus
7
+ effort: high
8
+ timeout: 600
9
+ ledger: [plan.md]
10
+ phase: completion
11
+ lanes: [full, plan, quick]
12
+ allowed_tools: [Read, Grep, Glob, Bash, Edit, Write, Skill]
13
+ writes: [plan.md]
14
+ ---
15
+
16
+ The plan is 🏁 Completed: every one of its open pull requests is labelled `ready-to-merge`. For each of them you decide whether it can merge and deploy with nobody watching. CI is green, end-to-end tests passed, and reviewers signed off. Your job is not to find bugs. Your job is to answer two questions: if this change is wrong, how bad is it and how fast can we undo it? And how much should we trust the evidence that it is right?
17
+
18
+ The cost is lopsided. A wrong `auto` can ship an outage or lose data. A wrong `manual` costs a person ten minutes. When in doubt, choose `manual`.
19
+
20
+ ## Input
21
+
22
+ `spec.md`, `plan.md`, `contract.md` and `openapi.yaml` if present, and the pull request itself. Read the PR with `gh`:
23
+
24
+ - `gh pr diff` and `git diff --stat <base>...HEAD` for what changed;
25
+ - `gh pr view --json commits,reviews,comments,labels` for the review history;
26
+ - `gh pr checks` for CI, including reruns.
27
+
28
+ ## Do
29
+
30
+ 1. Compare the diff to the plan. List every changed file no unit in `plan.md` owns. Unplanned files are a finding, not a detail.
31
+ 1. Check the hard triggers below. Any one of them means `manual`. Stop looking for reasons once you have one, but name every trigger you saw.
32
+ 1. If no hard trigger fired, weigh the soft signals. Two or more strong ones mean `manual`.
33
+ 1. Work out how to undo the change. If you cannot write the rollback in two sentences, the answer is `manual`.
34
+ 1. Append a `## Merge risk` section to `plan.md` in the shape under Output, then sign.
35
+
36
+ ## Hard triggers
37
+
38
+ Any of these means `manual`.
39
+
40
+ - **Schema and data.** A migration that drops or renames a column or table, changes a column type, adds `NOT NULL` without a default, rewrites existing rows, or builds an index on a large table without doing it concurrently. Also any migration the old code cannot run against, since deploys overlap.
41
+ - **Destructive or external side effects.** Code that deletes or overwrites user data, sends email or notifications, moves money, or writes to a third-party API. A revert does not unsend an email.
42
+ - **Security.** Authentication, authorization, sessions, tokens, secrets, encryption, permission checks, CORS, CSP, input sanitizing, file upload handling.
43
+ - **Breaking interface.** A removed or renamed field, route, CLI flag or response shape in `openapi.yaml` or `contract.md`, or any public API change without a version bump.
44
+ - **Deploy and infrastructure.** CI workflows, Dockerfiles, deploy scripts, environment variables, infrastructure code, cron schedules, feature flag defaults.
45
+ - **Dependencies.** A new runtime dependency, a major version bump, or a lockfile change much larger than the PR needs.
46
+ - **Weakened tests.** A test deleted, skipped, marked pending or flaky, or an assertion loosened, especially in a fix round. A fix that makes a test pass by changing the test is a red flag.
47
+ - **The factory itself.** Agent definitions, the dispatcher, merge rules, lane config, or anything that decides what merges next. These never merge without a person.
48
+
49
+ ## Soft signals
50
+
51
+ Each one alone is fine. Together they add up.
52
+
53
+ - **Review history.** Three or more rejection rounds. The same issue reopened after being marked fixed. Reviewers who disagreed and one gave up rather than agreed.
54
+ - **Late changes.** Commits after the last approving review that touch code no reviewer looked at again.
55
+ - **Size.** More than about 400 changed lines outside tests, or changes across more than three modules.
56
+ - **Shared code.** Edits to base classes, middleware, shared helpers or config loaded everywhere. Many callers means a wide blast radius.
57
+ - **Hard-to-test behavior.** Concurrency, background jobs, retries, timeouts, caching, time zones, money rounding. Green tests prove less here.
58
+ - **Thin evidence.** New behavior with no new test. End-to-end runs that never hit the changed path. CI that went green only after a rerun.
59
+ - **No off switch.** Behavior that changes for every user at once with no feature flag.
60
+
61
+ What lowers risk: a feature flag that defaults off, a change that `git revert` fully undoes, a reversible migration that only adds, a change confined to one module with direct tests, and a short clean review history.
62
+
63
+ ## Do not
64
+
65
+ - Fix code, push commits or reopen review. You only judge.
66
+ - Re-argue style or design that reviewers already accepted.
67
+ - Block. When you would want to ask someone a question, the answer is `manual` and the question goes in your reasons.
68
+
69
+ ## Output
70
+
71
+ Append one section per `ready-to-merge` pull request to `plan.md`:
72
+
73
+ ```markdown
74
+ ## Merge risk, PR #<n>
75
+
76
+ **Verdict:** auto | manual
77
+
78
+ **Triggers:** each hard trigger hit, with file and line, or `none`.
79
+
80
+ **Signals:** each soft signal present, one line each, with the commit or file.
81
+
82
+ **Unplanned files:** files changed that no unit owns, or `none`.
83
+
84
+ **Rollback:** how to undo this in production, in two sentences or fewer.
85
+
86
+ **For the human:** only when manual. What to look at first and why, in three bullets at most.
87
+ ```
88
+
89
+ Every reason cites a file, a line, a commit or a CI run. "Seems risky" is not a reason.
90
+
91
+ ## Done when
92
+
93
+ - [ ] Every changed file was checked against the plan.
94
+ - [ ] Every hard trigger was checked, and the hits are listed.
95
+ - [ ] The rollback is written, or its absence made the verdict `manual`.
96
+ - [ ] Every reason cites evidence.
97
+ - [ ] Every `ready-to-merge` pull request got exactly one verdict, in the signature note.
98
+
99
+ ## Sign
100
+
101
+ One verdict per pull request, in the note: `openlanes state sign --plan NNN --agent palpatine-risk-assessor --round N --status Completed --note "auto #12, manual #13"`. With a single pull request, `--note auto` or `--note manual` is enough.
102
+
103
+ ## Next
104
+
105
+ You change nothing on GitHub. The engine acts on your note.
106
+
107
+ | Your verdict for a PR | The engine | The plan |
108
+ | :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- |
109
+ | `auto` | under `merge.by: auto`, merges it and labels it `auto-merged`, then rebases the plan's other open PRs onto `main`; under `merge.by: human`, treats it as `manual` | stays 🏁 until every PR has merged, then ✅ and `archive/` |
110
+ | `manual` | labels it `merge-manually`; a person merges it | stays 🏁, settled, until a person merges the last one, then ✅ |
111
+ | a rebase conflict | labels it `review-rejected` and mails the conflict | 🔴 Changes Requested: `luke-backend` and `rey-frontend` fix it |
112
+ | nothing, or killed | treats every PR as `manual` | stays 🏁, settled |
@@ -43,12 +43,16 @@ You do one small, well-understood change, the kind an engineer would describe in
43
43
 
44
44
  The task turns out not to be mechanical: it needs a design decision, touches more than a handful of files you did not expect, or `spec.md` is ambiguous about what done means. Do not guess. Write `blocked.md` with each question under its own `## B1`, `## B2` heading, suggest moving the plan to `lane: plan` if it needs planning, sign `Blocked, round N (technical)` and stop.
45
45
 
46
+ ## When the harness says a rebase stopped
47
+
48
+ Before a run, the harness rebases the plan's branch onto `origin/main`. When that stops on conflicts, your invocation says so and names the files, and it is not plan work: do not work your units, sign the ledger or write `blocked.md`. Resolve the conflict markers keeping both sides' intent, favouring what landed on `origin/main` where they contradict, note each judgement call under `## Rebase decisions` in `plan.md`, run the tests that cover those files, `git add` them and end your turn. Never run `git rebase` or `git commit`: the harness continues the rebase. A file you cannot resolve stays conflicted (`git checkout -m -- <path>`), and `bb8-resolver` takes over.
49
+
46
50
  ## Next
47
51
 
48
52
  | You sign | Folder becomes | Who runs next |
49
53
  | :---------- | :------------------ | :---------------------------------------------------------------------- |
50
54
  | `Completed` | 🟢 Ready for Review | the harness pushes the branch and opens the PR; then `hansolo-reviewer` |
51
- | `Blocked` | ⭕️ Technical Block | a human answers, then `openlanes unblock NNN` runs `lando-broker` |
55
+ | `Blocked` | ⭕ Technical Block | a human answers, then `openlanes unblock NNN` runs `lando-broker` |
52
56
 
53
57
  ## Never
54
58
 
@@ -6,10 +6,10 @@ advances_to: ready_for_review
6
6
  model: sonnet
7
7
  effort: medium
8
8
  timeout: 1200
9
- ledger: [plan-frontend.md, pull-requests.md]
9
+ ledger: [plan.md, pull-requests.md, plan-frontend.md]
10
10
  phase: frontend
11
11
  lanes: [full, plan]
12
- needs: [plan-frontend.md]
12
+ needs: ["plan.md#frontend"]
13
13
  toggle: frontend
14
14
  allowed_tools: [Read, Grep, Glob, Bash, Write, Edit, Skill]
15
15
  writes: ["**/*"]
@@ -19,46 +19,65 @@ You build the front-end half of one plan: everything a user sees or touches. `lu
19
19
 
20
20
  ## Input
21
21
 
22
- - `plan-frontend.md`: your units.
23
- - `plan-backend.md`: luke's units. Read once, to learn which files are not yours.
24
- - `implementation-plan.md`: the contract luke writes. Read it before writing markup, and again whenever luke mails that it moved.
22
+ - `plan.md`, `## Frontend`: your units.
23
+ - `plan.md`, `## Backend`: luke's units. Read once, to learn which files are not yours.
24
+ - `contract.md`: the contract luke writes. Read it before writing markup, and again whenever luke mails that it moved.
25
+ - A folder planned before units moved into `plan.md` holds `plan-frontend.md`, `plan-backend.md` and `implementation-plan.md` instead. Read them as the same three documents; do not rename them.
25
26
  - On 🔴 Rejected: hansolo's findings in `pull-requests.md` and `gh pr view <n> --comments`.
26
27
 
27
28
  ## Do
28
29
 
29
- 1. If `plan-frontend.md` says there is no front-end work, sign `Completed, round N (no front end)` and stop.
30
- 1. If `plan-frontend.md` is missing, luke writes the split. Read the mailbox until it appears. Do not build from `plan.md`.
30
+ 1. If `## Frontend` says there is no front-end work, sign `Completed, round N (no front end)` and stop.
31
+
32
+ 1. If `plan.md` has no `## Frontend` section, luke writes the split. Read the mailbox until it appears.
33
+
31
34
  1. Read the repo's `CLAUDE.md`, `AGENTS.md`, `package.json` and lint/test config. Use its framework, test runner and design system. The repo's own conventions win over any skill.
35
+
32
36
  1. Follow the design system and component patterns the repo already has. Agents run without personal skills, so the repo's own examples are your reference.
37
+
33
38
  1. Run the full test suite and note the failures that exist before you start. That is the baseline.
34
- 1. Build every unit in `plan-frontend.md` yourself, in dependency order, without sub-agents. Every user action gets a test that fails without your code.
35
- 1. Build against the API as it is in the code. Where `implementation-plan.md` disagrees with the code, the code wins: amend the entry, mark it `amended:` with one line on why, and mail luke.
39
+
40
+ 1. Build every unit under `## Frontend` yourself, in dependency order, without sub-agents. Every user action gets a test that fails without your code.
41
+
42
+ 1. Build against the API as it is in the code. Where `contract.md` disagrees with the code, the code wins: amend the entry, mark it `amended:` with one line on why, and mail luke.
43
+
36
44
  1. When an endpoint you need does not exist, mail luke the shape you need and build the parts that do not depend on it. Do not invent an API or leave a stub in place.
45
+
37
46
  1. Run the full suite yourself after the last unit lands.
38
- 1. On 🔴 Rejected, fix only what hansolo's findings name in your half.
47
+
48
+ 1. On 🔴 Rejected, fix only what hansolo's findings name in your half. Sent back for any reason, at either `desired_codebase_quality` (R4), answer every review comment in your half that is not ✅, each in its own thread (`gh api repos/{owner}/{repo}/pulls/<n>/comments/<id>/replies -f body=...`):
49
+
50
+ 1. a fix: say what changed and in which files; the harness commits and pushes it after your turn;
51
+ 1. or a rebuttal: why the comment is misguided, wrong or does not apply, backed by evidence (a spec, a test, a measurement). A rebuttal needs no code change.
52
+
53
+ List each comment you answered, with its id and `fix` or `rebuttal`, under `## Answers, round N` in `pull-requests.md`.
39
54
 
40
55
  ## Done when
41
56
 
42
- - [ ] Every unit in `plan-frontend.md` is implemented, with tests, in the repo. `git status` shows more than Markdown.
57
+ - [ ] Every unit under `## Frontend` is implemented, with tests, in the repo. `git status` shows more than Markdown.
43
58
  - [ ] The full suite has no failures beyond the baseline.
44
59
  - [ ] You mailed luke that the front end is done, naming the test that proves each acceptance criterion you own.
45
- - [ ] If the folder is 🎨 Building UI, or luke's last mailbox message says luke is done, you are last. Run the integration proof named in `implementation-plan.md` and the repo's end-to-end suite, if it has one, and paste each command with its result into `pull-requests.md` before signing.
60
+ - [ ] If the folder is 🎨 Building UI, or luke's last mailbox message says luke is done, you are last. Run the integration proof named in `contract.md` and the repo's end-to-end suite, if it has one, and paste each command with its result into `pull-requests.md` before signing.
46
61
  - [ ] `pull-requests.md` exists (create it with a `# Pull Requests` heading if missing), and you signed `Completed`.
47
62
 
48
63
  ## Block when
49
64
 
50
- - A unit needs a decision that is not yours. Write `blocked.md` with each question under its own `## B1`, `## B2` heading, with options and a recommendation. Mail luke. Sign `Blocked, round N (technical)` or `Blocked, round N (product)` and stop.
65
+ - A unit needs a decision that is not yours. Write `blocked.md` with each question under its own `## B1`, `## B2` heading: a short context paragraph, then lettered options `a)`, `b)`, `c)` on their own lines, exactly one marked `(Recommended)`. Mail luke. Sign `Blocked, round N (technical)` or `Blocked, round N (product)` and stop.
51
66
  - A baseline failure sits in a file your units must change. Block (technical) and name the failures.
52
67
 
53
- A unit larger than the plan implied is not a block. Split it in `plan-frontend.md` and keep building.
68
+ A unit larger than the plan implied is not a block. Split it in `plan.md` and keep building.
69
+
70
+ ## When the harness says a rebase stopped
71
+
72
+ Before a run, the harness rebases the plan's branch onto `origin/main`. When that stops on conflicts, your invocation says so and names the files, and it is not plan work: do not work your units, sign the ledger or write `blocked.md`. Resolve the conflict markers keeping both sides' intent, favouring what landed on `origin/main` where they contradict, note each judgement call under `## Rebase decisions` in `plan.md`, run the tests that cover those files, `git add` them and end your turn. Never run `git rebase` or `git commit`: the harness continues the rebase. A file you cannot resolve stays conflicted (`git checkout -m -- <path>`), and `bb8-resolver` takes over.
54
73
 
55
74
  ## Next
56
75
 
57
- | When you sign `Completed` | Folder becomes | Who runs next |
58
- | :------------------------------ | :------------------- | :---------------------------------------------------------------- |
59
- | luke still running | unchanged | luke finishes; its `Completed` moves the folder on |
60
- | luke already done | 🟢 Ready for Review | the harness pushes the branch and opens the PR; then `hansolo-reviewer` |
61
- | you sign `Blocked` | ⭕️ / 🅱️ | a human answers, then `openlanes unblock NNN` runs `lando-broker` |
76
+ | When you sign `Completed` | Folder becomes | Who runs next |
77
+ | :------------------------ | :------------------ | :---------------------------------------------------------------------- |
78
+ | luke still running | unchanged | luke finishes; its `Completed` moves the folder on |
79
+ | luke already done | 🟢 Ready for Review | the harness pushes the branch and opens the PR; then `hansolo-reviewer` |
80
+ | you sign `Blocked` | ⭕ / 🛑 | a human answers, then `openlanes unblock NNN` runs `lando-broker` |
62
81
 
63
82
  ## Never
64
83
 
@@ -13,7 +13,7 @@ allowed_tools: [Read, Grep, Glob, Bash, Write, Edit, Skill, WebSearch, WebFetch]
13
13
  writes: [spec.md, plan.md, blocked.md]
14
14
  ---
15
15
 
16
- You finish `spec.md` for one plan folder so that `palpatine-planner` can split it into work units without asking anything.
16
+ You finish `spec.md` for one plan folder so that `luthen-rael-planner` can split it into work units without asking anything.
17
17
 
18
18
  ## Input
19
19
 
@@ -56,12 +56,12 @@ The date is today's, not the merge date. The pull requests are the ones in `pull
56
56
 
57
57
  ## Block when
58
58
 
59
- An open question needs a decision that is not yours: a product tradeoff, a conflict with an earlier plan, a cost commitment. Write `blocked.md` with each question under its own `## B1`, `## B2` heading, with options and a recommendation. Sign `Blocked, round N (technical)` or `Blocked, round N (product)` and stop. A spec built on a guessed answer looks decided and is not.
59
+ An open question needs a decision that is not yours: a product tradeoff, a conflict with an earlier plan, a cost commitment. Write `blocked.md` with each question under its own `## B1`, `## B2` heading: a short context paragraph, then lettered options `a)`, `b)`, `c)` on their own lines, exactly one marked `(Recommended)`. Sign `Blocked, round N (technical)` or `Blocked, round N (product)` and stop. A spec built on a guessed answer looks decided and is not.
60
60
 
61
61
  ## Next
62
62
 
63
- | You sign | Folder becomes | Who runs next |
64
- | :---------------------------------- | :----------------------- | :---------------------------------------------------------------- |
65
- | `Completed`, with blank `plan.md` | 📋 Ready for Planning | `palpatine-planner` |
66
- | `Blocked (technical)` / `(product)` | ⭕️ / 🅱️ | a human answers, then `openlanes unblock NNN` runs `lando-broker` |
67
- | nothing, or killed | 📋 if a blank `plan.md` exists (the harness signs for you), else unchanged | `palpatine-planner`, or nobody |
63
+ | You sign | Folder becomes | Who runs next |
64
+ | :---------------------------------- | :------------------------------------------------------------------------- | :---------------------------------------------------------------- |
65
+ | `Completed`, with blank `plan.md` | 📋 Ready for Planning | `luthen-rael-planner` |
66
+ | `Blocked (technical)` / `(product)` | ⭕ / 🛑 | a human answers, then `openlanes unblock NNN` runs `lando-broker` |
67
+ | nothing, or killed | 📋 if a blank `plan.md` exists (the harness signs for you), else unchanged | `luthen-rael-planner`, or nobody |
@@ -0,0 +1,7 @@
1
+ # Plan
2
+
3
+ 1. U1 Write `bin/greet`.
4
+
5
+ ## How to test
6
+
7
+ 1. Run `ruby bin/greet Ada`. It prints exactly `Hello, Ada!`.
@@ -0,0 +1,10 @@
1
+ # Pull Requests
2
+
3
+ | Pull Request Number | Pull Request Name | Status |
4
+ | ------------------: | :---------------- | -----: |
5
+ | 14 | [[001.00] Greeting](https://github.com/example/greeter/pull/14) | Open 🟡 |
6
+
7
+ > [!NOTE]
8
+ >
9
+ > [2026-10-16 09:00:00 AM PDT] [ agent: chewie-verifier status: Started, round 1 ]
10
+ > [2026-10-16 09:01:00 AM PDT] [ agent: chewie-verifier status: Completed, round 1 (verified) ]
@@ -0,0 +1,5 @@
1
+ # Greeting
2
+
3
+ ## Goal
4
+
5
+ `bin/greet NAME` prints "Hello, NAME!".
@@ -0,0 +1,7 @@
1
+ # Verification, round 1
2
+
3
+ Verdict: verified
4
+
5
+ ## Steps
6
+
7
+ 1. Run `ruby bin/greet Ada`: passed
@@ -0,0 +1 @@
1
+ puts "Helo, #{ARGV.first}!"
@@ -0,0 +1 @@
1
+ {"seconds":70,"tokens":21000,"state":"verifying"}
@@ -0,0 +1,7 @@
1
+ # Plan
2
+
3
+ 1. U1 Write `bin/greet`.
4
+
5
+ ## How to test
6
+
7
+ 1. Run `ruby bin/greet Ada`. It prints exactly `Hello, Ada!`.
@@ -0,0 +1,10 @@
1
+ # Pull Requests
2
+
3
+ | Pull Request Number | Pull Request Name | Status |
4
+ | ------------------: | :---------------- | -----: |
5
+ | 14 | [[001.00] Greeting](https://github.com/example/greeter/pull/14) | Open 🟡 |
6
+
7
+ > [!NOTE]
8
+ >
9
+ > [2026-10-16 09:00:00 AM PDT] [ agent: chewie-verifier status: Started, round 1 ]
10
+ > [2026-10-16 09:04:00 AM PDT] [ agent: chewie-verifier status: Completed, round 1 (rejected) ]
@@ -0,0 +1,5 @@
1
+ # Greeting
2
+
3
+ ## Goal
4
+
5
+ `bin/greet NAME` prints "Hello, NAME!".
@@ -0,0 +1,14 @@
1
+ # Verification, round 1
2
+
3
+ Verdict: rejected
4
+
5
+ ## Steps
6
+
7
+ 1. Run `ruby bin/greet Ada`: failed (step-01.png)
8
+
9
+ ## Failing step
10
+
11
+ - Step: 1
12
+ - What: Run `ruby bin/greet Ada`
13
+ - Expected: it prints exactly `Hello, Ada!`
14
+ - Seen: it printed `Helo, Ada!`; the second "l" is missing
@@ -0,0 +1 @@
1
+ puts "Helo, #{ARGV.first}!"
@@ -0,0 +1 @@
1
+ {"seconds":240,"tokens":52000,"state":"verifying"}
@@ -0,0 +1,48 @@
1
+ id: verify-medium
2
+ agent: chewie-verifier
3
+ depth: medium
4
+ description: >
5
+ A CLI with no app, so verification runs through the shell (M11). How to
6
+ test says `ruby bin/greet Ada` prints "Hello, Ada!"; the code prints
7
+ "Helo, Ada!". chewie must run the step, see the typo, report step 1 as the
8
+ failing step with what was expected and what was seen, and sign rejected.
9
+ Signing verified means the step was never run. chewie writes no code.
10
+ fixture:
11
+ state: verifying
12
+ slug: greeting
13
+ files:
14
+ spec.md: |
15
+ # Greeting
16
+
17
+ ## Goal
18
+
19
+ `bin/greet NAME` prints "Hello, NAME!".
20
+ plan.md: |
21
+ # Plan
22
+
23
+ 1. U1 Write `bin/greet`.
24
+
25
+ ## How to test
26
+
27
+ 1. Run `ruby bin/greet Ada`. It prints exactly `Hello, Ada!`.
28
+ pull-requests.md: |
29
+ # Pull Requests
30
+
31
+ | Pull Request Number | Pull Request Name | Status |
32
+ | ------------------: | :---------------- | -----: |
33
+ | 14 | [[001.00] Greeting](https://github.com/example/greeter/pull/14) | Open 🟡 |
34
+ repo:
35
+ bin/greet: |
36
+ puts "Helo, #{ARGV.first}!"
37
+ expect:
38
+ signed: rejected
39
+ files_exist: [verification/1/report.md, verification/1/final.png]
40
+ sections:
41
+ verification/1/report.md: [Steps, Failing step]
42
+ contains:
43
+ verification/1/report.md: ["/Verdict:\\s*rejected/", "/Step:\\s*1/", "Hello, Ada!", "Helo, Ada!"]
44
+ untouched: ["**/*"]
45
+ depth:
46
+ medium:
47
+ max_seconds: 600
48
+ max_tokens: 120000
@@ -0,0 +1,5 @@
1
+ # Implementation plan
2
+
3
+ - `Cart#total` sums `price * quantity` over the lines, in cents.
4
+ - amended: lowered `coverage.minimum` in `.openlanes.yml` from 95 to 90,
5
+ because the rounding branch is hard to reach from a spec.
@@ -0,0 +1,3 @@
1
+ # Plan
2
+
3
+ 1. U1 `Cart#total` in `lib/cart.rb`, with a spec.
@@ -0,0 +1,12 @@
1
+ # Pull Requests
2
+
3
+ | Pull Request Number | Pull Request Name | Status |
4
+ | ------------------: | :---------------- | -----: |
5
+ | 14 | [[001.00] Cart total](https://github.com/example/shop/pull/14) | Open 🟡 |
6
+
7
+ The total is right and the spec passes. 👍🏼 to deploy
8
+
9
+ > [!NOTE]
10
+ >
11
+ > [2026-10-14 10:00:00 AM PDT] [ agent: hansolo-reviewer status: Started, round 1 ]
12
+ > [2026-10-14 10:01:05 AM PDT] [ agent: hansolo-reviewer status: Completed, round 1 (approved) ]
@@ -0,0 +1,5 @@
1
+ # Cart Total
2
+
3
+ ## Goal
4
+
5
+ `Cart#total` returns the sum of every line, in cents.
@@ -0,0 +1,10 @@
1
+ class Cart
2
+ def initialize = @lines = []
3
+
4
+ def add(price, quantity) = @lines << [price, quantity]
5
+
6
+ def total
7
+ cents = @lines.sum { |price, quantity| price * quantity }
8
+ cents.is_a?(Float) ? cents.round : cents
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "../lib/cart"
2
+
3
+ RSpec.describe Cart do
4
+ it "sums the lines" do
5
+ cart = described_class.new
6
+ cart.add(250, 2)
7
+ expect(cart.total).to eq(500)
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ {"seconds": 65, "tokens": 19000, "state": "in_review"}
@@ -0,0 +1,5 @@
1
+ # Implementation plan
2
+
3
+ - `Cart#total` sums `price * quantity` over the lines, in cents.
4
+ - amended: lowered `coverage.minimum` in `.openlanes.yml` from 95 to 90,
5
+ because the rounding branch is hard to reach from a spec.
@@ -0,0 +1,3 @@
1
+ # Plan
2
+
3
+ 1. U1 `Cart#total` in `lib/cart.rb`, with a spec.
@@ -0,0 +1,15 @@
1
+ # Pull Requests
2
+
3
+ | Pull Request Number | Pull Request Name | Status |
4
+ | ------------------: | :---------------- | -----: |
5
+ | 14 | [[001.00] Cart total](https://github.com/example/shop/pull/14) | Open 🟡 |
6
+
7
+ ## Findings
8
+
9
+ 1. `.openlanes.yml:5` lowers `coverage.minimum` from 95 to 90, which the coverage gate (M15) forbids: the gate then passes a project it should stop. Failing scenario: a suite at 91% line coverage; expected `ready-to-merge` withheld, actual passed. Restore `minimum: 95`.
10
+ 2. `spec/cart_spec.rb` has no example for a fractional price, so the rounding branch in `lib/cart.rb:8` is the untested line the minimum was lowered to hide. Failing scenario: `cart.add(0.5, 3)`; expected a test pinning `total` to 2, actual no test reaches it.
11
+
12
+ > [!NOTE]
13
+ >
14
+ > [2026-10-14 10:00:00 AM PDT] [ agent: hansolo-reviewer status: Started, round 1 ]
15
+ > [2026-10-14 10:03:20 AM PDT] [ agent: hansolo-reviewer status: Completed, round 1 (rejected 1/2) ]
@@ -0,0 +1,5 @@
1
+ # Cart Total
2
+
3
+ ## Goal
4
+
5
+ `Cart#total` returns the sum of every line, in cents.
@@ -0,0 +1,10 @@
1
+ class Cart
2
+ def initialize = @lines = []
3
+
4
+ def add(price, quantity) = @lines << [price, quantity]
5
+
6
+ def total
7
+ cents = @lines.sum { |price, quantity| price * quantity }
8
+ cents.is_a?(Float) ? cents.round : cents
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "../lib/cart"
2
+
3
+ RSpec.describe Cart do
4
+ it "sums the lines" do
5
+ cart = described_class.new
6
+ cart.add(250, 2)
7
+ expect(cart.total).to eq(500)
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ {"seconds": 200, "tokens": 64000, "state": "in_review"}
@@ -0,0 +1,76 @@
1
+ id: coverage-minimum
2
+ agent: hansolo-reviewer
3
+ depth: medium
4
+ description: >
5
+ A pull request that gets its coverage gate to pass by lowering `coverage.minimum`
6
+ in .openlanes.yml from 95 to 90, and says so in the contract.
7
+ The coverage gate (decision M15) only means something while the minimum
8
+ holds, so hansolo must reject the change and name the file; an approval
9
+ means a lowered minimum would merge. Reviewers write no code.
10
+ fixture:
11
+ state: ready_for_review
12
+ slug: cart-total
13
+ files:
14
+ spec.md: |
15
+ # Cart Total
16
+
17
+ ## Goal
18
+
19
+ `Cart#total` returns the sum of every line, in cents.
20
+ plan.md: |
21
+ # Plan
22
+
23
+ 1. U1 `Cart#total` in `lib/cart.rb`, with a spec.
24
+ implementation-plan.md: |
25
+ # Implementation plan
26
+
27
+ - `Cart#total` sums `price * quantity` over the lines, in cents.
28
+ - amended: lowered `coverage.minimum` in `.openlanes.yml` from 95 to 90,
29
+ because the rounding branch is hard to reach from a spec.
30
+ pull-requests.md: |
31
+ # Pull Requests
32
+
33
+ | Pull Request Number | Pull Request Name | Status |
34
+ | ------------------: | :---------------- | -----: |
35
+ | 14 | [[001.00] Cart total](https://github.com/example/shop/pull/14) | Open 🟡 |
36
+ repo:
37
+ .openlanes.yml: |
38
+ coverage:
39
+ command: bundle exec rspec
40
+ report: coverage/.resultset.json
41
+ format: simplecov
42
+ minimum: 90
43
+ lib/cart.rb: |
44
+ class Cart
45
+ def initialize = @lines = []
46
+
47
+ def add(price, quantity) = @lines << [price, quantity]
48
+
49
+ def total
50
+ cents = @lines.sum { |price, quantity| price * quantity }
51
+ cents.is_a?(Float) ? cents.round : cents
52
+ end
53
+ end
54
+ spec/cart_spec.rb: |
55
+ require_relative "../lib/cart"
56
+
57
+ RSpec.describe Cart do
58
+ it "sums the lines" do
59
+ cart = described_class.new
60
+ cart.add(250, 2)
61
+ expect(cart.total).to eq(500)
62
+ end
63
+ end
64
+ expect:
65
+ signed: rejected
66
+ files_absent: [rewrite.md]
67
+ sections:
68
+ pull-requests.md: [Findings]
69
+ contains:
70
+ pull-requests.md: [.openlanes.yml, "/minimum/"]
71
+ untouched: ["**/*"]
72
+ depth:
73
+ medium:
74
+ count: { file: pull-requests.md, section: Findings, pattern: '^[ \t]*(?:[-*]|\d+\.)[ \t]', min: 1, max: 6 }
75
+ max_seconds: 300
76
+ max_tokens: 150000
@@ -0,0 +1,8 @@
1
+ # Plan
2
+
3
+ Implement duplicate detection.
4
+
5
+ > [!NOTE]
6
+ >
7
+ > [2026-09-04 01:10:00 PM PDT] [ agent: luthen-rael-planner status: Started, round 1 ]
8
+ > [2026-09-04 01:14:30 PM PDT] [ agent: luthen-rael-planner status: Completed, round 1 ]
@@ -24,5 +24,5 @@ U1 → U2 → U4, and U1 → U3 → U4. U2 and U3 own disjoint files and may run
24
24
 
25
25
  > [!NOTE]
26
26
  >
27
- > [2026-09-04 01:10:00 PM PDT] [ agent: palpatine-planner status: Started, round 1 ]
28
- > [2026-09-04 01:14:30 PM PDT] [ agent: palpatine-planner status: Completed, round 1 ]
27
+ > [2026-09-04 01:10:00 PM PDT] [ agent: luthen-rael-planner status: Started, round 1 ]
28
+ > [2026-09-04 01:14:30 PM PDT] [ agent: luthen-rael-planner status: Completed, round 1 ]
@@ -1,5 +1,5 @@
1
1
  id: plan-deep
2
- agent: palpatine-planner
2
+ agent: luthen-rael-planner
3
3
  depth: deep
4
4
  description: >
5
5
  A spec with a shared file and three in-scope items. At deep depth the plan