openlanes 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. checksums.yaml +7 -0
  2. data/agents/hansolo-reviewer.md +59 -0
  3. data/agents/lando-broker.md +70 -0
  4. data/agents/leah-researcher.md +60 -0
  5. data/agents/luke-backend.md +73 -0
  6. data/agents/palpatine-planner.md +61 -0
  7. data/agents/r2d2-mechanic.md +57 -0
  8. data/agents/rey-frontend.md +68 -0
  9. data/agents/yoda-writer.md +67 -0
  10. data/bin/factory-e2e +157 -0
  11. data/bin/plan-number +164 -0
  12. data/bin/setup +26 -0
  13. data/evals/cases/hansolo-reviewer/review-medium/fail/plan/plan.md +3 -0
  14. data/evals/cases/hansolo-reviewer/review-medium/fail/plan/pull-requests.md +12 -0
  15. data/evals/cases/hansolo-reviewer/review-medium/fail/plan/spec.md +5 -0
  16. data/evals/cases/hansolo-reviewer/review-medium/fail/repo/lib/cart.rb +9 -0
  17. data/evals/cases/hansolo-reviewer/review-medium/fail/repo/spec/cart_spec.rb +7 -0
  18. data/evals/cases/hansolo-reviewer/review-medium/fail/run.json +1 -0
  19. data/evals/cases/hansolo-reviewer/review-medium/pass/plan/plan.md +3 -0
  20. data/evals/cases/hansolo-reviewer/review-medium/pass/plan/pull-requests.md +15 -0
  21. data/evals/cases/hansolo-reviewer/review-medium/pass/plan/spec.md +5 -0
  22. data/evals/cases/hansolo-reviewer/review-medium/pass/repo/lib/cart.rb +9 -0
  23. data/evals/cases/hansolo-reviewer/review-medium/pass/repo/spec/cart_spec.rb +7 -0
  24. data/evals/cases/hansolo-reviewer/review-medium/pass/run.json +1 -0
  25. data/evals/cases/hansolo-reviewer/review-medium.yml +60 -0
  26. data/evals/cases/lando-broker/unblock-fast/fail/plan/blocked.md +9 -0
  27. data/evals/cases/lando-broker/unblock-fast/fail/plan/spec.md +16 -0
  28. data/evals/cases/lando-broker/unblock-fast/fail/run.json +1 -0
  29. data/evals/cases/lando-broker/unblock-fast/pass/plan/spec.md +18 -0
  30. data/evals/cases/lando-broker/unblock-fast/pass/run.json +1 -0
  31. data/evals/cases/lando-broker/unblock-fast.yml +44 -0
  32. data/evals/cases/leah-researcher/research-deep/fail/plan/spec.md +26 -0
  33. data/evals/cases/leah-researcher/research-deep/fail/run.json +1 -0
  34. data/evals/cases/leah-researcher/research-deep/pass/plan/spec.md +39 -0
  35. data/evals/cases/leah-researcher/research-deep/pass/run.json +1 -0
  36. data/evals/cases/leah-researcher/research-deep.yml +51 -0
  37. data/evals/cases/leah-researcher/research-fast/fail/plan/spec.md +27 -0
  38. data/evals/cases/leah-researcher/research-fast/fail/run.json +1 -0
  39. data/evals/cases/leah-researcher/research-fast/pass/plan/spec.md +23 -0
  40. data/evals/cases/leah-researcher/research-fast/pass/run.json +1 -0
  41. data/evals/cases/leah-researcher/research-fast.yml +55 -0
  42. data/evals/cases/luke-backend/build-medium/fail/plan/plan-backend.md +7 -0
  43. data/evals/cases/luke-backend/build-medium/fail/plan/plan-frontend.md +1 -0
  44. data/evals/cases/luke-backend/build-medium/fail/plan/plan.md +3 -0
  45. data/evals/cases/luke-backend/build-medium/fail/plan/pull-requests.md +8 -0
  46. data/evals/cases/luke-backend/build-medium/fail/plan/spec.md +8 -0
  47. data/evals/cases/luke-backend/build-medium/fail/repo/Gemfile +2 -0
  48. data/evals/cases/luke-backend/build-medium/fail/repo/lib/cart.rb +11 -0
  49. data/evals/cases/luke-backend/build-medium/fail/repo/spec/cart_spec.rb +7 -0
  50. data/evals/cases/luke-backend/build-medium/fail/run.json +1 -0
  51. data/evals/cases/luke-backend/build-medium/pass/plan/plan-backend.md +7 -0
  52. data/evals/cases/luke-backend/build-medium/pass/plan/plan-frontend.md +1 -0
  53. data/evals/cases/luke-backend/build-medium/pass/plan/plan.md +3 -0
  54. data/evals/cases/luke-backend/build-medium/pass/plan/pull-requests.md +8 -0
  55. data/evals/cases/luke-backend/build-medium/pass/plan/spec.md +8 -0
  56. data/evals/cases/luke-backend/build-medium/pass/repo/Gemfile +2 -0
  57. data/evals/cases/luke-backend/build-medium/pass/repo/lib/cart.rb +11 -0
  58. data/evals/cases/luke-backend/build-medium/pass/repo/spec/cart_spec.rb +11 -0
  59. data/evals/cases/luke-backend/build-medium/pass/run.json +1 -0
  60. data/evals/cases/luke-backend/build-medium.yml +68 -0
  61. data/evals/cases/palpatine-planner/plan-deep/fail/plan/plan-backend.md +6 -0
  62. data/evals/cases/palpatine-planner/plan-deep/fail/plan/plan.md +8 -0
  63. data/evals/cases/palpatine-planner/plan-deep/fail/plan/spec.md +14 -0
  64. data/evals/cases/palpatine-planner/plan-deep/fail/run.json +1 -0
  65. data/evals/cases/palpatine-planner/plan-deep/pass/plan/plan-backend.md +32 -0
  66. data/evals/cases/palpatine-planner/plan-deep/pass/plan/plan-frontend.md +1 -0
  67. data/evals/cases/palpatine-planner/plan-deep/pass/plan/plan.md +28 -0
  68. data/evals/cases/palpatine-planner/plan-deep/pass/plan/spec.md +14 -0
  69. data/evals/cases/palpatine-planner/plan-deep/pass/run.json +1 -0
  70. data/evals/cases/palpatine-planner/plan-deep.yml +50 -0
  71. data/evals/cases/palpatine-planner/plan-fast/fail/plan/plan-backend.md +48 -0
  72. data/evals/cases/palpatine-planner/plan-fast/fail/plan/plan-frontend.md +1 -0
  73. data/evals/cases/palpatine-planner/plan-fast/fail/plan/plan.md +12 -0
  74. data/evals/cases/palpatine-planner/plan-fast/fail/plan/spec.md +12 -0
  75. data/evals/cases/palpatine-planner/plan-fast/fail/run.json +1 -0
  76. data/evals/cases/palpatine-planner/plan-fast/pass/plan/plan-backend.md +8 -0
  77. data/evals/cases/palpatine-planner/plan-fast/pass/plan/plan-frontend.md +1 -0
  78. data/evals/cases/palpatine-planner/plan-fast/pass/plan/plan.md +12 -0
  79. data/evals/cases/palpatine-planner/plan-fast/pass/plan/spec.md +12 -0
  80. data/evals/cases/palpatine-planner/plan-fast/pass/run.json +1 -0
  81. data/evals/cases/palpatine-planner/plan-fast.yml +47 -0
  82. data/evals/cases/r2d2-mechanic/task-fast/fail/plan/plan.md +7 -0
  83. data/evals/cases/r2d2-mechanic/task-fast/fail/plan/pull-requests.md +6 -0
  84. data/evals/cases/r2d2-mechanic/task-fast/fail/plan/spec.md +6 -0
  85. data/evals/cases/r2d2-mechanic/task-fast/fail/repo/README.md +3 -0
  86. data/evals/cases/r2d2-mechanic/task-fast/fail/repo/lib/greeter/formatter.rb +12 -0
  87. data/evals/cases/r2d2-mechanic/task-fast/fail/repo/lib/greeter.rb +15 -0
  88. data/evals/cases/r2d2-mechanic/task-fast/fail/repo/spec/greeter_spec.rb +7 -0
  89. data/evals/cases/r2d2-mechanic/task-fast/fail/run.json +1 -0
  90. data/evals/cases/r2d2-mechanic/task-fast/pass/plan/plan.md +7 -0
  91. data/evals/cases/r2d2-mechanic/task-fast/pass/plan/pull-requests.md +6 -0
  92. data/evals/cases/r2d2-mechanic/task-fast/pass/plan/spec.md +6 -0
  93. data/evals/cases/r2d2-mechanic/task-fast/pass/repo/README.md +3 -0
  94. data/evals/cases/r2d2-mechanic/task-fast/pass/repo/lib/greeter.rb +3 -0
  95. data/evals/cases/r2d2-mechanic/task-fast/pass/repo/spec/greeter_spec.rb +7 -0
  96. data/evals/cases/r2d2-mechanic/task-fast/pass/run.json +1 -0
  97. data/evals/cases/r2d2-mechanic/task-fast.yml +59 -0
  98. data/evals/cases/r2d2-mechanic/task-medium/fail/plan/plan.md +7 -0
  99. data/evals/cases/r2d2-mechanic/task-medium/fail/plan/pull-requests.md +6 -0
  100. data/evals/cases/r2d2-mechanic/task-medium/fail/plan/spec.md +6 -0
  101. data/evals/cases/r2d2-mechanic/task-medium/fail/repo/Gemfile +2 -0
  102. data/evals/cases/r2d2-mechanic/task-medium/fail/repo/lib/greeter.rb +6 -0
  103. data/evals/cases/r2d2-mechanic/task-medium/fail/repo/spec/greeter_spec.rb +11 -0
  104. data/evals/cases/r2d2-mechanic/task-medium/fail/run.json +1 -0
  105. data/evals/cases/r2d2-mechanic/task-medium/pass/plan/plan.md +7 -0
  106. data/evals/cases/r2d2-mechanic/task-medium/pass/plan/pull-requests.md +6 -0
  107. data/evals/cases/r2d2-mechanic/task-medium/pass/plan/spec.md +6 -0
  108. data/evals/cases/r2d2-mechanic/task-medium/pass/repo/Gemfile +2 -0
  109. data/evals/cases/r2d2-mechanic/task-medium/pass/repo/lib/greeter.rb +6 -0
  110. data/evals/cases/r2d2-mechanic/task-medium/pass/repo/spec/greeter_spec.rb +11 -0
  111. data/evals/cases/r2d2-mechanic/task-medium/pass/run.json +1 -0
  112. data/evals/cases/r2d2-mechanic/task-medium.yml +58 -0
  113. data/evals/cases/rey-frontend/ui-medium/fail/plan/plan-frontend.md +7 -0
  114. data/evals/cases/rey-frontend/ui-medium/fail/plan/plan.md +4 -0
  115. data/evals/cases/rey-frontend/ui-medium/fail/plan/pull-requests.md +8 -0
  116. data/evals/cases/rey-frontend/ui-medium/fail/plan/spec.md +5 -0
  117. data/evals/cases/rey-frontend/ui-medium/fail/repo/lib/cart.rb +5 -0
  118. data/evals/cases/rey-frontend/ui-medium/fail/repo/web/cart_badge.js +4 -0
  119. data/evals/cases/rey-frontend/ui-medium/fail/repo/web/cart_badge.test.js +3 -0
  120. data/evals/cases/rey-frontend/ui-medium/fail/run.json +1 -0
  121. data/evals/cases/rey-frontend/ui-medium/pass/plan/plan-frontend.md +7 -0
  122. data/evals/cases/rey-frontend/ui-medium/pass/plan/plan.md +4 -0
  123. data/evals/cases/rey-frontend/ui-medium/pass/plan/pull-requests.md +8 -0
  124. data/evals/cases/rey-frontend/ui-medium/pass/plan/spec.md +5 -0
  125. data/evals/cases/rey-frontend/ui-medium/pass/repo/lib/cart.rb +3 -0
  126. data/evals/cases/rey-frontend/ui-medium/pass/repo/web/cart_badge.js +4 -0
  127. data/evals/cases/rey-frontend/ui-medium/pass/repo/web/cart_badge.test.js +3 -0
  128. data/evals/cases/rey-frontend/ui-medium/pass/run.json +1 -0
  129. data/evals/cases/rey-frontend/ui-medium.yml +55 -0
  130. data/evals/cases/yoda-writer/spec-medium/fail/plan/plan.md +5 -0
  131. data/evals/cases/yoda-writer/spec-medium/fail/plan/spec.md +45 -0
  132. data/evals/cases/yoda-writer/spec-medium/fail/run.json +1 -0
  133. data/evals/cases/yoda-writer/spec-medium/pass/plan/plan.md +0 -0
  134. data/evals/cases/yoda-writer/spec-medium/pass/plan/spec.md +63 -0
  135. data/evals/cases/yoda-writer/spec-medium/pass/run.json +1 -0
  136. data/evals/cases/yoda-writer/spec-medium.yml +40 -0
  137. data/exe/depot +1 -0
  138. data/exe/lanes +1 -0
  139. data/exe/openlanes +32 -0
  140. data/lib/openlanes/adapters/base.rb +69 -0
  141. data/lib/openlanes/adapters/claude.rb +124 -0
  142. data/lib/openlanes/adapters/codex.rb +33 -0
  143. data/lib/openlanes/adapters/model.rb +37 -0
  144. data/lib/openlanes/adapters/pi.rb +22 -0
  145. data/lib/openlanes/adapters/stream.rb +196 -0
  146. data/lib/openlanes/adapters.rb +92 -0
  147. data/lib/openlanes/agents/agent.rb +103 -0
  148. data/lib/openlanes/agents/profile.rb +57 -0
  149. data/lib/openlanes/agents/registry.rb +151 -0
  150. data/lib/openlanes/agents/roster.rb +103 -0
  151. data/lib/openlanes/agents/routing.rb +88 -0
  152. data/lib/openlanes/agents.rb +20 -0
  153. data/lib/openlanes/cli/agents/subcommands/describe.rb +66 -0
  154. data/lib/openlanes/cli/agents/subcommands/list.rb +20 -0
  155. data/lib/openlanes/cli/base.rb +263 -0
  156. data/lib/openlanes/cli/create/create.rb +354 -0
  157. data/lib/openlanes/cli/docs/docs.rb +40 -0
  158. data/lib/openlanes/cli/eval/eval.rb +110 -0
  159. data/lib/openlanes/cli/index/index.rb +40 -0
  160. data/lib/openlanes/cli/init/init.rb +145 -0
  161. data/lib/openlanes/cli/linear/linear.rb +36 -0
  162. data/lib/openlanes/cli/linear/subcommands/import.rb +174 -0
  163. data/lib/openlanes/cli/linear/subcommands/projects.rb +55 -0
  164. data/lib/openlanes/cli/list_plans/list_plans.rb +21 -0
  165. data/lib/openlanes/cli/mail/mail.rb +31 -0
  166. data/lib/openlanes/cli/mail/subcommands/read.rb +43 -0
  167. data/lib/openlanes/cli/mail/subcommands/send.rb +43 -0
  168. data/lib/openlanes/cli/resync/subcommands/dirs.rb +48 -0
  169. data/lib/openlanes/cli/resync/subcommands/prs.rb +111 -0
  170. data/lib/openlanes/cli/run/run.rb +544 -0
  171. data/lib/openlanes/cli/skills/subcommands/install.rb +92 -0
  172. data/lib/openlanes/cli/start/start.rb +110 -0
  173. data/lib/openlanes/cli/state/state.rb +26 -0
  174. data/lib/openlanes/cli/state/subcommands/show.rb +30 -0
  175. data/lib/openlanes/cli/state/subcommands/sign.rb +48 -0
  176. data/lib/openlanes/cli/states/states.rb +15 -0
  177. data/lib/openlanes/cli/unblock/unblock.rb +235 -0
  178. data/lib/openlanes/cli/version/version.rb +13 -0
  179. data/lib/openlanes/cli/web/web.rb +100 -0
  180. data/lib/openlanes/cli/worktree/worktree.rb +85 -0
  181. data/lib/openlanes/cli.rb +162 -0
  182. data/lib/openlanes/engine/board.rb +104 -0
  183. data/lib/openlanes/engine/dispatcher.rb +1297 -0
  184. data/lib/openlanes/engine/progress_log.rb +125 -0
  185. data/lib/openlanes/engine/runner.rb +224 -0
  186. data/lib/openlanes/engine/state_file.rb +190 -0
  187. data/lib/openlanes/engine/tally.rb +177 -0
  188. data/lib/openlanes/engine.rb +19 -0
  189. data/lib/openlanes/evals/case.rb +191 -0
  190. data/lib/openlanes/evals/changes.rb +67 -0
  191. data/lib/openlanes/evals/check.rb +224 -0
  192. data/lib/openlanes/evals/evidence.rb +71 -0
  193. data/lib/openlanes/evals/live.rb +140 -0
  194. data/lib/openlanes/evals/recording.rb +38 -0
  195. data/lib/openlanes/evals/run.rb +34 -0
  196. data/lib/openlanes/evals/score.rb +24 -0
  197. data/lib/openlanes/evals/scorer.rb +42 -0
  198. data/lib/openlanes/evals/verdict.rb +18 -0
  199. data/lib/openlanes/evals.rb +56 -0
  200. data/lib/openlanes/execution/checks.rb +73 -0
  201. data/lib/openlanes/execution/child.rb +228 -0
  202. data/lib/openlanes/execution/clock.rb +121 -0
  203. data/lib/openlanes/execution/control.rb +194 -0
  204. data/lib/openlanes/execution/executor.rb +849 -0
  205. data/lib/openlanes/execution/prompt.rb +455 -0
  206. data/lib/openlanes/execution/transcript.rb +531 -0
  207. data/lib/openlanes/execution.rb +19 -0
  208. data/lib/openlanes/launcher.rb +69 -0
  209. data/lib/openlanes/lifecycle/adoption.rb +197 -0
  210. data/lib/openlanes/lifecycle/brief.rb +288 -0
  211. data/lib/openlanes/lifecycle/completion.rb +58 -0
  212. data/lib/openlanes/lifecycle/creator.rb +126 -0
  213. data/lib/openlanes/lifecycle/lanes.rb +74 -0
  214. data/lib/openlanes/lifecycle/resync.rb +428 -0
  215. data/lib/openlanes/lifecycle/unblocker.rb +236 -0
  216. data/lib/openlanes/lifecycle.rb +28 -0
  217. data/lib/openlanes/linear/api.rb +224 -0
  218. data/lib/openlanes/linear/attribution.rb +185 -0
  219. data/lib/openlanes/linear/fuzzy.rb +68 -0
  220. data/lib/openlanes/linear/import.rb +314 -0
  221. data/lib/openlanes/linear/issue.rb +187 -0
  222. data/lib/openlanes/linear/mapping.rb +116 -0
  223. data/lib/openlanes/linear/push.rb +197 -0
  224. data/lib/openlanes/linear/survey.rb +174 -0
  225. data/lib/openlanes/linear/unit.rb +274 -0
  226. data/lib/openlanes/linear.rb +41 -0
  227. data/lib/openlanes/live/claims.rb +71 -0
  228. data/lib/openlanes/live/command.rb +122 -0
  229. data/lib/openlanes/live/commands.rb +505 -0
  230. data/lib/openlanes/live/keys.rb +93 -0
  231. data/lib/openlanes/live/memory_store.rb +265 -0
  232. data/lib/openlanes/live/meter.rb +51 -0
  233. data/lib/openlanes/live/node.rb +88 -0
  234. data/lib/openlanes/live/publisher.rb +179 -0
  235. data/lib/openlanes/live/repo.rb +60 -0
  236. data/lib/openlanes/live/run_record.rb +133 -0
  237. data/lib/openlanes/live/run_state.rb +101 -0
  238. data/lib/openlanes/live/session.rb +107 -0
  239. data/lib/openlanes/live/snapshot.rb +322 -0
  240. data/lib/openlanes/live/stations.rb +67 -0
  241. data/lib/openlanes/live/store.rb +277 -0
  242. data/lib/openlanes/live.rb +109 -0
  243. data/lib/openlanes/plans/dev_work.rb +56 -0
  244. data/lib/openlanes/plans/feature.rb +131 -0
  245. data/lib/openlanes/plans/index.rb +208 -0
  246. data/lib/openlanes/plans/ledger.rb +255 -0
  247. data/lib/openlanes/plans/mailbox.rb +164 -0
  248. data/lib/openlanes/plans/ordinal.rb +92 -0
  249. data/lib/openlanes/plans/plan_state.rb +291 -0
  250. data/lib/openlanes/plans/pull_request.rb +29 -0
  251. data/lib/openlanes/plans/pull_requests.rb +229 -0
  252. data/lib/openlanes/plans/spec.rb +213 -0
  253. data/lib/openlanes/plans/state_machine.rb +433 -0
  254. data/lib/openlanes/plans/status.rb +365 -0
  255. data/lib/openlanes/plans/subject.rb +133 -0
  256. data/lib/openlanes/plans/tree.rb +79 -0
  257. data/lib/openlanes/plans.rb +39 -0
  258. data/lib/openlanes/presentation/diagram.rb +149 -0
  259. data/lib/openlanes/presentation/documentation.rb +438 -0
  260. data/lib/openlanes/presentation/reporter.rb +181 -0
  261. data/lib/openlanes/presentation/viewer.rb +62 -0
  262. data/lib/openlanes/presentation.rb +23 -0
  263. data/lib/openlanes/skills/installer.rb +68 -0
  264. data/lib/openlanes/skills/skill.rb +60 -0
  265. data/lib/openlanes/skills.rb +25 -0
  266. data/lib/openlanes/support/config.rb +217 -0
  267. data/lib/openlanes/support/frontmatter.rb +38 -0
  268. data/lib/openlanes/support/markdown.rb +56 -0
  269. data/lib/openlanes/support/project.rb +79 -0
  270. data/lib/openlanes/support/ui.rb +671 -0
  271. data/lib/openlanes/vcs/github.rb +171 -0
  272. data/lib/openlanes/vcs/publisher.rb +221 -0
  273. data/lib/openlanes/vcs/worktree.rb +248 -0
  274. data/lib/openlanes/vcs.rb +19 -0
  275. data/lib/openlanes/version.rb +10 -0
  276. data/lib/openlanes/web/app.rb +176 -0
  277. data/lib/openlanes/web/context.rb +66 -0
  278. data/lib/openlanes/web/demo.rb +169 -0
  279. data/lib/openlanes/web/demo_board.rb +286 -0
  280. data/lib/openlanes/web/events.rb +104 -0
  281. data/lib/openlanes/web/launcher.rb +143 -0
  282. data/lib/openlanes/web/server.rb +77 -0
  283. data/lib/openlanes/web/stores.rb +36 -0
  284. data/lib/openlanes/web.rb +92 -0
  285. data/lib/openlanes.rb +151 -0
  286. data/openlanes.gemspec +87 -0
  287. data/schemas/plan-state.schema.json +101 -0
  288. data/skills/openlanes/SKILL.md +48 -0
  289. data/skills/openlanes-documents/SKILL.md +61 -0
  290. data/skills/openlanes-documents/references/blocked-template.md +49 -0
  291. data/skills/openlanes-documents/references/closing-templates.md +59 -0
  292. data/skills/openlanes-documents/references/plan-template.md +61 -0
  293. data/skills/openlanes-documents/references/retroactive-spec.md +43 -0
  294. data/skills/openlanes-documents/references/spec-template.md +45 -0
  295. data/skills/openlanes-run/SKILL.md +90 -0
  296. data/skills/openlanes-setup/SKILL.md +64 -0
  297. data/skills/openlanes-spec/SKILL.md +90 -0
  298. data/skills/openlanes-status/SKILL.md +32 -0
  299. data/skills/openlanes-sync/SKILL.md +22 -0
  300. data/web/dist/assets/apl-B4CMkyY2.js +2 -0
  301. data/web/dist/assets/asciiarmor-Df11BRmG.js +2 -0
  302. data/web/dist/assets/asn1-EdZsLKOL.js +2 -0
  303. data/web/dist/assets/asterisk-B-8jnY81.js +2 -0
  304. data/web/dist/assets/barlow-condensed-latin-600-normal-BFJEwTuo.woff +0 -0
  305. data/web/dist/assets/barlow-condensed-latin-600-normal-DepVgxBB.woff2 +0 -0
  306. data/web/dist/assets/barlow-condensed-latin-ext-600-normal-18ESti3H.woff2 +0 -0
  307. data/web/dist/assets/barlow-condensed-latin-ext-600-normal-Clv9cIcR.woff +0 -0
  308. data/web/dist/assets/barlow-condensed-vietnamese-600-normal-A5AYRdjN.woff2 +0 -0
  309. data/web/dist/assets/barlow-condensed-vietnamese-600-normal-CNlPk46_.woff +0 -0
  310. data/web/dist/assets/brainfuck-C4LP7Hcl.js +2 -0
  311. data/web/dist/assets/clike-B9uivgTg.js +2 -0
  312. data/web/dist/assets/clojure-BMjYHr_A.js +2 -0
  313. data/web/dist/assets/cmake-BQqOBYOt.js +2 -0
  314. data/web/dist/assets/cobol-CWcv1MsR.js +2 -0
  315. data/web/dist/assets/coffeescript-S37ZYGWr.js +2 -0
  316. data/web/dist/assets/commonlisp-DBKNyK5s.js +2 -0
  317. data/web/dist/assets/crystal-SjHAIU92.js +2 -0
  318. data/web/dist/assets/css-BnMrqG3P.js +2 -0
  319. data/web/dist/assets/cypher-C_CwsFkJ.js +2 -0
  320. data/web/dist/assets/d-pRatUO7H.js +2 -0
  321. data/web/dist/assets/diff-DbItnlRl.js +2 -0
  322. data/web/dist/assets/dockerfile-BKs6k2Af.js +2 -0
  323. data/web/dist/assets/dtd-DF_7sFjM.js +2 -0
  324. data/web/dist/assets/dylan-DwRh75JA.js +2 -0
  325. data/web/dist/assets/ebnf-CDyGwa7X.js +2 -0
  326. data/web/dist/assets/ecl-Cabwm37j.js +2 -0
  327. data/web/dist/assets/eiffel-CnydiIhH.js +2 -0
  328. data/web/dist/assets/elm-vLlmbW-K.js +2 -0
  329. data/web/dist/assets/erlang-BNw1qcRV.js +2 -0
  330. data/web/dist/assets/factor-kuTfRLto.js +2 -0
  331. data/web/dist/assets/favicon-C8pAuqqr.png +0 -0
  332. data/web/dist/assets/fcl-Kvtd6kyn.js +2 -0
  333. data/web/dist/assets/forth-Ffai-XNe.js +2 -0
  334. data/web/dist/assets/fortran-DYz_wnZ1.js +2 -0
  335. data/web/dist/assets/gas-Bneqetm1.js +2 -0
  336. data/web/dist/assets/gherkin-heZmZLOM.js +2 -0
  337. data/web/dist/assets/groovy-D9Dt4D0W.js +2 -0
  338. data/web/dist/assets/haskell-Cw1EW3IL.js +2 -0
  339. data/web/dist/assets/haxe-H-WmDvRZ.js +2 -0
  340. data/web/dist/assets/http-DBlCnlav.js +2 -0
  341. data/web/dist/assets/idl-BEugSyMb.js +2 -0
  342. data/web/dist/assets/index-2xPC-eHt.js +2 -0
  343. data/web/dist/assets/index-8dNhRmiO.js +8 -0
  344. data/web/dist/assets/index-B7-O9ujQ.js +2 -0
  345. data/web/dist/assets/index-BdR34cXC.js +2 -0
  346. data/web/dist/assets/index-Bp7W-ZTq.js +2 -0
  347. data/web/dist/assets/index-Byyxbh_z.js +4 -0
  348. data/web/dist/assets/index-C0VmkrO-.js +2 -0
  349. data/web/dist/assets/index-CI74IkWP.js +198 -0
  350. data/web/dist/assets/index-CYxcbpRM.js +3 -0
  351. data/web/dist/assets/index-D0rmJN3h.js +2 -0
  352. data/web/dist/assets/index-DB4QwuYn.js +2 -0
  353. data/web/dist/assets/index-DDI7zoAS.js +2 -0
  354. data/web/dist/assets/index-DGLUuEXi.js +2 -0
  355. data/web/dist/assets/index-OR-odsl9.js +2 -0
  356. data/web/dist/assets/index-P3vSkiU-.js +2 -0
  357. data/web/dist/assets/index-a4EHR-u4.css +1 -0
  358. data/web/dist/assets/index-mRV4XhJZ.js +2 -0
  359. data/web/dist/assets/index-popk9wbW.js +2 -0
  360. data/web/dist/assets/index-uM88Njdj.js +2 -0
  361. data/web/dist/assets/javascript-iXu5QeM3.js +2 -0
  362. data/web/dist/assets/julia-DuME0IfC.js +2 -0
  363. data/web/dist/assets/livescript-BwQOo05w.js +2 -0
  364. data/web/dist/assets/logo-on-dark-DI9gCdN4.png +0 -0
  365. data/web/dist/assets/logo-on-light-BciwqxcJ.png +0 -0
  366. data/web/dist/assets/lua-VAEuO923.js +2 -0
  367. data/web/dist/assets/mathematica-DTrFuWx2.js +2 -0
  368. data/web/dist/assets/mbox-CNhZ1qSd.js +2 -0
  369. data/web/dist/assets/mirc-CjQqDB4T.js +2 -0
  370. data/web/dist/assets/mllike-CXdrOF99.js +2 -0
  371. data/web/dist/assets/modelica-Dc1JOy9r.js +2 -0
  372. data/web/dist/assets/mscgen-BA5vi2Kp.js +2 -0
  373. data/web/dist/assets/mumps-BT43cFF4.js +2 -0
  374. data/web/dist/assets/nginx-DdIZxoE0.js +2 -0
  375. data/web/dist/assets/nsis-LY0VT_u5.js +2 -0
  376. data/web/dist/assets/ntriples-BfvgReVJ.js +2 -0
  377. data/web/dist/assets/octave-Ck1zUtKM.js +2 -0
  378. data/web/dist/assets/overpass-cyrillic-400-normal-CZsFKZCk.woff +0 -0
  379. data/web/dist/assets/overpass-cyrillic-400-normal-tXDxWGRy.woff2 +0 -0
  380. data/web/dist/assets/overpass-cyrillic-600-normal-B-hc8bdn.woff2 +0 -0
  381. data/web/dist/assets/overpass-cyrillic-600-normal-CXB2Mrig.woff +0 -0
  382. data/web/dist/assets/overpass-cyrillic-800-normal-CP6RWG8X.woff2 +0 -0
  383. data/web/dist/assets/overpass-cyrillic-800-normal-PJW4A9xW.woff +0 -0
  384. data/web/dist/assets/overpass-cyrillic-ext-400-normal-AKUz2ZI5.woff2 +0 -0
  385. data/web/dist/assets/overpass-cyrillic-ext-400-normal-C2ZjKngx.woff +0 -0
  386. data/web/dist/assets/overpass-cyrillic-ext-600-normal-CW4Fknsm.woff2 +0 -0
  387. data/web/dist/assets/overpass-cyrillic-ext-600-normal-Zx-mtRSD.woff +0 -0
  388. data/web/dist/assets/overpass-cyrillic-ext-800-normal-CIth-cA7.woff2 +0 -0
  389. data/web/dist/assets/overpass-cyrillic-ext-800-normal-hx3cL3ZN.woff +0 -0
  390. data/web/dist/assets/overpass-latin-400-normal-BpeLJ0bs.woff2 +0 -0
  391. data/web/dist/assets/overpass-latin-400-normal-c_C8zulu.woff +0 -0
  392. data/web/dist/assets/overpass-latin-600-normal-25RhTNCi.woff2 +0 -0
  393. data/web/dist/assets/overpass-latin-600-normal-DhYQrzaY.woff +0 -0
  394. data/web/dist/assets/overpass-latin-800-normal-Bzx_XP5l.woff2 +0 -0
  395. data/web/dist/assets/overpass-latin-800-normal-D6-q4f0l.woff +0 -0
  396. data/web/dist/assets/overpass-latin-ext-400-normal-BIkXRwl6.woff2 +0 -0
  397. data/web/dist/assets/overpass-latin-ext-400-normal-DUq_h-_z.woff +0 -0
  398. data/web/dist/assets/overpass-latin-ext-600-normal-Cyj4Nio0.woff2 +0 -0
  399. data/web/dist/assets/overpass-latin-ext-600-normal-DQKKMGzp.woff +0 -0
  400. data/web/dist/assets/overpass-latin-ext-800-normal-D6WKWGNs.woff +0 -0
  401. data/web/dist/assets/overpass-latin-ext-800-normal-DZ60AB77.woff2 +0 -0
  402. data/web/dist/assets/overpass-mono-cyrillic-400-normal-B144qALP.woff2 +0 -0
  403. data/web/dist/assets/overpass-mono-cyrillic-400-normal-XK9_jwT8.woff +0 -0
  404. data/web/dist/assets/overpass-mono-cyrillic-ext-400-normal-Dgejvo4A.woff2 +0 -0
  405. data/web/dist/assets/overpass-mono-cyrillic-ext-400-normal-DgxwtUZy.woff +0 -0
  406. data/web/dist/assets/overpass-mono-latin-400-normal-DqAOLzCO.woff +0 -0
  407. data/web/dist/assets/overpass-mono-latin-400-normal-VINZG6Js.woff2 +0 -0
  408. data/web/dist/assets/overpass-mono-latin-ext-400-normal-5YIw-E8g.woff +0 -0
  409. data/web/dist/assets/overpass-mono-latin-ext-400-normal-DBdJzBs_.woff2 +0 -0
  410. data/web/dist/assets/overpass-mono-vietnamese-400-normal-DrLp_cHj.woff +0 -0
  411. data/web/dist/assets/overpass-mono-vietnamese-400-normal-jmOeL0rj.woff2 +0 -0
  412. data/web/dist/assets/overpass-vietnamese-400-normal-BKRCEiXy.woff2 +0 -0
  413. data/web/dist/assets/overpass-vietnamese-400-normal-CCWAWVG7.woff +0 -0
  414. data/web/dist/assets/overpass-vietnamese-600-normal-CjS-4vQf.woff2 +0 -0
  415. data/web/dist/assets/overpass-vietnamese-600-normal-DlMMlPfM.woff +0 -0
  416. data/web/dist/assets/overpass-vietnamese-800-normal-BB8K9-Vo.woff2 +0 -0
  417. data/web/dist/assets/overpass-vietnamese-800-normal-DZUygvj_.woff +0 -0
  418. data/web/dist/assets/oz-BzwKVEFT.js +2 -0
  419. data/web/dist/assets/pascal--L3eBynH.js +2 -0
  420. data/web/dist/assets/perl-CdXCOZ3F.js +2 -0
  421. data/web/dist/assets/pig-CevX1Tat.js +2 -0
  422. data/web/dist/assets/powershell-CFHJl5sT.js +2 -0
  423. data/web/dist/assets/properties-C78fOPTZ.js +2 -0
  424. data/web/dist/assets/protobuf-ChK-085T.js +2 -0
  425. data/web/dist/assets/pug-DeIclll2.js +2 -0
  426. data/web/dist/assets/puppet-DMA9R1ak.js +2 -0
  427. data/web/dist/assets/python-BuPzkPfP.js +2 -0
  428. data/web/dist/assets/q-pXgVlZs6.js +2 -0
  429. data/web/dist/assets/r-B6wPVr8A.js +2 -0
  430. data/web/dist/assets/rpm-CTu-6PCP.js +2 -0
  431. data/web/dist/assets/ruby-BK5aLJev.js +2 -0
  432. data/web/dist/assets/sas-B4kiWyti.js +2 -0
  433. data/web/dist/assets/scheme-C41bIUwD.js +2 -0
  434. data/web/dist/assets/shell-CjFT_Tl9.js +2 -0
  435. data/web/dist/assets/sieve-C3Gn_uJK.js +2 -0
  436. data/web/dist/assets/simple-mode-GW_nhZxv.js +2 -0
  437. data/web/dist/assets/smalltalk-CnHTOXQT.js +2 -0
  438. data/web/dist/assets/solr-DehyRSwq.js +2 -0
  439. data/web/dist/assets/sparql-DkYu6x3z.js +2 -0
  440. data/web/dist/assets/spreadsheet-BCZA_wO0.js +2 -0
  441. data/web/dist/assets/sql-D0XecflT.js +2 -0
  442. data/web/dist/assets/stex-C3f8Ysf7.js +2 -0
  443. data/web/dist/assets/stylus-B533Al4x.js +2 -0
  444. data/web/dist/assets/swift-BzpIVaGY.js +2 -0
  445. data/web/dist/assets/tcl-DVfN8rqt.js +2 -0
  446. data/web/dist/assets/textile-CnDTJFAw.js +2 -0
  447. data/web/dist/assets/tiddlywiki-DO-Gjzrf.js +2 -0
  448. data/web/dist/assets/tiki-DGYXhP31.js +2 -0
  449. data/web/dist/assets/toml-Bm5Em-hy.js +2 -0
  450. data/web/dist/assets/troff-wAsdV37c.js +2 -0
  451. data/web/dist/assets/ttcn-CfJYG6tj.js +2 -0
  452. data/web/dist/assets/ttcn-cfg-B9xdYoR4.js +2 -0
  453. data/web/dist/assets/turtle-B1tBg_DP.js +2 -0
  454. data/web/dist/assets/vb-CmGdzxic.js +2 -0
  455. data/web/dist/assets/vbscript-BuJXcnF6.js +2 -0
  456. data/web/dist/assets/velocity-D8B20fx6.js +2 -0
  457. data/web/dist/assets/verilog-C6RDOZhf.js +2 -0
  458. data/web/dist/assets/vhdl-lSbBsy5d.js +2 -0
  459. data/web/dist/assets/webidl-ZXfAyPTL.js +2 -0
  460. data/web/dist/assets/xquery-DzFWVndE.js +2 -0
  461. data/web/dist/assets/yacas-BJ4BC0dw.js +2 -0
  462. data/web/dist/assets/z80-Hz9HOZM7.js +2 -0
  463. data/web/dist/index.html +14 -0
  464. data/web/dist/vite.svg +1 -0
  465. data/web/src/api/fixtures/board.json +512 -0
  466. metadata +907 -0
@@ -0,0 +1,12 @@
1
+ ---
2
+ frontend: false
3
+ ---
4
+ # Reject Empty Titles
5
+
6
+ ## Goal
7
+
8
+ `create` refuses an empty title with exit 2 and creates no folder.
9
+
10
+ ## In scope
11
+
12
+ - `Creator#create("")` raises; the CLI exits 2; a spec proves both.
@@ -0,0 +1 @@
1
+ {"seconds": 388, "tokens": 172500, "state": "planned"}
@@ -0,0 +1,8 @@
1
+ ## U1 Reject empty titles
2
+
3
+ - **Discipline:** back end
4
+ - **Owns:** `lib/creator.rb`, `spec/creator_spec.rb`
5
+ - **Must not touch:** `lib/cli.rb`
6
+ - **Depends on:** nothing
7
+ - **Done when:** `spec/creator_spec.rb` "rejects an empty title" passes
8
+
@@ -0,0 +1 @@
1
+ No front-end work in this plan.
@@ -0,0 +1,12 @@
1
+ # Plan
2
+
3
+ One unit; it is also the integration check, since there is no front end.
4
+
5
+ ## Order
6
+
7
+ 1. U1 Reject empty titles. Integration: `exe/openlanes create ""` exits 2 and `.plans` is unchanged.
8
+
9
+ > [!NOTE]
10
+ >
11
+ > [2026-09-04 01:10:00 PM PDT] [ agent: palpatine-planner status: Started, round 1 ]
12
+ > [2026-09-04 01:14:30 PM PDT] [ agent: palpatine-planner status: Completed, round 1 ]
@@ -0,0 +1,12 @@
1
+ ---
2
+ frontend: false
3
+ ---
4
+ # Reject Empty Titles
5
+
6
+ ## Goal
7
+
8
+ `create` refuses an empty title with exit 2 and creates no folder.
9
+
10
+ ## In scope
11
+
12
+ - `Creator#create("")` raises; the CLI exits 2; a spec proves both.
@@ -0,0 +1 @@
1
+ {"seconds": 121, "tokens": 31800, "state": "planned"}
@@ -0,0 +1,47 @@
1
+ id: plan-fast
2
+ agent: palpatine-planner
3
+ depth: fast
4
+ description: >
5
+ A one-change spec. At fast depth the plan is one or two units with every
6
+ field filled in; six units for a one-line validation is overdone.
7
+ fixture:
8
+ state: ready_for_planning
9
+ slug: reject-empty-titles
10
+ files:
11
+ spec.md: |
12
+ ---
13
+ frontend: false
14
+ ---
15
+ # Reject Empty Titles
16
+
17
+ ## Goal
18
+
19
+ `create` refuses an empty title with exit 2 and creates no folder.
20
+
21
+ ## In scope
22
+
23
+ - `Creator#create("")` raises; the CLI exits 2; a spec proves both.
24
+ plan.md: ""
25
+ expect:
26
+ state: planned
27
+ signed: true
28
+ files_exist: [plan.md, plan-backend.md, plan-frontend.md]
29
+ contains:
30
+ plan.md: ["/[Ii]ntegration/"]
31
+ plan-backend.md: ["Owns:", "Must not touch:", "Depends on:", "Done when:"]
32
+ depth:
33
+ fast:
34
+ count: { file: plan-backend.md, pattern: "Discipline:", min: 1, max: 3 }
35
+ words: { file: plan.md, max: 300 }
36
+ max_seconds: 300
37
+ max_tokens: 80000
38
+ medium:
39
+ count: { file: plan-backend.md, pattern: "Discipline:", min: 2, max: 6 }
40
+ words: { file: plan.md, min: 80, max: 1200 }
41
+ max_seconds: 450
42
+ max_tokens: 150000
43
+ deep:
44
+ count: { file: plan-backend.md, pattern: "Discipline:", min: 3, max: 8 }
45
+ words: { file: plan.md, min: 150, max: 2500 }
46
+ max_seconds: 600
47
+ max_tokens: 300000
@@ -0,0 +1,7 @@
1
+ # Plan
2
+
3
+ ## Task
4
+
5
+ - Changed: "Helo" to "Hello" in `lib/greeter.rb:2`; the spec now asserts the whole greeting.
6
+ - Verified: `bundle exec rspec` — 1 example, 0 failures.
7
+ - Look first at: nothing else changed.
@@ -0,0 +1,6 @@
1
+ # Pull Requests
2
+
3
+ > [!NOTE]
4
+ >
5
+ > [2026-09-04 04:00:00 PM PDT] [ agent: r2d2-mechanic status: Started, round 1 ]
6
+ > [2026-09-04 04:02:40 PM PDT] [ agent: r2d2-mechanic status: Completed, round 1 ]
@@ -0,0 +1,6 @@
1
+ ---
2
+ lane: quick
3
+ ---
4
+ # Greeting Typo
5
+
6
+ `lib/greeter.rb` says "Helo". Make it "Hello" and keep the test honest.
@@ -0,0 +1,3 @@
1
+ # Greeter
2
+
3
+ Says hello.
@@ -0,0 +1,12 @@
1
+ module Greeter
2
+ # Turns a name into a greeting.
3
+ class Formatter
4
+ def initialize(salutation:)
5
+ @salutation = salutation
6
+ end
7
+
8
+ # @param name [String]
9
+ # @return [String]
10
+ def format(name) = "#{@salutation}, #{name.strip}!"
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "greeter/formatter"
2
+
3
+ # Greets people. Restructured around a formatter so salutations can vary.
4
+ module Greeter
5
+ DEFAULT_SALUTATION = "Hello"
6
+
7
+ class << self
8
+ # @param name [String]
9
+ # @param salutation [String]
10
+ # @return [String]
11
+ def greet(name, salutation: DEFAULT_SALUTATION)
12
+ Formatter.new(salutation:).format(name)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ require_relative "../lib/greeter"
2
+
3
+ RSpec.describe Greeter do
4
+ it "greets" do
5
+ expect(described_class.greet("Ada")).to eq("Hello, Ada!")
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ {"seconds": 260, "tokens": 57900}
@@ -0,0 +1,7 @@
1
+ # Plan
2
+
3
+ ## Task
4
+
5
+ - Changed: "Helo" to "Hello" in `lib/greeter.rb:2`; the spec now asserts the whole greeting.
6
+ - Verified: `bundle exec rspec` — 1 example, 0 failures.
7
+ - Look first at: nothing else changed.
@@ -0,0 +1,6 @@
1
+ # Pull Requests
2
+
3
+ > [!NOTE]
4
+ >
5
+ > [2026-09-04 04:00:00 PM PDT] [ agent: r2d2-mechanic status: Started, round 1 ]
6
+ > [2026-09-04 04:02:40 PM PDT] [ agent: r2d2-mechanic status: Completed, round 1 ]
@@ -0,0 +1,6 @@
1
+ ---
2
+ lane: quick
3
+ ---
4
+ # Greeting Typo
5
+
6
+ `lib/greeter.rb` says "Helo". Make it "Hello" and keep the test honest.
@@ -0,0 +1,3 @@
1
+ # Greeter
2
+
3
+ Says hello.
@@ -0,0 +1,3 @@
1
+ module Greeter
2
+ def self.greet(name) = "Hello, #{name}!"
3
+ end
@@ -0,0 +1,7 @@
1
+ require_relative "../lib/greeter"
2
+
3
+ RSpec.describe Greeter do
4
+ it "greets" do
5
+ expect(described_class.greet("Ada")).to eq("Hello, Ada!")
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ {"seconds": 95, "tokens": 21400}
@@ -0,0 +1,59 @@
1
+ id: task-fast
2
+ agent: r2d2-mechanic
3
+ depth: fast
4
+ description: >
5
+ A quick-lane typo fix. At fast depth the diff is a line or two in the
6
+ file named and its test, with three lines under ## Task. Restructuring the
7
+ module on the way past is an oversized diff, however tidy.
8
+ fixture:
9
+ state: planned
10
+ slug: greeting-typo
11
+ files:
12
+ spec.md: |
13
+ ---
14
+ lane: quick
15
+ ---
16
+ # Greeting Typo
17
+
18
+ `lib/greeter.rb` says "Helo". Make it "Hello" and keep the test honest.
19
+ plan.md: |
20
+ # Plan
21
+
22
+ ## Task
23
+ repo:
24
+ README.md: |
25
+ # Greeter
26
+
27
+ Says hello.
28
+ lib/greeter.rb: |
29
+ module Greeter
30
+ def self.greet(name) = "Helo, #{name}!"
31
+ end
32
+ spec/greeter_spec.rb: |
33
+ require_relative "../lib/greeter"
34
+
35
+ RSpec.describe Greeter do
36
+ it "greets" do
37
+ expect(described_class.greet("Ada")).to include("Ada")
38
+ end
39
+ end
40
+ expect:
41
+ signed: true
42
+ files_exist: [pull-requests.md]
43
+ sections:
44
+ plan.md: [Task]
45
+ changed_paths: [lib/greeter.rb]
46
+ untouched: [README.md]
47
+ depth:
48
+ fast:
49
+ changed_files: { min: 1, max: 2 }
50
+ changed_lines: { min: 1, max: 20 }
51
+ words: { file: plan.md, section: Task, min: 5, max: 80 }
52
+ max_seconds: 300
53
+ max_tokens: 60000
54
+ medium:
55
+ changed_files: { min: 1, max: 4 }
56
+ changed_lines: { min: 2, max: 80 }
57
+ words: { file: plan.md, section: Task, min: 5, max: 150 }
58
+ max_seconds: 600
59
+ max_tokens: 120000
@@ -0,0 +1,7 @@
1
+ # Plan
2
+
3
+ ## Task
4
+
5
+ - Changed: `Greeter.greet` takes `shout:`; `lib/greeter.rb:2`. Added a spec for it.
6
+ - Verified: `bundle exec rspec` — 2 examples, 0 failures.
7
+ - Look first at: the keyword default, which keeps every existing caller unchanged.
@@ -0,0 +1,6 @@
1
+ # Pull Requests
2
+
3
+ > [!NOTE]
4
+ >
5
+ > [2026-09-04 04:00:00 PM PDT] [ agent: r2d2-mechanic status: Started, round 1 ]
6
+ > [2026-09-04 04:09:58 PM PDT] [ agent: r2d2-mechanic status: **Interrupted, round 1 (no closing ledger line)** ]
@@ -0,0 +1,6 @@
1
+ ---
2
+ lane: quick
3
+ ---
4
+ # Shout Option
5
+
6
+ `Greeter.greet(name, shout: true)` returns the greeting upper-cased. Test it.
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gem "rspec"
@@ -0,0 +1,6 @@
1
+ module Greeter
2
+ def self.greet(name, shout: false)
3
+ greeting = "Hello, #{name}!"
4
+ shout ? greeting.upcase : greeting
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "../lib/greeter"
2
+
3
+ RSpec.describe Greeter do
4
+ it "greets" do
5
+ expect(described_class.greet("Ada")).to eq("Hello, Ada!")
6
+ end
7
+
8
+ it "shouts when asked" do
9
+ expect(described_class.greet("Ada", shout: true)).to eq("HELLO, ADA!")
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ {"seconds": 598, "tokens": 71000}
@@ -0,0 +1,7 @@
1
+ # Plan
2
+
3
+ ## Task
4
+
5
+ - Changed: `Greeter.greet` takes `shout:`; `lib/greeter.rb:2`. Added a spec for it.
6
+ - Verified: `bundle exec rspec` — 2 examples, 0 failures.
7
+ - Look first at: the keyword default, which keeps every existing caller unchanged.
@@ -0,0 +1,6 @@
1
+ # Pull Requests
2
+
3
+ > [!NOTE]
4
+ >
5
+ > [2026-09-04 04:00:00 PM PDT] [ agent: r2d2-mechanic status: Started, round 1 ]
6
+ > [2026-09-04 04:02:40 PM PDT] [ agent: r2d2-mechanic status: Completed, round 1 ]
@@ -0,0 +1,6 @@
1
+ ---
2
+ lane: quick
3
+ ---
4
+ # Shout Option
5
+
6
+ `Greeter.greet(name, shout: true)` returns the greeting upper-cased. Test it.
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gem "rspec"
@@ -0,0 +1,6 @@
1
+ module Greeter
2
+ def self.greet(name, shout: false)
3
+ greeting = "Hello, #{name}!"
4
+ shout ? greeting.upcase : greeting
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "../lib/greeter"
2
+
3
+ RSpec.describe Greeter do
4
+ it "greets" do
5
+ expect(described_class.greet("Ada")).to eq("Hello, Ada!")
6
+ end
7
+
8
+ it "shouts when asked" do
9
+ expect(described_class.greet("Ada", shout: true)).to eq("HELLO, ADA!")
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ {"seconds": 240, "tokens": 64000}
@@ -0,0 +1,58 @@
1
+ id: task-medium
2
+ agent: r2d2-mechanic
3
+ depth: medium
4
+ description: >
5
+ A quick-lane option: --shout upper-cases the greeting. At medium depth a
6
+ few files may change, with a test. Stopping without a Completed line
7
+ leaves the harness nothing to act on, however good the diff.
8
+ fixture:
9
+ state: planned
10
+ slug: shout-option
11
+ files:
12
+ spec.md: |
13
+ ---
14
+ lane: quick
15
+ ---
16
+ # Shout Option
17
+
18
+ `Greeter.greet(name, shout: true)` returns the greeting upper-cased. Test it.
19
+ plan.md: |
20
+ # Plan
21
+
22
+ ## Task
23
+ repo:
24
+ Gemfile: |
25
+ source "https://rubygems.org"
26
+ gem "rspec"
27
+ lib/greeter.rb: |
28
+ module Greeter
29
+ def self.greet(name) = "Hello, #{name}!"
30
+ end
31
+ spec/greeter_spec.rb: |
32
+ require_relative "../lib/greeter"
33
+
34
+ RSpec.describe Greeter do
35
+ it "greets" do
36
+ expect(described_class.greet("Ada")).to eq("Hello, Ada!")
37
+ end
38
+ end
39
+ expect:
40
+ signed: true
41
+ files_exist: [pull-requests.md]
42
+ sections:
43
+ plan.md: [Task]
44
+ changed_paths: [lib/greeter.rb, spec/greeter_spec.rb]
45
+ untouched: [Gemfile]
46
+ depth:
47
+ fast:
48
+ changed_files: { min: 1, max: 2 }
49
+ changed_lines: { min: 1, max: 20 }
50
+ words: { file: plan.md, section: Task, min: 5, max: 80 }
51
+ max_seconds: 300
52
+ max_tokens: 60000
53
+ medium:
54
+ changed_files: { min: 1, max: 4 }
55
+ changed_lines: { min: 2, max: 80 }
56
+ words: { file: plan.md, section: Task, min: 5, max: 150 }
57
+ max_seconds: 600
58
+ max_tokens: 120000
@@ -0,0 +1,7 @@
1
+ ## U2 Show the quantity error
2
+
3
+ - **Discipline:** front end
4
+ - **Owns:** `web/cart_badge.js`, `web/cart_badge.test.js`
5
+ - **Must not touch:** `lib/cart.rb`
6
+ - **Depends on:** U1
7
+ - **Done when:** `web/cart_badge.test.js` "shows the error" passes
@@ -0,0 +1,4 @@
1
+ # Plan
2
+
3
+ 1. U1 (back end, done) raises `Cart::InvalidQuantity`.
4
+ 2. U2 (front end) shows it. Integration: add -1 in the browser, see the message.
@@ -0,0 +1,8 @@
1
+ # Pull Requests
2
+
3
+ Integration proof: `npm test` — 2 passed; adding -1 on the cart page shows "quantity must be at least 1".
4
+
5
+ > [!NOTE]
6
+ >
7
+ > [2026-09-04 03:00:00 PM PDT] [ agent: rey-frontend status: Started, round 1 ]
8
+ > [2026-09-04 03:09:12 PM PDT] [ agent: rey-frontend status: Completed, round 1 ]
@@ -0,0 +1,5 @@
1
+ # Quantity Error
2
+
3
+ ## Goal
4
+
5
+ The cart page shows `Cart::InvalidQuantity`'s message next to the quantity field.
@@ -0,0 +1,5 @@
1
+ class Cart
2
+ class InvalidQuantity < ArgumentError
3
+ def message = "quantity must be at least 1"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ export function render(cart) {
2
+ const error = cart.error ? `<p role="alert" class="field-error">${cart.error}</p>` : "";
3
+ return `<span class="badge">${cart.count}</span>${error}`;
4
+ }
@@ -0,0 +1,3 @@
1
+ import { render } from "./cart_badge.js";
2
+ test("renders the count", () => expect(render({ count: 2 })).toContain("2"));
3
+ test("shows the error", () => expect(render({ count: 0, error: "quantity must be at least 1" })).toContain('role="alert"'));
@@ -0,0 +1 @@
1
+ {"seconds": 610, "tokens": 131000}
@@ -0,0 +1,7 @@
1
+ ## U2 Show the quantity error
2
+
3
+ - **Discipline:** front end
4
+ - **Owns:** `web/cart_badge.js`, `web/cart_badge.test.js`
5
+ - **Must not touch:** `lib/cart.rb`
6
+ - **Depends on:** U1
7
+ - **Done when:** `web/cart_badge.test.js` "shows the error" passes
@@ -0,0 +1,4 @@
1
+ # Plan
2
+
3
+ 1. U1 (back end, done) raises `Cart::InvalidQuantity`.
4
+ 2. U2 (front end) shows it. Integration: add -1 in the browser, see the message.
@@ -0,0 +1,8 @@
1
+ # Pull Requests
2
+
3
+ Integration proof: `npm test` — 2 passed; adding -1 on the cart page shows "quantity must be at least 1".
4
+
5
+ > [!NOTE]
6
+ >
7
+ > [2026-09-04 03:00:00 PM PDT] [ agent: rey-frontend status: Started, round 1 ]
8
+ > [2026-09-04 03:09:12 PM PDT] [ agent: rey-frontend status: Completed, round 1 ]
@@ -0,0 +1,5 @@
1
+ # Quantity Error
2
+
3
+ ## Goal
4
+
5
+ The cart page shows `Cart::InvalidQuantity`'s message next to the quantity field.
@@ -0,0 +1,3 @@
1
+ class Cart
2
+ class InvalidQuantity < ArgumentError; end
3
+ end
@@ -0,0 +1,4 @@
1
+ export function render(cart) {
2
+ const error = cart.error ? `<p role="alert" class="field-error">${cart.error}</p>` : "";
3
+ return `<span class="badge">${cart.count}</span>${error}`;
4
+ }
@@ -0,0 +1,3 @@
1
+ import { render } from "./cart_badge.js";
2
+ test("renders the count", () => expect(render({ count: 2 })).toContain("2"));
3
+ test("shows the error", () => expect(render({ count: 0, error: "quantity must be at least 1" })).toContain('role="alert"'));
@@ -0,0 +1 @@
1
+ {"seconds": 552, "tokens": 118000}
@@ -0,0 +1,55 @@
1
+ id: ui-medium
2
+ agent: rey-frontend
3
+ depth: medium
4
+ description: >
5
+ One front-end unit against a back end that already landed: show the cart's
6
+ quantity error next to the field. rey must change the interface and its
7
+ test, paste the integration proof, and leave the back end alone.
8
+ fixture:
9
+ state: building_ui
10
+ slug: quantity-error
11
+ files:
12
+ spec.md: |
13
+ # Quantity Error
14
+
15
+ ## Goal
16
+
17
+ The cart page shows `Cart::InvalidQuantity`'s message next to the quantity field.
18
+ plan.md: |
19
+ # Plan
20
+
21
+ 1. U1 (back end, done) raises `Cart::InvalidQuantity`.
22
+ 2. U2 (front end) shows it. Integration: add -1 in the browser, see the message.
23
+ plan-frontend.md: |
24
+ ## U2 Show the quantity error
25
+
26
+ - **Discipline:** front end
27
+ - **Owns:** `web/cart_badge.js`, `web/cart_badge.test.js`
28
+ - **Must not touch:** `lib/cart.rb`
29
+ - **Depends on:** U1
30
+ - **Done when:** `web/cart_badge.test.js` "shows the error" passes
31
+ repo:
32
+ lib/cart.rb: |
33
+ class Cart
34
+ class InvalidQuantity < ArgumentError; end
35
+ end
36
+ web/cart_badge.js: |
37
+ export function render(cart) {
38
+ return `<span class="badge">${cart.count}</span>`;
39
+ }
40
+ web/cart_badge.test.js: |
41
+ import { render } from "./cart_badge.js";
42
+ test("renders the count", () => expect(render({ count: 2 })).toContain("2"));
43
+ expect:
44
+ signed: true
45
+ files_exist: [pull-requests.md]
46
+ contains:
47
+ pull-requests.md: ["/[Ii]ntegration/"]
48
+ changed_paths: [web/*.js, web/*.test.js]
49
+ untouched: [lib/**]
50
+ depth:
51
+ medium:
52
+ changed_files: { min: 2, max: 6 }
53
+ changed_lines: { min: 4, max: 200 }
54
+ max_seconds: 1200
55
+ max_tokens: 200000
@@ -0,0 +1,5 @@
1
+ # Plan
2
+
3
+ ## Units
4
+
5
+ 1. Validate quantity in Cart#add.