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,39 @@
1
+ # Filing Deadlines
2
+
3
+ Show each small business its next estimated-tax filing deadline, moved for weekends and holidays.
4
+
5
+ ## What research needs to settle
6
+
7
+ 1. Which deadlines apply, and where do they come from?
8
+ 2. How is a deadline moved when it falls on a weekend or holiday?
9
+ 3. Does the codebase already know about holidays?
10
+
11
+ ## Research
12
+
13
+ ### 1. Which deadlines apply
14
+
15
+ Estimated tax is due in four instalments: the 15th of April, June, September and January of the following year (https://tax.example.gov/estimated-payments, retrieved 2026-09-04). The instalment schedule is the same for sole proprietors and single-member companies; partnerships pass the obligation to their partners (https://tax.example.gov/partnerships/estimated, retrieved 2026-09-04). A state-level schedule exists for the fictional state of Westland and follows the federal dates with one exception, a January instalment due on the 31st (https://revenue.westland.example.gov/estimated, retrieved 2026-09-04).
16
+
17
+ ### 2. Weekends and holidays
18
+
19
+ When a due date falls on a Saturday, Sunday or legal holiday, the deadline moves to the next business day (https://tax.example.gov/publications/deadlines#weekend-rule, retrieved 2026-09-04). Legal holidays include those observed in the capital district, which adds Emancipation Day, observed on the nearest weekday when it falls on a weekend (https://dc.example.gov/holidays, retrieved 2026-09-04). The observed-date rule is where most calendars go wrong: a holiday on a Saturday is observed on the Friday before, which does not move a Monday deadline.
20
+
21
+ ### 3. What the codebase knows
22
+
23
+ `lib/calendar.rb:2` hard-codes three holidays for 2025 only. Nothing computes observed dates, and nothing knows the capital district's holiday. Running the calendar against 2026 returns no holidays at all, so every 2026 deadline would be computed as if no holiday existed.
24
+
25
+ ### Contradictions
26
+
27
+ 1. The draft says "weekends and holidays"; the code knows 2025 only. Production runs the code, so today every holiday-adjacent deadline in 2026 is wrong.
28
+ 2. The federal page lists the January instalment as the 15th; Westland lists the 31st. Both are right for their own return, so the product must show two deadlines, not one.
29
+
30
+ ### Could not settle
31
+
32
+ 1. Whether the product should show Westland deadlines at all, or federal only. This is a product decision for yoda to lift.
33
+ 2. Whether disaster-area postponements, which move deadlines per county, are in scope (https://tax.example.gov/disaster-relief, retrieved 2026-09-04).
34
+
35
+ > [!NOTE]
36
+ >
37
+ > [2026-09-04 11:29:20 AM PDT] [ agent: leah-researcher status: Started, round 1 ]
38
+ > [2026-09-04 11:47:51 AM PDT] [ agent: leah-researcher status: Completed, round 1 ]
39
+ > [2026-09-04 11:47:52 AM PDT] [ next: yoda-writer ]
@@ -0,0 +1 @@
1
+ {"seconds": 1011, "tokens": 214800, "state": "researched"}
@@ -0,0 +1,51 @@
1
+ id: research-deep
2
+ agent: leah-researcher
3
+ depth: deep
4
+ description: >
5
+ A spec that touches a regulated rule. At deep depth leah must survey the
6
+ code and several primary sources, list contradictions and what it could
7
+ not settle. A two-paragraph chapter with one link is too shallow here.
8
+ fixture:
9
+ state: new
10
+ slug: filing-deadlines
11
+ files:
12
+ spec.md: |
13
+ # Filing Deadlines
14
+
15
+ Show each small business its next estimated-tax filing deadline, moved for weekends and holidays.
16
+
17
+ ## What research needs to settle
18
+
19
+ 1. Which deadlines apply, and where do they come from?
20
+ 2. How is a deadline moved when it falls on a weekend or holiday?
21
+ 3. Does the codebase already know about holidays?
22
+ repo:
23
+ lib/calendar.rb: |
24
+ # Business days only; holidays are hard-coded for 2025.
25
+ module Calendar
26
+ HOLIDAYS = %w[2025-01-01 2025-07-04 2025-12-25].freeze
27
+ end
28
+ expect:
29
+ state: researched
30
+ signed: true
31
+ files_absent: [plan.md]
32
+ sections:
33
+ spec.md: [Research, Contradictions, Could not settle]
34
+ contains:
35
+ spec.md: [lib/calendar.rb]
36
+ depth:
37
+ fast:
38
+ words: { file: spec.md, section: Research, min: 40, max: 180 }
39
+ count: { file: spec.md, section: Research, pattern: 'https?://', min: 1, max: 3 }
40
+ max_seconds: 300
41
+ max_tokens: 80000
42
+ medium:
43
+ words: { file: spec.md, section: Research, min: 120, max: 1200 }
44
+ count: { file: spec.md, section: Research, pattern: 'https?://', min: 2, max: 8 }
45
+ max_seconds: 600
46
+ max_tokens: 150000
47
+ deep:
48
+ words: { file: spec.md, section: Research, min: 250, max: 3000 }
49
+ count: { file: spec.md, section: Research, pattern: 'https?://', min: 5 }
50
+ max_seconds: 1200
51
+ max_tokens: 300000
@@ -0,0 +1,27 @@
1
+ # Billing Retries
2
+
3
+ Jobs that call the Example Corp billing API fail on transient 503 responses. Retry them.
4
+
5
+ ## What research needs to settle
6
+
7
+ 1. Does the repository already have a retry helper we can reuse?
8
+ 2. What backoff does the billing API ask clients to use?
9
+
10
+ ## Research
11
+
12
+ ### Repository survey
13
+
14
+ `lib/retry_policy.rb:1` defines `RetryPolicy` with three attempts, a 0.5 second base and doubling delays. `lib/billing_client.rb:2` defines `BillingClient#charge`, which posts to `/charges` and does not retry at all today. No other file in the repository mentions retries, backoff, jitter or circuit breaking, and there is no shared HTTP wrapper that could host the behaviour instead.
15
+
16
+ ### Upstream guidance
17
+
18
+ The billing API documentation asks for exponential backoff from 500 ms (https://docs.example.com/billing/errors, retrieved 2026-09-04). Its rate limit page repeats the advice (https://docs.example.com/billing/rate-limits, retrieved 2026-09-04). The changelog shows the advice has not changed since version 2 (https://docs.example.com/billing/changelog, retrieved 2026-09-04). A general article on jitter argues for full jitter over equal jitter (https://blog.example.org/backoff-and-jitter, retrieved 2026-09-04). A second article compares decorrelated jitter (https://blog.example.net/decorrelated-jitter, retrieved 2026-09-04). The HTTP specification defines `Retry-After` (https://www.rfc-editor.org/rfc/rfc9110#field.retry-after, retrieved 2026-09-04).
19
+
20
+ ### Survey of alternative libraries
21
+
22
+ Three retry gems were compared for completeness, although the repository already has a policy: one wraps Faraday middleware, one decorates arbitrary blocks, and one integrates with background job frameworks. Each would add a dependency for behaviour the twelve-line policy already implements, so none is recommended, but their feature matrices are summarised here for a future reader who might want circuit breaking or metrics later.
23
+
24
+ > [!NOTE]
25
+ >
26
+ > [2026-09-04 11:29:20 AM PDT] [ agent: leah-researcher status: Started, round 1 ]
27
+ > [2026-09-04 11:46:02 AM PDT] [ agent: leah-researcher status: Completed, round 1 ]
@@ -0,0 +1 @@
1
+ {"seconds": 982, "tokens": 241300, "state": "researched"}
@@ -0,0 +1,23 @@
1
+ # Billing Retries
2
+
3
+ Jobs that call the Example Corp billing API fail on transient 503 responses. Retry them.
4
+
5
+ ## What research needs to settle
6
+
7
+ 1. Does the repository already have a retry helper we can reuse?
8
+ 2. What backoff does the billing API ask clients to use?
9
+
10
+ ## Research
11
+
12
+ 1. Yes. `lib/retry_policy.rb:1` defines `RetryPolicy`: three attempts, 0.5 s base, doubling. `BillingClient#charge` (`lib/billing_client.rb:2`) does not use it yet.
13
+ 2. The billing API asks for exponential backoff starting at 500 ms and honouring `Retry-After` on 503 (https://docs.example.com/billing/errors, retrieved 2026-09-04). The existing policy matches except for `Retry-After`.
14
+
15
+ ### Could not settle
16
+
17
+ 1. Whether `charge` is idempotent on retry; the API docs do not say.
18
+
19
+ > [!NOTE]
20
+ >
21
+ > [2026-09-04 11:29:20 AM PDT] [ agent: leah-researcher status: Started, round 1 ]
22
+ > [2026-09-04 11:31:42 AM PDT] [ agent: leah-researcher status: Completed, round 1 ]
23
+ > [2026-09-04 11:31:43 AM PDT] [ next: yoda-writer ]
@@ -0,0 +1 @@
1
+ {"seconds": 142, "tokens": 38150, "state": "researched"}
@@ -0,0 +1,55 @@
1
+ id: research-fast
2
+ agent: leah-researcher
3
+ depth: fast
4
+ description: >
5
+ A bare spec asking two narrow questions. At fast depth leah should answer
6
+ both from the repository and one upstream page, and stop: a short Research
7
+ chapter, few sources, a small bill.
8
+ fixture:
9
+ state: new
10
+ slug: billing-retries
11
+ files:
12
+ spec.md: |
13
+ # Billing Retries
14
+
15
+ Jobs that call the Example Corp billing API fail on transient 503 responses. Retry them.
16
+
17
+ ## What research needs to settle
18
+
19
+ 1. Does the repository already have a retry helper we can reuse?
20
+ 2. What backoff does the billing API ask clients to use?
21
+ repo:
22
+ lib/retry_policy.rb: |
23
+ # Bounded exponential backoff: 3 attempts, 0.5s base, doubling.
24
+ class RetryPolicy
25
+ ATTEMPTS = 3
26
+ BASE = 0.5
27
+ end
28
+ lib/billing_client.rb: |
29
+ class BillingClient
30
+ def charge(amount) = post("/charges", amount:)
31
+ end
32
+ expect:
33
+ state: researched
34
+ signed: true
35
+ files_absent: [plan.md]
36
+ sections:
37
+ spec.md: [Research]
38
+ contains:
39
+ spec.md: [lib/retry_policy.rb]
40
+ depth:
41
+ fast:
42
+ words: { file: spec.md, section: Research, min: 40, max: 180 }
43
+ count: { file: spec.md, section: Research, pattern: 'https?://', min: 1, max: 3 }
44
+ max_seconds: 300
45
+ max_tokens: 80000
46
+ medium:
47
+ words: { file: spec.md, section: Research, min: 120, max: 1200 }
48
+ count: { file: spec.md, section: Research, pattern: 'https?://', min: 2, max: 8 }
49
+ max_seconds: 600
50
+ max_tokens: 150000
51
+ deep:
52
+ words: { file: spec.md, section: Research, min: 250, max: 3000 }
53
+ count: { file: spec.md, section: Research, pattern: 'https?://', min: 5 }
54
+ max_seconds: 1200
55
+ max_tokens: 300000
@@ -0,0 +1,7 @@
1
+ ## U1 Reject negative quantity
2
+
3
+ - **Discipline:** back end
4
+ - **Owns:** `lib/cart.rb`, `spec/cart_spec.rb`
5
+ - **Must not touch:** `Gemfile`
6
+ - **Depends on:** nothing
7
+ - **Done when:** `spec/cart_spec.rb` "rejects a negative quantity" passes
@@ -0,0 +1 @@
1
+ No front-end work in this plan.
@@ -0,0 +1,3 @@
1
+ # Plan
2
+
3
+ 1. U1 Reject negative quantity (back end). Integration: U1's spec.
@@ -0,0 +1,8 @@
1
+ # Pull Requests
2
+
3
+ `bundle exec rspec` — 1 example, 0 failures.
4
+
5
+ > [!NOTE]
6
+ >
7
+ > [2026-09-04 02:00:00 PM PDT] [ agent: luke-backend status: Started, round 1 ]
8
+ > [2026-09-04 02:11:20 PM PDT] [ agent: luke-backend status: Completed, round 1 ]
@@ -0,0 +1,8 @@
1
+ ---
2
+ frontend: false
3
+ ---
4
+ # Negative Quantity
5
+
6
+ ## Goal
7
+
8
+ `Cart#add` rejects a quantity below 1.
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gem "rspec"
@@ -0,0 +1,11 @@
1
+ class Cart
2
+ class InvalidQuantity < ArgumentError; end
3
+
4
+ def initialize = @lines = {}
5
+
6
+ def add(sku, quantity)
7
+ raise InvalidQuantity, "quantity must be at least 1, got #{quantity}" if quantity < 1
8
+
9
+ @lines[sku] = quantity
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ require_relative "../lib/cart"
2
+
3
+ RSpec.describe Cart do
4
+ it "adds a line" do
5
+ expect(described_class.new.add("A1", 2)).to eq(2)
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ {"seconds": 390, "tokens": 88000}
@@ -0,0 +1,7 @@
1
+ ## U1 Reject negative quantity
2
+
3
+ - **Discipline:** back end
4
+ - **Owns:** `lib/cart.rb`, `spec/cart_spec.rb`
5
+ - **Must not touch:** `Gemfile`
6
+ - **Depends on:** nothing
7
+ - **Done when:** `spec/cart_spec.rb` "rejects a negative quantity" passes
@@ -0,0 +1 @@
1
+ No front-end work in this plan.
@@ -0,0 +1,3 @@
1
+ # Plan
2
+
3
+ 1. U1 Reject negative quantity (back end). Integration: U1's spec.
@@ -0,0 +1,8 @@
1
+ # Pull Requests
2
+
3
+ `bundle exec rspec` — 2 examples, 0 failures.
4
+
5
+ > [!NOTE]
6
+ >
7
+ > [2026-09-04 02:00:00 PM PDT] [ agent: luke-backend status: Started, round 1 ]
8
+ > [2026-09-04 02:11:20 PM PDT] [ agent: luke-backend status: Completed, round 1 ]
@@ -0,0 +1,8 @@
1
+ ---
2
+ frontend: false
3
+ ---
4
+ # Negative Quantity
5
+
6
+ ## Goal
7
+
8
+ `Cart#add` rejects a quantity below 1.
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gem "rspec"
@@ -0,0 +1,11 @@
1
+ class Cart
2
+ class InvalidQuantity < ArgumentError; end
3
+
4
+ def initialize = @lines = {}
5
+
6
+ def add(sku, quantity)
7
+ raise InvalidQuantity, "quantity must be at least 1, got #{quantity}" if quantity < 1
8
+
9
+ @lines[sku] = quantity
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "../lib/cart"
2
+
3
+ RSpec.describe Cart do
4
+ it "adds a line" do
5
+ expect(described_class.new.add("A1", 2)).to eq(2)
6
+ end
7
+
8
+ it "rejects a negative quantity" do
9
+ expect { described_class.new.add("A1", -1) }.to raise_error(Cart::InvalidQuantity)
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ {"seconds": 680, "tokens": 142000}
@@ -0,0 +1,68 @@
1
+ id: build-medium
2
+ agent: luke-backend
3
+ depth: medium
4
+ description: >
5
+ One back-end unit: reject a negative quantity in Cart#add, with a test.
6
+ The folder's 🟢 needs a published pull request, which an eval never opens,
7
+ so this case checks the signature and the diff: code and its test changed,
8
+ nothing outside the unit's files touched.
9
+ fixture:
10
+ state: planned
11
+ slug: negative-quantity
12
+ files:
13
+ spec.md: |
14
+ ---
15
+ frontend: false
16
+ ---
17
+ # Negative Quantity
18
+
19
+ ## Goal
20
+
21
+ `Cart#add` rejects a quantity below 1.
22
+ plan.md: |
23
+ # Plan
24
+
25
+ 1. U1 Reject negative quantity (back end). Integration: U1's spec.
26
+ plan-backend.md: |
27
+ ## U1 Reject negative quantity
28
+
29
+ - **Discipline:** back end
30
+ - **Owns:** `lib/cart.rb`, `spec/cart_spec.rb`
31
+ - **Must not touch:** `Gemfile`
32
+ - **Depends on:** nothing
33
+ - **Done when:** `spec/cart_spec.rb` "rejects a negative quantity" passes
34
+ plan-frontend.md: |
35
+ No front-end work in this plan.
36
+ repo:
37
+ Gemfile: |
38
+ source "https://rubygems.org"
39
+ gem "rspec"
40
+ lib/cart.rb: |
41
+ class Cart
42
+ def initialize = @lines = {}
43
+
44
+ def add(sku, quantity)
45
+ @lines[sku] = quantity
46
+ end
47
+ end
48
+ spec/cart_spec.rb: |
49
+ require_relative "../lib/cart"
50
+
51
+ RSpec.describe Cart do
52
+ it "adds a line" do
53
+ expect(described_class.new.add("A1", 2)).to eq(2)
54
+ end
55
+ end
56
+ expect:
57
+ signed: true
58
+ files_exist: [pull-requests.md]
59
+ contains:
60
+ pull-requests.md: ["# Pull Requests"]
61
+ changed_paths: [lib/**/*.rb, spec/**/*_spec.rb]
62
+ untouched: [Gemfile]
63
+ depth:
64
+ medium:
65
+ changed_files: { min: 2, max: 6 }
66
+ changed_lines: { min: 4, max: 200 }
67
+ max_seconds: 1200
68
+ max_tokens: 250000
@@ -0,0 +1,6 @@
1
+ ## U1 Everything
2
+
3
+ - **Discipline:** back end
4
+ - **Owns:** `lib/`
5
+ - **Depends on:** nothing
6
+ - **Done when:** tests pass
@@ -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: palpatine-planner status: Started, round 1 ]
8
+ > [2026-09-04 01:14:30 PM PDT] [ agent: palpatine-planner status: Completed, round 1 ]
@@ -0,0 +1,14 @@
1
+ ---
2
+ frontend: false
3
+ ---
4
+ # Duplicate Job IDs
5
+
6
+ ## Goal
7
+
8
+ The job queue refuses a job whose ID is already queued, and says which job holds it.
9
+
10
+ ## In scope
11
+
12
+ - `Queue#push` rejects a duplicate ID with `Queue::Duplicate`.
13
+ - The worker logs the rejected ID and the holder.
14
+ - `config/queue.yml` gains `dedupe: true`, read by both.
@@ -0,0 +1 @@
1
+ {"seconds": 64, "tokens": 15100, "state": "planned"}
@@ -0,0 +1,32 @@
1
+ ## U1 Dedupe setting
2
+
3
+ - **Discipline:** back end
4
+ - **Owns:** `config/queue.yml`, `lib/queue/config.rb`, `spec/queue/config_spec.rb`
5
+ - **Must not touch:** `lib/queue.rb`, `lib/worker.rb`
6
+ - **Depends on:** nothing
7
+ - **Done when:** `spec/queue/config_spec.rb` passes
8
+
9
+ ## U2 Reject duplicates
10
+
11
+ - **Discipline:** back end
12
+ - **Owns:** `lib/queue.rb`, `spec/queue_spec.rb`
13
+ - **Must not touch:** `config/queue.yml`, `lib/worker.rb`
14
+ - **Depends on:** U1
15
+ - **Done when:** `spec/queue_spec.rb` "rejects a duplicate id" passes
16
+
17
+ ## U3 Worker logging
18
+
19
+ - **Discipline:** back end
20
+ - **Owns:** `lib/worker.rb`, `spec/worker_spec.rb`
21
+ - **Must not touch:** `config/queue.yml`, `lib/queue.rb`
22
+ - **Depends on:** U1
23
+ - **Done when:** `spec/worker_spec.rb` "logs the holder" passes
24
+
25
+ ## U4 Integration check
26
+
27
+ - **Discipline:** back end
28
+ - **Owns:** `spec/integration/dedupe_spec.rb`
29
+ - **Must not touch:** every other file
30
+ - **Depends on:** U2, U3
31
+ - **Done when:** `spec/integration/dedupe_spec.rb` passes with nothing stubbed
32
+
@@ -0,0 +1 @@
1
+ No front-end work in this plan.
@@ -0,0 +1,28 @@
1
+ # Plan
2
+
3
+ Four back-end units. `config/queue.yml` is written by U1 only; U2 and U3 read it, so they follow U1. U4 is the integration check.
4
+
5
+ ## Units
6
+
7
+ 1. U1 Dedupe setting: adds `dedupe: true` to `config/queue.yml` and `Queue::Config#dedupe?`.
8
+ 2. U2 Reject duplicates: `Queue#push` raises `Queue::Duplicate` naming the holder.
9
+ 3. U3 Worker logging: the worker rescues `Queue::Duplicate` and logs both IDs.
10
+ 4. U4 Integration check: push the same ID twice through a real queue and worker, nothing stubbed; it must show one job run, one rejection logged with the holder's ID.
11
+
12
+ ## Dependency graph
13
+
14
+ U1 → U2 → U4, and U1 → U3 → U4. U2 and U3 own disjoint files and may run at the same time.
15
+
16
+ ## Signatures
17
+
18
+ - `Queue#push(job) → Job`, raises `Queue::Duplicate(id:, holder:)`.
19
+ - `Queue::Config#dedupe? → Boolean`.
20
+
21
+ ## Risks
22
+
23
+ - U2 and U3 both read the setting; if U1 slips, both wait. Nothing else is shared.
24
+
25
+ > [!NOTE]
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 ]
@@ -0,0 +1,14 @@
1
+ ---
2
+ frontend: false
3
+ ---
4
+ # Duplicate Job IDs
5
+
6
+ ## Goal
7
+
8
+ The job queue refuses a job whose ID is already queued, and says which job holds it.
9
+
10
+ ## In scope
11
+
12
+ - `Queue#push` rejects a duplicate ID with `Queue::Duplicate`.
13
+ - The worker logs the rejected ID and the holder.
14
+ - `config/queue.yml` gains `dedupe: true`, read by both.
@@ -0,0 +1 @@
1
+ {"seconds": 402, "tokens": 128700, "state": "planned"}
@@ -0,0 +1,50 @@
1
+ id: plan-deep
2
+ agent: palpatine-planner
3
+ depth: deep
4
+ description: >
5
+ A spec with a shared file and three in-scope items. At deep depth the plan
6
+ must split it into several units with ownership, ordering for the shared
7
+ file and a named integration check; a single vague unit is too shallow.
8
+ fixture:
9
+ state: ready_for_planning
10
+ slug: duplicate-job-ids
11
+ files:
12
+ spec.md: |
13
+ ---
14
+ frontend: false
15
+ ---
16
+ # Duplicate Job IDs
17
+
18
+ ## Goal
19
+
20
+ The job queue refuses a job whose ID is already queued, and says which job holds it.
21
+
22
+ ## In scope
23
+
24
+ - `Queue#push` rejects a duplicate ID with `Queue::Duplicate`.
25
+ - The worker logs the rejected ID and the holder.
26
+ - `config/queue.yml` gains `dedupe: true`, read by both.
27
+ plan.md: ""
28
+ expect:
29
+ state: planned
30
+ signed: true
31
+ files_exist: [plan.md, plan-backend.md, plan-frontend.md]
32
+ contains:
33
+ plan.md: ["/[Ii]ntegration/"]
34
+ plan-backend.md: ["Owns:", "Must not touch:", "Depends on:", "Done when:"]
35
+ depth:
36
+ fast:
37
+ count: { file: plan-backend.md, pattern: "Discipline:", min: 1, max: 3 }
38
+ words: { file: plan.md, max: 300 }
39
+ max_seconds: 300
40
+ max_tokens: 80000
41
+ medium:
42
+ count: { file: plan-backend.md, pattern: "Discipline:", min: 2, max: 6 }
43
+ words: { file: plan.md, min: 80, max: 1200 }
44
+ max_seconds: 450
45
+ max_tokens: 150000
46
+ deep:
47
+ count: { file: plan-backend.md, pattern: "Discipline:", min: 3, max: 8 }
48
+ words: { file: plan.md, min: 150, max: 2500 }
49
+ max_seconds: 600
50
+ max_tokens: 300000
@@ -0,0 +1,48 @@
1
+ ## U1 Step 1
2
+
3
+ - **Discipline:** back end
4
+ - **Owns:** `lib/creator/step_1.rb`
5
+ - **Must not touch:** `lib/cli.rb`
6
+ - **Depends on:** nothing
7
+ - **Done when:** `spec/creator/step_1_spec.rb` passes
8
+
9
+ ## U2 Step 2
10
+
11
+ - **Discipline:** back end
12
+ - **Owns:** `lib/creator/step_2.rb`
13
+ - **Must not touch:** `lib/cli.rb`
14
+ - **Depends on:** nothing
15
+ - **Done when:** `spec/creator/step_2_spec.rb` passes
16
+
17
+ ## U3 Step 3
18
+
19
+ - **Discipline:** back end
20
+ - **Owns:** `lib/creator/step_3.rb`
21
+ - **Must not touch:** `lib/cli.rb`
22
+ - **Depends on:** nothing
23
+ - **Done when:** `spec/creator/step_3_spec.rb` passes
24
+
25
+ ## U4 Step 4
26
+
27
+ - **Discipline:** back end
28
+ - **Owns:** `lib/creator/step_4.rb`
29
+ - **Must not touch:** `lib/cli.rb`
30
+ - **Depends on:** nothing
31
+ - **Done when:** `spec/creator/step_4_spec.rb` passes
32
+
33
+ ## U5 Step 5
34
+
35
+ - **Discipline:** back end
36
+ - **Owns:** `lib/creator/step_5.rb`
37
+ - **Must not touch:** `lib/cli.rb`
38
+ - **Depends on:** nothing
39
+ - **Done when:** `spec/creator/step_5_spec.rb` passes
40
+
41
+ ## U6 Step 6
42
+
43
+ - **Discipline:** back end
44
+ - **Owns:** `lib/creator/step_6.rb`
45
+ - **Must not touch:** `lib/cli.rb`
46
+ - **Depends on:** nothing
47
+ - **Done when:** `spec/creator/step_6_spec.rb` passes
48
+
@@ -0,0 +1 @@
1
+ No front-end work in this plan.
@@ -0,0 +1,12 @@
1
+ # Plan
2
+
3
+ Six units, U6 is the integration check.
4
+
5
+ ## Order
6
+
7
+ U1, then U2 to U5 in parallel, then U6.
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 ]