diff --git a/.beads/backup/backup_state.json b/.beads/backup/backup_state.json index 5851c5053..e9c80319f 100644 --- a/.beads/backup/backup_state.json +++ b/.beads/backup/backup_state.json @@ -1,13 +1,13 @@ { - "last_dolt_commit": "ktiu0av8v39qp1ru6imjag7jd2shfbja", + "last_dolt_commit": "8ekhhjbsq6t920lt8fma52lkf8of2sp0", "last_event_id": 0, - "timestamp": "2026-03-10T04:25:42.936336Z", + "timestamp": "2026-03-10T11:16:17.571691Z", "counts": { - "issues": 2423, - "events": 19270, + "issues": 2452, + "events": 19411, "comments": 3400, - "dependencies": 1862, - "labels": 3697, + "dependencies": 1895, + "labels": 3781, "config": 11 } } \ No newline at end of file diff --git a/.beads/backup/dependencies.jsonl b/.beads/backup/dependencies.jsonl index 351c008aa..d9f245b03 100644 --- a/.beads/backup/dependencies.jsonl +++ b/.beads/backup/dependencies.jsonl @@ -47,6 +47,7 @@ {"created_at":"2026-02-19T21:37:24Z","created_by":"Dan Abrams","depends_on_id":"gromit-la8u4","issue_id":"gromit-166sc","type":"blocks"} {"created_at":"2026-02-05T20:00:03Z","created_by":"Dan Abrams","depends_on_id":"gromit-q19","issue_id":"gromit-16d","type":"blocks"} {"created_at":"2026-02-19T10:04:59Z","created_by":"Dan Abrams","depends_on_id":"gromit-ejjc3","issue_id":"gromit-16zu4","type":"blocks"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-r9zlh","issue_id":"gromit-181wx","type":"blocks"} {"created_at":"2026-03-08T00:20:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-4h10x","issue_id":"gromit-187wy","type":"blocks"} {"created_at":"2026-02-22T21:20:30Z","created_by":"Dan Abrams","depends_on_id":"gromit-rvnu2","issue_id":"gromit-18sei","type":"blocks"} {"created_at":"2026-02-23T02:10:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-18sei","issue_id":"gromit-18sei.1","type":"parent-child"} @@ -118,8 +119,12 @@ {"created_at":"2026-02-13T15:52:37Z","created_by":"Dan Abrams","depends_on_id":"gromit-jz5w","issue_id":"gromit-2mbe","type":"blocks"} {"created_at":"2026-02-07T04:50:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-5vs","issue_id":"gromit-2ns","type":"blocks"} {"created_at":"2026-02-07T04:50:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-jyf","issue_id":"gromit-2ns","type":"blocks"} +{"created_at":"2026-03-10T00:50:02Z","created_by":"Dan Abrams","depends_on_id":"gromit-8c38m","issue_id":"gromit-2octl","type":"blocks"} {"created_at":"2026-03-08T07:51:48Z","created_by":"Dan Abrams","depends_on_id":"gromit-ksj6x","issue_id":"gromit-2opey","type":"blocks"} {"created_at":"2026-02-07T05:48:27Z","created_by":"Dan Abrams","depends_on_id":"gromit-3eg","issue_id":"gromit-2pm","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-k1iky","issue_id":"gromit-2q0ft","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-p24bl","issue_id":"gromit-2q0ft","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-zs7g7","issue_id":"gromit-2q0ft","type":"blocks"} {"created_at":"2026-02-05T19:45:43Z","created_by":"Dan Abrams","depends_on_id":"gromit-dfe","issue_id":"gromit-2qv","type":"blocks"} {"created_at":"2026-02-06T22:25:41Z","created_by":"Dan Abrams","depends_on_id":"gromit-okv","issue_id":"gromit-2s5","type":"parent-child"} {"created_at":"2026-02-05T20:01:03Z","created_by":"Dan Abrams","depends_on_id":"gromit-bvo","issue_id":"gromit-2sj","type":"blocks"} @@ -157,6 +162,7 @@ {"created_at":"2026-03-08T16:47:55Z","created_by":"Dan Abrams","depends_on_id":"gromit-spzax","issue_id":"gromit-3hde3","type":"blocks"} {"created_at":"2026-03-08T16:47:55Z","created_by":"Dan Abrams","depends_on_id":"gromit-vre3h","issue_id":"gromit-3hde3","type":"blocks"} {"created_at":"2026-03-08T16:47:54Z","created_by":"Dan Abrams","depends_on_id":"gromit-vre3h","issue_id":"gromit-3i1ko","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-b39ja","issue_id":"gromit-3i6ff","type":"blocks"} {"created_at":"2026-03-08T00:20:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-4h10x","issue_id":"gromit-3jjty","type":"blocks"} {"created_at":"2026-02-21T15:04:22Z","created_by":"Dan Abrams","depends_on_id":"gromit-pkloh","issue_id":"gromit-3jtuq","type":"blocks"} {"created_at":"2026-02-19T19:42:41Z","created_by":"Dan Abrams","depends_on_id":"gromit-9xmm1","issue_id":"gromit-3la54","type":"blocks"} @@ -227,6 +233,7 @@ {"created_at":"2026-02-11T07:04:38Z","created_by":"Dan Abrams","depends_on_id":"gromit-s7hk","issue_id":"gromit-4yrb","type":"blocks"} {"created_at":"2026-03-09T16:02:25Z","created_by":"Dan Abrams","depends_on_id":"gromit-t6zsi","issue_id":"gromit-4zfv6","type":"blocks"} {"created_at":"2026-02-07T18:27:23Z","created_by":"Dan Abrams","depends_on_id":"gromit-ieh","issue_id":"gromit-4zg","type":"blocks"} +{"created_at":"2026-03-10T00:50:02Z","created_by":"Dan Abrams","depends_on_id":"gromit-y67or","issue_id":"gromit-50wzq","type":"blocks"} {"created_at":"2026-02-07T05:48:27Z","created_by":"Dan Abrams","depends_on_id":"gromit-3y6","issue_id":"gromit-51s","type":"blocks"} {"created_at":"2026-02-07T05:48:27Z","created_by":"Dan Abrams","depends_on_id":"gromit-xe0","issue_id":"gromit-51s","type":"blocks"} {"created_at":"2026-02-19T10:05:05Z","created_by":"Dan Abrams","depends_on_id":"gromit-16zu4","issue_id":"gromit-51t64","type":"blocks"} @@ -324,6 +331,7 @@ {"created_at":"2026-02-19T19:42:45Z","created_by":"Dan Abrams","depends_on_id":"gromit-kyknq","issue_id":"gromit-75zeo","type":"blocks"} {"created_at":"2026-02-19T19:42:45Z","created_by":"Dan Abrams","depends_on_id":"gromit-retjh","issue_id":"gromit-75zeo","type":"blocks"} {"created_at":"2026-02-07T05:54:37Z","created_by":"Dan Abrams","depends_on_id":"gromit-tnc","issue_id":"gromit-76o","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-veios","issue_id":"gromit-78vah","type":"blocks"} {"created_at":"2026-03-04T13:02:42Z","created_by":"Dan Abrams","depends_on_id":"gromit-791l5","issue_id":"gromit-791l5.1","type":"parent-child"} {"created_at":"2026-03-04T13:02:42Z","created_by":"Dan Abrams","depends_on_id":"gromit-791l5","issue_id":"gromit-791l5.2","type":"parent-child"} {"created_at":"2026-02-08T09:09:44Z","created_by":"Dan Abrams","depends_on_id":"gromit-k9mi","issue_id":"gromit-7dcu","type":"blocks"} @@ -492,6 +500,9 @@ {"created_at":"2026-03-08T17:51:57Z","created_by":"Dan Abrams","depends_on_id":"gromit-mxfo3","issue_id":"gromit-7obu9","type":"blocks"} {"created_at":"2026-02-11T09:27:33Z","created_by":"Dan Abrams","depends_on_id":"gromit-vujh","issue_id":"gromit-7oob","type":"blocks"} {"created_at":"2026-02-12T12:00:41Z","created_by":"Dan Abrams","depends_on_id":"gromit-gobj","issue_id":"gromit-7qr9","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-2q0ft","issue_id":"gromit-7t6ch","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-78vah","issue_id":"gromit-7t6ch","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-o8uk4","issue_id":"gromit-7t6ch","type":"blocks"} {"created_at":"2026-02-06T22:43:29Z","created_by":"Dan Abrams","depends_on_id":"gromit-g1x","issue_id":"gromit-7uf","type":"parent-child"} {"created_at":"2026-03-08T09:37:57Z","created_by":"Dan Abrams","depends_on_id":"gromit-0k6x4","issue_id":"gromit-7v10e","type":"blocks"} {"created_at":"2026-02-07T11:47:13Z","created_by":"Dan Abrams","depends_on_id":"gromit-5wx","issue_id":"gromit-7v4","type":"blocks"} @@ -526,6 +537,7 @@ {"created_at":"2026-02-20T17:51:01Z","created_by":"Dan Abrams","depends_on_id":"gromit-85lh","issue_id":"gromit-85lh.4","type":"parent-child"} {"created_at":"2026-02-15T19:54:31Z","created_by":"Dan Abrams","depends_on_id":"gromit-edz8","issue_id":"gromit-86vp","type":"blocks"} {"created_at":"2026-02-14T09:39:01Z","created_by":"Dan Abrams","depends_on_id":"gromit-pngg","issue_id":"gromit-8acg","type":"blocks"} +{"created_at":"2026-03-10T00:50:02Z","created_by":"Dan Abrams","depends_on_id":"gromit-y67or","issue_id":"gromit-8c38m","type":"blocks"} {"created_at":"2026-03-09T17:26:49Z","created_by":"Dan Abrams","depends_on_id":"gromit-jyqo9","issue_id":"gromit-8co7o","type":"discovered-from"} {"created_at":"2026-02-12T17:55:41Z","created_by":"Dan Abrams","depends_on_id":"gromit-irc6","issue_id":"gromit-8d1c","type":"blocks"} {"created_at":"2026-02-06T22:43:29Z","created_by":"Dan Abrams","depends_on_id":"gromit-twl","issue_id":"gromit-8du","type":"parent-child"} @@ -657,6 +669,7 @@ {"created_at":"2026-02-14T10:25:40Z","created_by":"Dan Abrams","depends_on_id":"gromit-snap","issue_id":"gromit-b002","type":"blocks"} {"created_at":"2026-02-18T18:21:37Z","created_by":"Dan Abrams","depends_on_id":"gromit-8n1hv","issue_id":"gromit-b0a3c","type":"blocks"} {"created_at":"2026-02-07T11:47:13Z","created_by":"Dan Abrams","depends_on_id":"gromit-vst","issue_id":"gromit-b1w","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-2q0ft","issue_id":"gromit-b39ja","type":"blocks"} {"created_at":"2026-03-07T10:06:50Z","created_by":"Dan Abrams","depends_on_id":"gromit-o1fk9","issue_id":"gromit-b582a","type":"blocks"} {"created_at":"2026-03-06T23:03:40Z","created_by":"Dan Abrams","depends_on_id":"gromit-ns5fp","issue_id":"gromit-b5p6k","type":"blocks"} {"created_at":"2026-03-06T23:03:40Z","created_by":"Dan Abrams","depends_on_id":"gromit-ziybi","issue_id":"gromit-b5p6k","type":"blocks"} @@ -675,6 +688,9 @@ {"created_at":"2026-02-19T21:37:25Z","created_by":"Dan Abrams","depends_on_id":"gromit-piyea","issue_id":"gromit-bf100","type":"blocks"} {"created_at":"2026-02-19T21:37:25Z","created_by":"Dan Abrams","depends_on_id":"gromit-t1rh9","issue_id":"gromit-bf100","type":"blocks"} {"created_at":"2026-02-07T08:38:38Z","created_by":"Dan Abrams","depends_on_id":"gromit-def","issue_id":"gromit-bkk","type":"blocks"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-ce7ua","issue_id":"gromit-bkqc6","type":"blocks"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-k7gel","issue_id":"gromit-bkqc6","type":"blocks"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-rmmaq","issue_id":"gromit-bkqc6","type":"blocks"} {"created_at":"2026-02-07T04:50:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-8qq","issue_id":"gromit-bky","type":"blocks"} {"created_at":"2026-02-06T13:41:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-n7m","issue_id":"gromit-bl8","type":"parent-child"} {"created_at":"2026-02-06T22:03:52Z","created_by":"Dan Abrams","depends_on_id":"gromit-1sn","issue_id":"gromit-bo6","type":"parent-child"} @@ -700,6 +716,7 @@ {"created_at":"2026-02-07T05:48:27Z","created_by":"Dan Abrams","depends_on_id":"gromit-2pm","issue_id":"gromit-cc9","type":"blocks"} {"created_at":"2026-02-07T05:48:27Z","created_by":"Dan Abrams","depends_on_id":"gromit-3eg","issue_id":"gromit-cc9","type":"blocks"} {"created_at":"2026-02-06T09:29:33Z","created_by":"Dan Abrams","depends_on_id":"gromit-csr","issue_id":"gromit-ce1","type":"parent-child"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-rmmaq","issue_id":"gromit-ce7ua","type":"blocks"} {"created_at":"2026-03-08T07:51:47Z","created_by":"Dan Abrams","depends_on_id":"gromit-ic6w4","issue_id":"gromit-cfepn","type":"blocks"} {"created_at":"2026-03-08T07:51:47Z","created_by":"Dan Abrams","depends_on_id":"gromit-mo15p","issue_id":"gromit-cfepn","type":"blocks"} {"created_at":"2026-02-07T05:54:37Z","created_by":"Dan Abrams","depends_on_id":"gromit-nmh","issue_id":"gromit-cfh","type":"blocks"} @@ -868,6 +885,7 @@ {"created_at":"2026-02-16T02:27:04Z","created_by":"Dan Abrams","depends_on_id":"gromit-4i8u","issue_id":"gromit-el7d","type":"blocks"} {"created_at":"2026-02-08T08:10:56Z","created_by":"Dan Abrams","depends_on_id":"gromit-81bz","issue_id":"gromit-elej","type":"blocks"} {"created_at":"2026-02-18T18:21:34Z","created_by":"Dan Abrams","depends_on_id":"gromit-0gvd3","issue_id":"gromit-elmd4","type":"blocks"} +{"created_at":"2026-03-10T06:06:11Z","created_by":"Dan Abrams","depends_on_id":"gromit-r9zlh","issue_id":"gromit-en4ct","type":"discovered-from"} {"created_at":"2026-02-18T18:21:35Z","created_by":"Dan Abrams","depends_on_id":"gromit-0gvd3","issue_id":"gromit-es1tn","type":"blocks"} {"created_at":"2026-02-18T18:04:54Z","created_by":"Dan Abrams","depends_on_id":"gromit-31oar","issue_id":"gromit-etfv9","type":"blocks"} {"created_at":"2026-02-18T18:04:54Z","created_by":"Dan Abrams","depends_on_id":"gromit-c8tax","issue_id":"gromit-etfv9","type":"blocks"} @@ -901,6 +919,7 @@ {"created_at":"2026-02-16T18:38:56Z","created_by":"Dan Abrams","depends_on_id":"gromit-f8x2.3","issue_id":"gromit-f8x2.3.2","type":"parent-child"} {"created_at":"2026-02-16T18:38:57Z","created_by":"Dan Abrams","depends_on_id":"gromit-f8x2.3","issue_id":"gromit-f8x2.3.3","type":"parent-child"} {"created_at":"2026-02-18T18:21:39Z","created_by":"Dan Abrams","depends_on_id":"gromit-sonqy","issue_id":"gromit-f95ip","type":"blocks"} +{"created_at":"2026-03-10T00:50:01Z","created_by":"Dan Abrams","depends_on_id":"gromit-y67or","issue_id":"gromit-f99rv","type":"blocks"} {"created_at":"2026-03-07T10:06:47Z","created_by":"Dan Abrams","depends_on_id":"gromit-4ot02","issue_id":"gromit-f9c0p","type":"blocks"} {"created_at":"2026-02-13T21:04:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-ug5e","issue_id":"gromit-fa4v","type":"blocks"} {"created_at":"2026-02-16T15:43:47Z","created_by":"Dan Abrams","depends_on_id":"gromit-8ks7","issue_id":"gromit-fdak","type":"blocks"} @@ -984,6 +1003,7 @@ {"created_at":"2026-02-18T16:58:04Z","created_by":"Dan Abrams","depends_on_id":"gromit-tv7a","issue_id":"gromit-h94d","type":"blocks"} {"created_at":"2026-02-18T17:50:13Z","created_by":"Dan Abrams","depends_on_id":"gromit-85z2x","issue_id":"gromit-h9m4w","type":"blocks"} {"created_at":"2026-03-09T07:55:29Z","created_by":"Dan Abrams","depends_on_id":"gromit-soe06","issue_id":"gromit-hab86","type":"blocks"} +{"created_at":"2026-03-10T05:24:05Z","created_by":"Dan Abrams","depends_on_id":"gromit-rmmaq","issue_id":"gromit-hcio0","type":"blocks"} {"created_at":"2026-02-08T08:10:56Z","created_by":"Dan Abrams","depends_on_id":"gromit-81bz","issue_id":"gromit-hgu3","type":"blocks"} {"created_at":"2026-02-08T08:10:56Z","created_by":"Dan Abrams","depends_on_id":"gromit-elej","issue_id":"gromit-hgu3","type":"blocks"} {"created_at":"2026-03-02T20:19:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-hj49d","issue_id":"gromit-hj49d.1","type":"parent-child"} @@ -1103,6 +1123,7 @@ {"created_at":"2026-02-22T20:30:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-jzqqu","issue_id":"gromit-jzqqu.1","type":"parent-child"} {"created_at":"2026-02-22T20:30:07Z","created_by":"Dan Abrams","depends_on_id":"gromit-jzqqu","issue_id":"gromit-jzqqu.2","type":"parent-child"} {"created_at":"2026-02-22T20:30:08Z","created_by":"Dan Abrams","depends_on_id":"gromit-jzqqu","issue_id":"gromit-jzqqu.3","type":"parent-child"} +{"created_at":"2026-03-10T06:39:18Z","created_by":"Dan Abrams","depends_on_id":"gromit-veios","issue_id":"gromit-k1iky","type":"blocks"} {"created_at":"2026-02-19T18:22:23Z","created_by":"Dan Abrams","depends_on_id":"gromit-35lia","issue_id":"gromit-k1nj4","type":"blocks"} {"created_at":"2026-02-19T18:22:23Z","created_by":"Dan Abrams","depends_on_id":"gromit-mua95","issue_id":"gromit-k1nj4","type":"blocks"} {"created_at":"2026-02-07T05:54:37Z","created_by":"Dan Abrams","depends_on_id":"gromit-ypk","issue_id":"gromit-k3j","type":"blocks"} @@ -1111,6 +1132,7 @@ {"created_at":"2026-02-19T19:37:11Z","created_by":"Dan Abrams","depends_on_id":"gromit-k5lbt","issue_id":"gromit-k5lbt.1","type":"parent-child"} {"created_at":"2026-02-19T19:37:12Z","created_by":"Dan Abrams","depends_on_id":"gromit-k5lbt","issue_id":"gromit-k5lbt.2","type":"parent-child"} {"created_at":"2026-02-19T19:37:12Z","created_by":"Dan Abrams","depends_on_id":"gromit-k5lbt","issue_id":"gromit-k5lbt.3","type":"parent-child"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-rmmaq","issue_id":"gromit-k7gel","type":"blocks"} {"created_at":"2026-02-08T09:09:11Z","created_by":"Dan Abrams","depends_on_id":"gromit-laoe","issue_id":"gromit-k9mi","type":"blocks"} {"created_at":"2026-02-22T21:20:27Z","created_by":"Dan Abrams","depends_on_id":"gromit-rt0rc","issue_id":"gromit-k9qyt","type":"blocks"} {"created_at":"2026-02-23T02:08:33Z","created_by":"Dan Abrams","depends_on_id":"gromit-k9qyt","issue_id":"gromit-k9qyt.1","type":"parent-child"} @@ -1138,6 +1160,7 @@ {"created_at":"2026-02-21T08:35:01Z","created_by":"Dan Abrams","depends_on_id":"gromit-kkss1","issue_id":"gromit-kkss1.1","type":"parent-child"} {"created_at":"2026-02-21T08:35:02Z","created_by":"Dan Abrams","depends_on_id":"gromit-kkss1","issue_id":"gromit-kkss1.2","type":"parent-child"} {"created_at":"2026-02-21T08:35:03Z","created_by":"Dan Abrams","depends_on_id":"gromit-kkss1","issue_id":"gromit-kkss1.3","type":"parent-child"} +{"created_at":"2026-03-10T00:50:02Z","created_by":"Dan Abrams","depends_on_id":"gromit-8c38m","issue_id":"gromit-klkbj","type":"blocks"} {"created_at":"2026-02-06T22:43:30Z","created_by":"Dan Abrams","depends_on_id":"gromit-ehg","issue_id":"gromit-kox","type":"parent-child"} {"created_at":"2026-02-19T19:42:44Z","created_by":"Dan Abrams","depends_on_id":"gromit-9xmm1","issue_id":"gromit-kqle0","type":"blocks"} {"created_at":"2026-02-19T19:42:44Z","created_by":"Dan Abrams","depends_on_id":"gromit-ob8zn","issue_id":"gromit-kqle0","type":"blocks"} @@ -1304,6 +1327,8 @@ {"created_at":"2026-03-09T10:45:14Z","created_by":"Dan Abrams","depends_on_id":"gromit-s8gtb","issue_id":"gromit-nw3wu","type":"blocks"} {"created_at":"2026-02-22T04:26:20Z","created_by":"Dan Abrams","depends_on_id":"gromit-5x41e","issue_id":"gromit-nwe9y","type":"blocks"} {"created_at":"2026-02-05T11:49:07Z","created_by":"Dan Abrams","depends_on_id":"gromit-btj","issue_id":"gromit-nwl","type":"parent-child"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-hcio0","issue_id":"gromit-nxhpg","type":"blocks"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-r9zlh","issue_id":"gromit-nxhpg","type":"blocks"} {"created_at":"2026-02-21T15:04:38Z","created_by":"Dan Abrams","depends_on_id":"gromit-iqoj4","issue_id":"gromit-o13m2","type":"blocks"} {"created_at":"2026-03-07T10:06:49Z","created_by":"Dan Abrams","depends_on_id":"gromit-49evc","issue_id":"gromit-o1fk9","type":"blocks"} {"created_at":"2026-03-07T10:06:49Z","created_by":"Dan Abrams","depends_on_id":"gromit-b6ztp","issue_id":"gromit-o1fk9","type":"blocks"} @@ -1319,6 +1344,7 @@ {"created_at":"2026-02-08T17:00:34Z","created_by":"Dan Abrams","depends_on_id":"gromit-ll2l","issue_id":"gromit-o5py","type":"blocks"} {"created_at":"2026-02-08T17:00:34Z","created_by":"Dan Abrams","depends_on_id":"gromit-mzmb","issue_id":"gromit-o5py","type":"blocks"} {"created_at":"2026-02-18T22:51:48Z","created_by":"Dan Abrams","depends_on_id":"gromit-0jhei","issue_id":"gromit-o869e","type":"blocks"} +{"created_at":"2026-03-10T06:39:19Z","created_by":"Dan Abrams","depends_on_id":"gromit-78vah","issue_id":"gromit-o8uk4","type":"blocks"} {"created_at":"2026-02-21T15:04:01Z","created_by":"Dan Abrams","depends_on_id":"gromit-rmzva","issue_id":"gromit-oa7pl","type":"blocks"} {"created_at":"2026-03-08T17:51:57Z","created_by":"Dan Abrams","depends_on_id":"gromit-34ozp","issue_id":"gromit-oangl","type":"blocks"} {"created_at":"2026-03-08T17:51:57Z","created_by":"Dan Abrams","depends_on_id":"gromit-j8xke","issue_id":"gromit-oangl","type":"blocks"} @@ -1359,6 +1385,7 @@ {"created_at":"2026-02-22T22:24:13Z","created_by":"Dan Abrams","depends_on_id":"gromit-p0iei","issue_id":"gromit-p0iei.3","type":"parent-child"} {"created_at":"2026-02-22T22:24:14Z","created_by":"Dan Abrams","depends_on_id":"gromit-p0iei","issue_id":"gromit-p0iei.4","type":"parent-child"} {"created_at":"2026-03-09T07:55:30Z","created_by":"Dan Abrams","depends_on_id":"gromit-uiwwh","issue_id":"gromit-p1t55","type":"blocks"} +{"created_at":"2026-03-10T06:39:18Z","created_by":"Dan Abrams","depends_on_id":"gromit-veios","issue_id":"gromit-p24bl","type":"blocks"} {"created_at":"2026-02-06T22:43:29Z","created_by":"Dan Abrams","depends_on_id":"gromit-g1x","issue_id":"gromit-p2a","type":"parent-child"} {"created_at":"2026-03-09T01:50:41Z","created_by":"Dan Abrams","depends_on_id":"gromit-m2tgq","issue_id":"gromit-p3akg","type":"discovered-from"} {"created_at":"2026-02-13T15:53:13Z","created_by":"Dan Abrams","depends_on_id":"gromit-jz5w","issue_id":"gromit-p467","type":"blocks"} @@ -1420,6 +1447,8 @@ {"created_at":"2026-02-05T20:00:03Z","created_by":"Dan Abrams","depends_on_id":"gromit-cmw","issue_id":"gromit-q19","type":"blocks"} {"created_at":"2026-02-19T18:27:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-61692","issue_id":"gromit-q1k8n","type":"blocks"} {"created_at":"2026-02-07T22:39:04Z","created_by":"Dan Abrams","depends_on_id":"gromit-9ckj","issue_id":"gromit-q224","type":"blocks"} +{"created_at":"2026-03-10T06:39:20Z","created_by":"Dan Abrams","depends_on_id":"gromit-3i6ff","issue_id":"gromit-q436q","type":"blocks"} +{"created_at":"2026-03-10T06:39:20Z","created_by":"Dan Abrams","depends_on_id":"gromit-b39ja","issue_id":"gromit-q436q","type":"blocks"} {"created_at":"2026-02-07T23:36:10Z","created_by":"Dan Abrams","depends_on_id":"gromit-b61o","issue_id":"gromit-q4l8","type":"blocks"} {"created_at":"2026-02-19T19:42:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-4fhlk","issue_id":"gromit-q6ctg","type":"blocks"} {"created_at":"2026-02-19T19:42:46Z","created_by":"Dan Abrams","depends_on_id":"gromit-npr6x","issue_id":"gromit-q6ctg","type":"blocks"} @@ -1479,6 +1508,9 @@ {"created_at":"2026-02-07T05:47:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-6aa","issue_id":"gromit-r8c","type":"blocks"} {"created_at":"2026-02-07T05:47:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-8qh","issue_id":"gromit-r8c","type":"blocks"} {"created_at":"2026-02-12T15:20:57Z","created_by":"Dan Abrams","depends_on_id":"gromit-1rle","issue_id":"gromit-r8xq","type":"blocks"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-bkqc6","issue_id":"gromit-r9zlh","type":"blocks"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-ce7ua","issue_id":"gromit-r9zlh","type":"blocks"} +{"created_at":"2026-03-10T05:24:06Z","created_by":"Dan Abrams","depends_on_id":"gromit-hcio0","issue_id":"gromit-r9zlh","type":"blocks"} {"created_at":"2026-03-08T09:37:57Z","created_by":"Dan Abrams","depends_on_id":"gromit-hrtlk","issue_id":"gromit-rc6q8","type":"blocks"} {"created_at":"2026-02-06T22:43:30Z","created_by":"Dan Abrams","depends_on_id":"gromit-ehg","issue_id":"gromit-rfy","type":"parent-child"} {"created_at":"2026-03-07T00:55:33Z","created_by":"Dan Abrams","depends_on_id":"gromit-cbvlu","issue_id":"gromit-rg9ou","type":"blocks"} @@ -1675,6 +1707,7 @@ {"created_at":"2026-02-05T20:02:04Z","created_by":"Dan Abrams","depends_on_id":"gromit-1i7","issue_id":"gromit-vg2","type":"blocks"} {"created_at":"2026-02-12T06:34:47Z","created_by":"Dan Abrams","depends_on_id":"gromit-914c","issue_id":"gromit-vgzh","type":"blocks"} {"created_at":"2026-02-16T02:32:43Z","created_by":"Dan Abrams","depends_on_id":"gromit-s17a","issue_id":"gromit-vh9j","type":"blocks"} +{"created_at":"2026-03-10T01:35:23Z","created_by":"Dan Abrams","depends_on_id":"gromit-kavnv","issue_id":"gromit-vhvbr","type":"blocks"} {"created_at":"2026-02-22T22:17:18Z","created_by":"Dan Abrams","depends_on_id":"gromit-dh34r","issue_id":"gromit-vipl2","type":"blocks"} {"created_at":"2026-03-08T19:10:29Z","created_by":"Dan Abrams","depends_on_id":"gromit-ganlf","issue_id":"gromit-vj32h","type":"blocks"} {"created_at":"2026-02-22T21:20:31Z","created_by":"Dan Abrams","depends_on_id":"gromit-18sei","issue_id":"gromit-vj4fq","type":"blocks"} diff --git a/.beads/backup/events.jsonl b/.beads/backup/events.jsonl index 1badf080d..6fc9a1a0c 100644 --- a/.beads/backup/events.jsonl +++ b/.beads/backup/events.jsonl @@ -19268,3 +19268,144 @@ {"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:09:19Z","event_type":"closed","id":19269,"issue_id":"gromit-jb0h4","new_value":"Closed","old_value":""} {"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:11:11Z","event_type":"closed","id":19270,"issue_id":"gromit-x1xsn","new_value":"Closed","old_value":""} {"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:25:42Z","event_type":"closed","id":19271,"issue_id":"gromit-81reo","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:50:01Z","event_type":"created","id":19272,"issue_id":"gromit-y67or","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T00:50:01Z","event_type":"label_added","id":19273,"issue_id":"gromit-y67or","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T00:50:01Z","event_type":"label_added","id":19274,"issue_id":"gromit-y67or","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T00:50:01Z","event_type":"label_added","id":19275,"issue_id":"gromit-y67or","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:50:01Z","event_type":"created","id":19276,"issue_id":"gromit-f99rv","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T00:50:01Z","event_type":"label_added","id":19277,"issue_id":"gromit-f99rv","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T00:50:01Z","event_type":"label_added","id":19278,"issue_id":"gromit-f99rv","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T00:50:01Z","event_type":"label_added","id":19279,"issue_id":"gromit-f99rv","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:50:02Z","event_type":"created","id":19280,"issue_id":"gromit-8c38m","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19281,"issue_id":"gromit-8c38m","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19282,"issue_id":"gromit-8c38m","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19283,"issue_id":"gromit-8c38m","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:50:02Z","event_type":"created","id":19284,"issue_id":"gromit-2octl","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19285,"issue_id":"gromit-2octl","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19286,"issue_id":"gromit-2octl","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19287,"issue_id":"gromit-2octl","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:50:02Z","event_type":"created","id":19288,"issue_id":"gromit-50wzq","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19289,"issue_id":"gromit-50wzq","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19290,"issue_id":"gromit-50wzq","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19291,"issue_id":"gromit-50wzq","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:50:02Z","event_type":"created","id":19292,"issue_id":"gromit-klkbj","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19293,"issue_id":"gromit-klkbj","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19294,"issue_id":"gromit-klkbj","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T00:50:02Z","event_type":"label_added","id":19295,"issue_id":"gromit-klkbj","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:54:33Z","event_type":"closed","id":19296,"issue_id":"gromit-y67or","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T00:57:19Z","event_type":"closed","id":19297,"issue_id":"gromit-50wzq","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:03:32Z","event_type":"closed","id":19298,"issue_id":"gromit-8c38m","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:05:17Z","event_type":"closed","id":19299,"issue_id":"gromit-f99rv","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:12:34Z","event_type":"closed","id":19300,"issue_id":"gromit-klkbj","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:12:47Z","event_type":"status_changed","id":19301,"issue_id":"gromit-2octl","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"gromit-2octl\",\"title\":\"Fix spec_loop test compilation errors\",\"description\":\"In internal/v2/loop/spec_loop_specreview_test.go and spec_loop_test.go, fix type mismatches ([]stage.Finding → []specreview.SpecReviewFinding, []stagepkg.Finding → []finding.Finding), method references (ensureAcceptanceAndReview → ensureAcceptance), undefined constants (SpecFindingCategorySecurity → SpecFindingCategorySafety, etc.), pointer-vs-value issues, and undefined specReviewStage references.\",\"status\":\"open\",\"priority\":1,\"issue_type\":\"task\",\"owner\":\"me@thedanabrams.com\",\"created_at\":\"2026-03-10T04:50:02Z\",\"created_by\":\"Dan Abrams\",\"updated_at\":\"2026-03-10T04:50:02Z\"}"} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:23:38Z","event_type":"closed","id":19302,"issue_id":"gromit-2octl","new_value":"Fixed spec loop test compilation issues","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:24:09Z","event_type":"closed","id":19303,"issue_id":"gromit-2octl","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:35:23Z","event_type":"created","id":19304,"issue_id":"gromit-kavnv","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T01:35:23Z","event_type":"label_added","id":19305,"issue_id":"gromit-kavnv","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T01:35:23Z","event_type":"label_added","id":19306,"issue_id":"gromit-kavnv","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T01:35:23Z","event_type":"label_added","id":19307,"issue_id":"gromit-kavnv","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:35:23Z","event_type":"created","id":19308,"issue_id":"gromit-vhvbr","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T01:35:23Z","event_type":"label_added","id":19309,"issue_id":"gromit-vhvbr","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T01:35:23Z","event_type":"label_added","id":19310,"issue_id":"gromit-vhvbr","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T01:35:23Z","event_type":"label_added","id":19311,"issue_id":"gromit-vhvbr","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:35:24Z","event_type":"created","id":19312,"issue_id":"gromit-xuo34","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T01:35:24Z","event_type":"label_added","id":19313,"issue_id":"gromit-xuo34","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T01:35:24Z","event_type":"label_added","id":19314,"issue_id":"gromit-xuo34","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T01:35:24Z","event_type":"label_added","id":19315,"issue_id":"gromit-xuo34","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:37:20Z","event_type":"closed","id":19316,"issue_id":"gromit-kavnv","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:38:02Z","event_type":"status_changed","id":19317,"issue_id":"gromit-vhvbr","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"gromit-vhvbr\",\"title\":\"Add integration test for combined accept+review gating\",\"description\":\"Add integration test in internal/v2/loop/spec_loop_test.go that verifies the spec fails when accept passes but spec-review verdict is 'fail'. The test confirms ensureAcceptance() returns the combined failure and remediation is triggered, validating the verdict-level failure path.\",\"status\":\"open\",\"priority\":1,\"issue_type\":\"task\",\"owner\":\"me@thedanabrams.com\",\"created_at\":\"2026-03-10T05:35:24Z\",\"created_by\":\"Dan Abrams\",\"updated_at\":\"2026-03-10T05:35:24Z\"}"} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:43:11Z","event_type":"closed","id":19318,"issue_id":"gromit-vhvbr","new_value":"Added spec review verdict failure gating test","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:43:52Z","event_type":"closed","id":19319,"issue_id":"gromit-vhvbr","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T01:44:51Z","event_type":"closed","id":19320,"issue_id":"gromit-xuo34","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:24:05Z","event_type":"created","id":19321,"issue_id":"gromit-rmmaq","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T05:24:05Z","event_type":"label_added","id":19322,"issue_id":"gromit-rmmaq","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:0","created_at":"2026-03-10T05:24:05Z","event_type":"label_added","id":19323,"issue_id":"gromit-rmmaq","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T05:24:05Z","event_type":"label_added","id":19324,"issue_id":"gromit-rmmaq","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:24:05Z","event_type":"created","id":19325,"issue_id":"gromit-hcio0","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T05:24:05Z","event_type":"label_added","id":19326,"issue_id":"gromit-hcio0","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:0","created_at":"2026-03-10T05:24:05Z","event_type":"label_added","id":19327,"issue_id":"gromit-hcio0","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T05:24:05Z","event_type":"label_added","id":19328,"issue_id":"gromit-hcio0","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:24:06Z","event_type":"created","id":19329,"issue_id":"gromit-ce7ua","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19330,"issue_id":"gromit-ce7ua","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:0","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19331,"issue_id":"gromit-ce7ua","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19332,"issue_id":"gromit-ce7ua","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:24:06Z","event_type":"created","id":19333,"issue_id":"gromit-k7gel","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19334,"issue_id":"gromit-k7gel","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:0","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19335,"issue_id":"gromit-k7gel","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19336,"issue_id":"gromit-k7gel","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:24:06Z","event_type":"created","id":19337,"issue_id":"gromit-bkqc6","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19338,"issue_id":"gromit-bkqc6","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:0","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19339,"issue_id":"gromit-bkqc6","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19340,"issue_id":"gromit-bkqc6","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:24:06Z","event_type":"created","id":19341,"issue_id":"gromit-r9zlh","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19342,"issue_id":"gromit-r9zlh","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:0","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19343,"issue_id":"gromit-r9zlh","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19344,"issue_id":"gromit-r9zlh","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:24:06Z","event_type":"created","id":19345,"issue_id":"gromit-nxhpg","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19346,"issue_id":"gromit-nxhpg","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:0","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19347,"issue_id":"gromit-nxhpg","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19348,"issue_id":"gromit-nxhpg","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:24:06Z","event_type":"created","id":19349,"issue_id":"gromit-181wx","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19350,"issue_id":"gromit-181wx","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:0","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19351,"issue_id":"gromit-181wx","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T05:24:06Z","event_type":"label_added","id":19352,"issue_id":"gromit-181wx","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:25:55Z","event_type":"closed","id":19353,"issue_id":"gromit-rmmaq","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:29:54Z","event_type":"closed","id":19354,"issue_id":"gromit-ce7ua","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:35:51Z","event_type":"closed","id":19355,"issue_id":"gromit-hcio0","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:39:26Z","event_type":"closed","id":19356,"issue_id":"gromit-k7gel","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:43:11Z","event_type":"closed","id":19357,"issue_id":"gromit-bkqc6","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T05:58:37Z","event_type":"status_changed","id":19358,"issue_id":"gromit-r9zlh","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"gromit-r9zlh\",\"title\":\"Integrate spec-level review stage with combined verdict logic\",\"description\":\"Add specReviewStage field and WithSpecReviewStage option to SpecLoop in internal/v2/loop/spec_loop.go. After accept passes, run specReviewStage if present. Handle verdicts: critical findings trigger remediation with findings; pass with warnings trigger from-review bead creation scoped by Finding.Scope. Update remediationRunner interface to accept findings parameter.\",\"status\":\"open\",\"priority\":1,\"issue_type\":\"task\",\"owner\":\"me@thedanabrams.com\",\"created_at\":\"2026-03-10T09:24:06Z\",\"created_by\":\"Dan Abrams\",\"updated_at\":\"2026-03-10T09:24:06Z\"}"} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:02:04Z","event_type":"closed","id":19359,"issue_id":"gromit-r9zlh","new_value":"Completed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:06:11Z","event_type":"created","id":19360,"issue_id":"gromit-en4ct","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:06:39Z","event_type":"closed","id":19361,"issue_id":"gromit-r9zlh","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:16:28Z","event_type":"closed","id":19362,"issue_id":"gromit-181wx","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:20:28Z","event_type":"closed","id":19363,"issue_id":"gromit-nxhpg","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:18Z","event_type":"created","id":19364,"issue_id":"gromit-veios","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19365,"issue_id":"gromit-veios","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19366,"issue_id":"gromit-veios","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19367,"issue_id":"gromit-veios","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:18Z","event_type":"created","id":19368,"issue_id":"gromit-k1iky","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19369,"issue_id":"gromit-k1iky","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19370,"issue_id":"gromit-k1iky","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19371,"issue_id":"gromit-k1iky","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:18Z","event_type":"created","id":19372,"issue_id":"gromit-zs7g7","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19373,"issue_id":"gromit-zs7g7","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19374,"issue_id":"gromit-zs7g7","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19375,"issue_id":"gromit-zs7g7","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:18Z","event_type":"created","id":19376,"issue_id":"gromit-p24bl","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19377,"issue_id":"gromit-p24bl","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19378,"issue_id":"gromit-p24bl","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T06:39:18Z","event_type":"label_added","id":19379,"issue_id":"gromit-p24bl","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:19Z","event_type":"created","id":19380,"issue_id":"gromit-2q0ft","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19381,"issue_id":"gromit-2q0ft","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19382,"issue_id":"gromit-2q0ft","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:3","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19383,"issue_id":"gromit-2q0ft","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:19Z","event_type":"created","id":19384,"issue_id":"gromit-b39ja","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19385,"issue_id":"gromit-b39ja","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19386,"issue_id":"gromit-b39ja","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19387,"issue_id":"gromit-b39ja","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:19Z","event_type":"created","id":19388,"issue_id":"gromit-78vah","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19389,"issue_id":"gromit-78vah","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19390,"issue_id":"gromit-78vah","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19391,"issue_id":"gromit-78vah","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:19Z","event_type":"created","id":19392,"issue_id":"gromit-o8uk4","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19393,"issue_id":"gromit-o8uk4","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19394,"issue_id":"gromit-o8uk4","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19395,"issue_id":"gromit-o8uk4","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:19Z","event_type":"created","id":19396,"issue_id":"gromit-3i6ff","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19397,"issue_id":"gromit-3i6ff","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19398,"issue_id":"gromit-3i6ff","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:2","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19399,"issue_id":"gromit-3i6ff","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:19Z","event_type":"created","id":19400,"issue_id":"gromit-7t6ch","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19401,"issue_id":"gromit-7t6ch","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19402,"issue_id":"gromit-7t6ch","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T06:39:19Z","event_type":"label_added","id":19403,"issue_id":"gromit-7t6ch","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:39:20Z","event_type":"created","id":19404,"issue_id":"gromit-q436q","new_value":"","old_value":""} +{"actor":"Dan Abrams","comment":"Added label: spec:spec-level-review-and-targeted-remediation","created_at":"2026-03-10T06:39:20Z","event_type":"label_added","id":19405,"issue_id":"gromit-q436q","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: gen:1","created_at":"2026-03-10T06:39:20Z","event_type":"label_added","id":19406,"issue_id":"gromit-q436q","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":"Added label: estimated-files:1","created_at":"2026-03-10T06:39:20Z","event_type":"label_added","id":19407,"issue_id":"gromit-q436q","new_value":null,"old_value":null} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:54:36Z","event_type":"status_changed","id":19408,"issue_id":"gromit-veios","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"gromit-veios\",\"title\":\"Define shared Finding type with verdict logic\",\"description\":\"Create the Finding struct in internal/v2/stage/ with fields for severity (critical/warning/suggestion), category (bug/security/quality/test-gap/architecture/acceptance), scope (spec/general), description, and affected_files. Add Findings field to StageRequest. Implement ComputeVerdict function that returns \\\"fail\\\" for any critical finding, otherwise \\\"pass\\\". Include JSON serialization tags.\",\"status\":\"open\",\"priority\":1,\"issue_type\":\"task\",\"owner\":\"me@thedanabrams.com\",\"created_at\":\"2026-03-10T10:39:18Z\",\"created_by\":\"Dan Abrams\",\"updated_at\":\"2026-03-10T10:39:18Z\"}"} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:54:55Z","event_type":"closed","id":19409,"issue_id":"gromit-veios","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T06:56:09Z","event_type":"closed","id":19410,"issue_id":"gromit-zs7g7","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T07:06:55Z","event_type":"closed","id":19411,"issue_id":"gromit-78vah","new_value":"Closed","old_value":""} +{"actor":"Dan Abrams","comment":null,"created_at":"2026-03-10T07:16:17Z","event_type":"closed","id":19412,"issue_id":"gromit-k1iky","new_value":"Closed","old_value":""} diff --git a/.beads/backup/issues.jsonl b/.beads/backup/issues.jsonl index 6d4d457b9..e38b137bc 100644 --- a/.beads/backup/issues.jsonl +++ b/.beads/backup/issues.jsonl @@ -66,6 +66,7 @@ {"acceptance_criteria":"/tmp/bd-acceptance-3064158101.txt","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-19T12:16:26Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"95aa6612f737e0f231b7d24fb18d6ae29fbf86079a3ee9a26ae9232403ee7cf1","created_at":"2026-02-19T10:05:00Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create `internal/coverage/tracker.go` with `CoverageTracker` struct managing a checklist of `CriterionState` entries. Implement `NewTracker`, `MarkCovered`, `RecordRejection`, `NextUncovered`, `IsComplete`, `UncoveredCriteria`, `UntestableCriteria`, `FormatCoverageState`, and `Summary` methods. Create `internal/coverage/tracker_test.go` covering all state transitions and termination conditions.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-16zu4","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement CoverageTracker state machine","updated_at":"2026-02-19T12:16:26Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"AcceptanceCriteria-to-ExpectedOutputs mapping is in a separate method (e.g. resolveExpectedOutputs)\nnormalizeNilFields only handles nil-to-empty conversions\nSeparate method called after normalizeNilFields in parsing path\nAll existing tests pass","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:27Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"77058829aa24783d55bd7fc70e0fba1fdb31a109483105c0e7a9120660b8a310","created_at":"2026-02-19T20:05:40Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In internal/bead/bead.go:57-64, normalizeNilFields() now maps AcceptanceCriteria lines into ExpectedOutputs. This conflates two responsibilities: nil-safety normalization (the function's stated purpose) and data transformation (converting between field representations). The logic works but should be a separate method (e.g., resolveExpectedOutputs) called after normalizeNilFields in the parsing path, keeping normalizeNilFields purely about nil→empty conversions.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-176m0","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Move AcceptanceCriteria-to-ExpectedOutputs mapping out of normalizeNilFields","updated_at":"2026-03-02T19:42:27Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"All types compile and are importable from other packages\nPipeline constructor validates required fields and returns error for invalid deps\nCompile-time interface checks pass against concrete implementations","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-12T09:24:57Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a466441d3faf46046197cb9b99b10b319f28424a0f9395de171d0407dec239c8","created_at":"2026-02-11T10:39:05Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/pipeline/pipeline.go with Pipeline struct, Deps, Paths, and New constructor. Define narrow interfaces for all dependencies (AgentResolver, ClaudeClient, BeadClient, BacklogClient, PromptRenderer, LearningsManager, StateManager, LogWriter). Create internal/pipeline/types.go with all input/output structs (RefineInput, RefineResult, PlanInput, PlanResult, DecomposeInput, DecomposeResult, ReviewInput, ReviewResult, ExploreInput, ExploreResult), Session interface, EventType constants, Event struct, and typed session wrappers. Add compile-time interface satisfaction checks and initialize all slice fields to empty slices.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-17zd","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create pipeline foundation with types and interfaces","updated_at":"2026-02-12T09:24:57Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T10:16:28Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"13944cb9e3a7067d1cceba6dd08c2a093b8964fd35595daaa2dc9590e0ac548b","created_at":"2026-03-10T09:24:07Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Register --from-review bool flag and optional --spec string flag on run2 command in cmd/gromit/run2.go. When --from-review set, query open beads with from-review label (optionally filtered by --spec) and run them through bead loop. Skip plan, decompose, accept, and specreview.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-181wx","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add --from-review flag for running deferred review beads","updated_at":"2026-03-10T10:16:28Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T06:08:34Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"88787eea9f8f3555f3e7e4dcc566aefea6cc01247a3edbbbc96a77d6078a4635","created_at":"2026-03-08T05:20:07Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify the spec loop to preserve the worktree branch when Andon is triggered or generation cap is hit. On successful completion (PR merged), delete the worktree branch. The decision is made by the spec loop, not by stages.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-187wy","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Preserve worktree branch on failure, delete on success","updated_at":"2026-03-08T06:08:34Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Completed","closed_at":"2026-03-06T18:57:06Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"280476bc57d35d9b74d1234f6feec9b04bee9d56702125e215e2fc70ec23b424","created_at":"2026-03-06T17:53:38Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"The internal/v2/testutil/ package has 4 well-tested shared fakes (FakeGit, FakeLLM, FakeTaskTracker, FakePresenter) with interface contract assertions, but no test currently uses them. Every test defines local stubs instead. Strategy: keep local stubs for unit tests (minimal, focused), but migrate integration tests (loop/integration_test.go) and acceptance tests (acceptance_*_test.go) to use the testutil fakes where they provide richer behavior (dependency tracking, response matching). Do NOT replace simple unit test stubs — those are better as local, focused helpers.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-188e6","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Wire testutil shared fakes into integration and acceptance tests","updated_at":"2026-03-06T18:57:06Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Per-attempt summary log line: attempt number, high-complexity count, low-complexity count\nFinal warning message when high-complexity count \u003e 0 at loop exit\nWarning includes remaining high-complexity bead titles and reason snippets\nNo warning emitted when loop exits with zero high-complexity beads\nTest: per-attempt summary present and contains correct high count\nTest: final warning message present with correct count and reasons when high remains\nTest: no warning emitted on clean exit (zero high-complexity)","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-23T02:10:50Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9ff0f64c5ebb6a4418ffd3075da7d2de55fb8aa95408ea8ef31d21713ff47c33","created_at":"2026-02-22T21:20:30Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Emit a concise complexity summary after each attempt and a final warning when high-complexity beads remain after the retry loop exits in internal/pipeline/decompose.go. The final warning should include the remaining high-complexity count and reason snippets. Add tests in decompose_test.go asserting message presence and key fields.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-18sei","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add per-attempt and final complexity reporting to decompose output","updated_at":"2026-02-23T02:10:50Z","waiters":"","wisp_type":"","work_type":""} @@ -160,9 +161,11 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T20:43:45Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f3da6c6f4c626eb0973ac33c96dd53951bef724e802076c461dc6d2b0661302f","created_at":"2026-02-07T10:14:17Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In internal/runner/process.go, handleStallTimeout (line 174) checks totalRetriesThisBead \u003e maxRetriesPerBead after incrementing, while handleEscalation (line 389) checks totalRetriesThisBead \u003e= maxRetriesPerBead without incrementing. This means stall-based retries get one more attempt than failure-based escalations. Standardize the comparison to be consistent.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2na","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix retry limit inconsistency between stall timeout and escalation paths","updated_at":"2026-02-07T20:43:45Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"bead_integration_test.go exists with //go:build acceptance and all 4 integration tests\nbead_test.go no longer contains newIsolatedClient or the 4 integration tests\nTotal test function count across both files equals original count","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-21T06:34:03Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5fbbed26fae6cb6bcd301e7be81b940adf9fe2a499d49837298a4bfdca04599a","created_at":"2026-02-13T11:34:15Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Extract 4 integration tests (TestClientCreate, TestClientCreateWithParent, TestClientCreateInheritsCreateWithParent, TestClientCreateWithDeps) and newIsolatedClient helper from internal/bead/bead_test.go into new bead_integration_test.go with '//go:build acceptance' tag. Verify bead_test.go has no remaining references to newIsolatedClient.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2ndj","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Split bead_test.go integration tests","updated_at":"2026-02-21T06:34:03Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Tests verify buildSkillContent includes all three stage skills between delimiters\nTests verify mergeHookSettings correctly merges JSON\nTests verify mergeHookSettings is idempotent","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T05:46:16Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"68e034aaac1c4697fc2f5583d78e931afc61170f50e95dc0faa1c4e99fc91f9b","created_at":"2026-02-07T04:50:46Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create cmd/gromit/install_skill_test.go with unit tests for buildSkillContent and mergeHookSettings functions. Verify content inclusion, JSON merge correctness, and idempotency.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2ns","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add unit tests for skill building functions","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T05:24:09Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"343cf12589809f948fe86ae4ac69c11d6977633d95f44a9c127352e2c0ba69a8","created_at":"2026-03-10T04:50:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In internal/v2/loop/spec_loop_specreview_test.go and spec_loop_test.go, fix type mismatches ([]stage.Finding → []specreview.SpecReviewFinding, []stagepkg.Finding → []finding.Finding), method references (ensureAcceptanceAndReview → ensureAcceptance), undefined constants (SpecFindingCategorySecurity → SpecFindingCategorySafety, etc.), pointer-vs-value issues, and undefined specReviewStage references.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2octl","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix spec_loop test compilation errors","updated_at":"2026-03-10T05:24:09Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T13:20:02Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f1b4033a2cbe28f3840b72fb44a0cc4002ccf11b7acf1daf14cd480db595410c","created_at":"2026-03-08T11:51:48Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Extend debug to detect when root cause requires systemic changes (prompt, guard, process, rule) and generate human-readable recommendations. Implement in internal/v2/debug/systemic.go to fix immediate code problem while presenting recommendation for human review.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2opey","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement debug systemic recommendation path","updated_at":"2026-03-08T13:20:02Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Template includes standard context sections from build template\nInstructions specify reviewing code quality, naming, structure, and duplication\nInstructions specify all tests must continue to pass and behavior must not change","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T08:39:57Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5d3852f343e5b26de177381b921f42cfa2106c76aca2fe438bfc807be3c623c6","created_at":"2026-02-07T05:48:27Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create .gromit/templates/PROMPT_refactor.md with standard context sections plus instructions for refactoring without changing behavior. Instructions specify reviewing implementation for quality and committing refactoring changes separately.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2pm","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create PROMPT_refactor.md template","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Epic for tracking - unblock children","closed_at":"2026-02-05T15:53:31Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"684566ca3a21b23c06e1ff3e836f2b8239eb06c9f27356ca878c0b06fe873c11","created_at":"2026-02-05T15:52:28Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Improve validation reliability by capturing output, adding visibility, detecting partial progress, and pre-flight checks.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2po","is_template":0,"issue_type":"epic","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Validation Reliability Improvements","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"76ea0acccc2ed7064940823e8ef4e215333ffbedf329293ac00c8b24c4d60639","created_at":"2026-03-10T10:39:19Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify internal/v2/loop/spec_loop.go to run specreview after accept, combine verdicts (both must pass), and pass combined findings to remediation on failure. Load review_spec_v2.md fragment in internal/v2/loop/run2_components.go and construct specreview stage with highest-tier model. Make specreview stage accessible from spec loop via Run2LoopComponents.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2q0ft","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Wire spec-level review into spec loop and run2","updated_at":"2026-03-10T10:39:19Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T21:26:48Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ed8b79a6fbefed77a720c1627a694fbea71ea6018009c042eed69745180d6adb","created_at":"2026-02-07T19:01:35Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Several learnings are duplicated: (1) Template registration described twice with conflicting detail (ralph-runner-yx7b vs ralph-runner-kjix). (2) JSON omitempty covered in both Confirmed and provisional. (3) Table-driven test pattern stated twice. (4) Mock FnField pattern restated. (5) Contradictory newline management learnings. Archive duplicates and consolidate contradictory ones.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2qf1","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Consolidate duplicate and near-duplicate learnings in LEARNINGS.md","updated_at":"2026-02-07T21:26:48Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- [ ] New ScopeCheckConfig in config.go: Enabled bool, LargeThreshold string (default \"large\")\n- [ ] Added to Config as ScopeCheck with yaml tag \"scope_check\", default Enabled: false\n- [ ] New method runner.checkScope(ctx, bead) (*ScopeEstimate, error)\n- [ ] Called in processBead() after building prompt context, before escalation loop\n- [ ] Uses haiku model for fast estimation\n- [ ] If complexity == \"large\": logs warning, auto-sets model to opus (skipping lower models)\n- [ ] If scope check itself fails: logs warning and continues with normal flow (non-blocking)\n- [ ] ralph.yaml updated with commented example: scope_check: { enabled: true }\n- [ ] go build ./... passes","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Breaking down into smaller tasks","closed_at":"2026-02-05T19:59:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8f9810021f1fd48c4cd4e2a7edb9fecd3cd60b31ebbcbe9b6525925bc9f57f2e","created_at":"2026-02-05T19:45:21Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Before running the main build, ask haiku to quickly estimate task scope. If estimated as 'large', either auto-escalate the starting model or flag for decomposition. Add config to enable/disable this check.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2qv","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add pre-build scope check step in runner","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-21T04:26:50Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"87273cec6a37e08b71a400c8897cf36582c8de797615b5054b3cdda403a9ae7a","created_at":"2026-02-15T19:17:23Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add ProviderResult *provider.Result field to execution.InvocationResult (invoker.go:20). Populate it from the existing providerResult variable in Execute() (invoker.go:173). Add the same field to escalation.InvocationResult (handler.go:35). In makeInvokeFn (callbacks.go), propagate the ProviderResult from execution.InvocationResult through to escalation.InvocationResult. Extend executeClaudeInvocation to also return the provider.Result so callbacks.go can access it. Update all escalation.InvocationResult literal constructions in callbacks.go to include ProviderResult where available. All existing tests must pass unchanged.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-2s2q","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Carry provider.Result through InvocationResult","updated_at":"2026-02-21T04:26:50Z","waiters":"","wisp_type":"","work_type":""} @@ -211,6 +214,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-10T18:00:06Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"73df5475775ce47b6464fef4ce7c758c11887f27190fce5dd4c3564b214a38cc","created_at":"2026-02-10T16:51:15Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Replace the local claudeRunnerAdapter in internal/runner/runner.go with the shared one from internal/claude/adapter.go. Acceptance criteria: (1) runner.go imports and uses the shared adapter instead of defining its own, (2) existing runner tests pass without modification.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-3hch","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update internal/runner/runner.go to use shared claudeRunnerAdapter","updated_at":"2026-02-10T18:00:06Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T21:30:42Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"2f1c2ec7083ade4d6c1908314496595888ab04b88a9fd47517e55681bb7ffc65","created_at":"2026-03-08T20:47:55Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create integration tests in internal/v2/loop/integration_immutable_test.go using a real git repo (no LLM invocation) to verify stage sequence, event log cumulation, retry preservation, and squashing. Tests should confirm correctly formatted commits, cumulative events, prior attempt preservation in history, and correct per-bead squash behavior.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-3hde3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add integration tests for commit-per-stage flow","updated_at":"2026-03-08T21:30:42Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T21:03:14Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"93196d30460ff28557641ef03d2699ca1fc1c3998e4467e1f4672316430364c0","created_at":"2026-03-08T20:47:55Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify spec_loop.go to decide when to preserve or delete the worktree branch based on completion status. Update internal/v2/adapter/git/worktree.go with functions to preserve branches on failure (Andon or generation cap) and delete branches on success (PR merged). Include clear logging for all branch preservation and deletion decisions.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-3i1ko","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Preserve worktree branch on failure, delete on success","updated_at":"2026-03-08T21:03:14Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f8de792a47b7a7e903870210795e7dfb541e658b936d4b5c5382f13fd6d198e3","created_at":"2026-03-10T10:39:20Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify cmd/gromit/run2.go to add boolean --from-review flag and optional string --spec \u003cid\u003e flag. When --from-review is set, skip plan/decompose/accept/review stages and query open beads with from-review label. If --spec is provided, additionally filter by spec:\u003cid\u003e label. Run matching beads through bead loop directly with no remediation cycle. Add tests in run2_test.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-3i6ff","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Add --from-review flag to run2","updated_at":"2026-03-10T10:39:20Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Granularity defaults to \"bead\" when unset\nValidate() rejects \"invalid\" but accepts \"bead\" and \"spec\"\nYAML deserialization round-trips correctly","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-18T20:58:18Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"2672ab1aa284c1cf95adb1254d4820aceed91b31329937c1acf7c1b1a99c5399","created_at":"2026-02-18T18:21:32Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add `Granularity string` field with YAML tag `granularity` to `MethodologyConfig` in `internal/config/config.go`. In `SetDefaults()` default to `\"bead\"` when empty. In `Validate()` reject values other than `\"bead\"` and `\"spec\"`. Add commented `granularity` field to `gromit.yaml` methodology section. Add tests in `internal/config/config_test.go`.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-3i71i","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add Granularity field to MethodologyConfig","updated_at":"2026-02-18T20:58:18Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T21:12:06Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"72b554eebab04f61276231ce45bd2a4aea1285af75bd8a6364729735b2d8798c","created_at":"2026-02-07T19:01:19Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"When a precheck passes and auto-closes a bead (runner.go:342), the iteration log hardcodes DurationMs: 0. The precheck actually makes a haiku API call with a 30s timeout. Capture time.Now() before runPrecheck and compute actual duration. Also remove duplicate log — runPrecheck logs 'Pre-check: acceptance criteria already met' (runner.go:1314) then the caller logs the same message again (runner.go:322).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-3ibd","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix precheck iteration log recording DurationMs: 0 and duplicate log message","updated_at":"2026-02-07T21:12:06Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T06:16:38Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f382e9ece75d050d67a4e3b5ea55f7c820018d99d0bce8c301b446668ff5cf6e","created_at":"2026-03-08T05:20:07Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"When Present creates a PR, combine per-stage commits into one commit per bead with the bead title as the commit message. The full stage-level history remains on the worktree branch. Implement squash logic in Present stage or Git adapter.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-3jjty","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement per-bead squash logic in Present stage","updated_at":"2026-03-08T06:16:38Z","waiters":"","wisp_type":"","work_type":""} @@ -318,6 +322,7 @@ {"acceptance_criteria":"gromit refine uses cfg.Claude.Binary and passes cfg.Claude.Flags to Claude CLI invocation\ngromit plan uses cfg.Claude.Binary and passes cfg.Claude.Flags to Claude CLI invocation\nBoth commands default to binary=\"claude\" with no extra flags when cfg == nil","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-06T22:39:42Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"cf07ea69818339d25f2ab76ac822f6beb1a4497d488b994896ad26ebd97afa1e","created_at":"2026-02-06T22:11:58Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify cmd/gromit/refine.go and cmd/gromit/plan.go to use cfg.Claude.Binary and cfg.Claude.Flags when invoking Claude CLI. Replace hardcoded exec.Command(\"claude\", ...) with dynamic binary and args construction that prepends flags before existing arguments. Handle cfg == nil case with defaults (binary=\"claude\", flags=[]).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-4zs","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add config flags and binary to refine and plan commands","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:24Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8211844676055f3ac7f6f33ecf1becc67d2f3b5ff75816f05bad380e25b3492d","created_at":"2026-02-24T01:56:12Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"cmd/gromit writeBenchmarkReport currently calls internal benchmark WriteReport and then writes JSON again at the same result path with a second payload shape. Remove duplicate writer behavior so one owner defines report JSON/MD schema, preserve deterministic artifacts, and add tests to prevent overwrite/regression.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-50ggy","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Consolidate benchmark report writing to a single schema owner","updated_at":"2026-03-02T19:42:24Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"38 os.ReadFile+strings.Contains on .go source files replaced across 5 *_agent_test.go files\nCompile-time interface checks (var _ Interface = (*Impl)(nil)) added where applicable\nBehavioral integration tests replace fragile source-reading tests\nCount of os.ReadFile calls on .go files in test code drops to 0","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:27Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5e8233222e3f2d292dc1f5bd7495dce90d05bbb1a23cb7d5cbd35471984395ef","created_at":"2026-02-19T20:17:58Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"38 occurrences of os.ReadFile+strings.Contains on .go source files exist across 5 *_agent_test.go files. These tests verify code structure (absence of patterns like exec.Command) but are fragile to any refactoring. Replace with compile-time interface checks (var _ Interface = (*Impl)(nil)) and behavioral integration tests. For pattern-absence assertions that cannot be expressed as compile-time checks, consider grep-based CI checks as a fallback. Leading indicator: count of os.ReadFile calls on .go files in test code drops to 0.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-50gp2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Replace 38 source-text-reading tests with compile-time checks","updated_at":"2026-03-02T19:42:27Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T04:57:19Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a0f3d8b5349a95169a5634c82b46a806c457603f805df12c1be4754e0baeff28","created_at":"2026-03-10T04:50:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In internal/v2/stage/gate/gate.go, when checkSatisfaction returns true, close the bead via task tracker's CloseBead method before returning DecisionSkip. In gate_test.go, write TestGateClosesSatisfiedBead that verifies CloseBead is called with the bead's ID when satisfaction check passes.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-50wzq","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement bead closure on gate satisfaction","updated_at":"2026-03-10T04:57:19Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Calls StreamRun with rendered acceptance test prompt and bc.model\nReturns nil on successful Claude invocation\nReturns error with descriptive message on Claude failure","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T08:42:44Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"75bd2f4eea3d2d8b5f0a1810c581832642961d1cd1acfaaaee9f8988eeb10c0b","created_at":"2026-02-07T05:48:27Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add runAcceptanceTests method to Runner in internal/runner/process.go that renders acceptance test prompt and calls StreamRun with same model as build. Uses heartbeat/stall detection pattern from executeClaudeInvocation.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-51s","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement runAcceptanceTests method","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"/tmp/bd-acceptance-37263308.txt","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:37Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a3b307fcb379271585454281fa1ad2301d7d346b6b373a628edbe81c6d38b483","created_at":"2026-02-19T10:05:05Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"After the TDD cycle loop completes in `internal/runner/process_methodology.go` or `internal/runner/run_iteration.go`, populate `bc.Result` coverage fields from tracker state. When criteria are uncovered or untestable, add a bead comment via `r.beads.AddComment()` using `tracker.Summary()`. Log coverage summary to runner output. Add tests verifying field population and comment generation.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-51t64","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"Experiment: demoted P1→P2 (haiku). Mechanical TDD: report coverage to IterationResult. Tracking tier-demotion-2026-02-20.","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":4,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Report coverage results to IterationResult and bead comments","updated_at":"2026-03-02T19:42:37Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T02:21:21Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a9b363667fd0b08cfff567d686f6ba64189fd4b5052e5808dee66f98a835eef9","created_at":"2026-02-19T23:53:28Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/provider/provider.go:26-39 Result struct and lines 42-46 ToolEvent struct have no JSON tags. Per project rules, JSON tags must be explicit and snake_case. Fields like CostUSD would serialize as CostUSD instead of cost_usd, and CachedInputTokens as CachedInputTokens instead of cached_input_tokens.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-53522","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add JSON tags to provider.Result and ToolEvent structs","updated_at":"2026-02-20T02:21:21Z","waiters":"","wisp_type":"","work_type":""} @@ -451,6 +456,7 @@ {"acceptance_criteria":"Every invocation (build and ATDD) has INVOCATION_START and INVOCATION_END markers in stream log\nFailed invocations with no provider events still have both markers\nMarkers include provider name, model, tier, and outcome","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-21T01:25:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8c4c933c649cbf877d43848389e13e18fa95acd2dcd430c5a584e0d0dee2e0cc","created_at":"2026-02-15T19:56:47Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add streamLogger field to Runner struct. In makeInvokeFn (internal/runner/callbacks.go), emit INVOCATION_START before executeClaudeInvocation and INVOCATION_END after with provider, model, tier, success, duration, and failure_category. Add similar ATDD_INVOCATION_START/END markers for ATDD invocations. Add tests to internal/runner/callbacks_test.go verifying markers on success and failure paths.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-76gp","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add stream-log lifecycle markers for invocations","updated_at":"2026-02-21T01:25:20Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"PromptRenderer interface includes RenderTDDBuild method\nBoth mock renderers compile and satisfy updated interface","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T09:36:50Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9b736b651b2587c77269a898699ee04d019473e442ddba6540f4faf31224cdec","created_at":"2026-02-07T05:54:37Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add RenderTDDBuild method signature to PromptRenderer interface in internal/runner/interfaces.go. Update mockPromptRenderer in internal/runner/interfaces_test.go with RenderTDDBuildFn field. Update mockRenderer with stub implementation returning mock TDD prompt.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-76o","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update PromptRenderer interface and mocks","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-18T19:15:54Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"94d792ee595ffb46d5f2e6acd685688656d0326cb2332bbfa76cec40d1307912","created_at":"2026-02-18T18:36:53Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/state/state.go:53-57 unmarshals JSON into f.state but never calls f.state.NormalizeNilFields(). interactive_state.go correctly calls it at lines 71, 189, and 240. This inconsistency means slices like FilteredLearningHashes and maps like ProviderCounts remain nil after load, risking nil map panics. Add f.state.NormalizeNilFields() after the json.Unmarshal call.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-77xe5","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add missing NormalizeNilFields call in state.File.Load()","updated_at":"2026-02-18T19:15:54Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T11:06:55Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"0bdd57ba3cc3134c6ca73b8a2b9ca1ba1d507334fda54d7b542adbfd96ac0131","created_at":"2026-03-10T10:39:19Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Update internal/v2/remediation/remediation.go Run() method to accept []stage.Finding instead of gap analysis string. Set req.Findings on decompose stage request instead of req.GapAnalysis. Maintain backward compat: if findings are empty but gap analysis exists, fall back to current behavior. Handle error case when both are missing.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-78vah","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Modify remediation runner to accept findings","updated_at":"2026-03-10T11:06:55Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- SubprocessEnv respects an existing GOMAXPROCS if already set to a reasonable value\n- Only sets GOMAXPROCS if not already present in the environment\n- Document why the cap exists (resource exhaustion prevention?) and whether it applies to macOS or only Linux cgroup-constrained environments\n- Existing tests still pass\n- go test ./internal/procutil/... passes\n\nKey file: internal/procutil/procutil.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-04T18:02:43Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"62bb4d24361fe84e94d31841d2c4c8ca0c32a8a647cdd046d4d2faae4ff3e7cb","created_at":"2026-03-04T13:06:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/procutil/procutil.go SubprocessEnv() unconditionally overwrites any user-set GOMAXPROCS with MaxGoParallelism (hardcoded '4'). If a CI system or user intentionally sets GOMAXPROCS higher for their environment, this silently throttles their builds. Also investigate whether GOMAXPROCS capping is relevant on macOS/Darwin — the project runs on macOS (Darwin 25.2.0) and GOMAXPROCS behavior may differ from Linux in terms of cgroup awareness.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-791l5","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Respect existing GOMAXPROCS in SubprocessEnv instead of unconditional override","updated_at":"2026-03-04T18:02:43Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"internal/procutil/procutil_test.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Completed","closed_at":"2026-03-04T18:58:57Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"faa658ddd7a015c08262352d2dd3c0452b786e6b00fcd55388ae70c58957f31e","created_at":"2026-03-04T18:02:42Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-791l5.1","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Write failing tests for GOMAXPROCS-respecting SubprocessEnv behavior","updated_at":"2026-03-04T18:58:57Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"internal/procutil/procutil.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Completed","closed_at":"2026-03-04T18:20:26Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"e9e973e5d97f81f8b403e8e8f5ab5a53faff2058300c78bac0f92740439af7f3","created_at":"2026-03-04T18:02:43Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-791l5.2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update SubprocessEnv to skip override when GOMAXPROCS is already set, and add comment documenting cgroup/macOS context","updated_at":"2026-03-04T18:20:26Z","waiters":"","wisp_type":"","work_type":""} @@ -626,6 +632,7 @@ {"acceptance_criteria":"var _ ProviderRunner = (*ConcreteImpl)(nil) added in production file (not test file)\nCompile-time check uses the actual concrete implementation type\nCheck is at package level in the appropriate production .go file","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:26Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ec641900c3d4691136548d70a7f28d05d190d9af5fae57a2425ba74bbe2548c1","created_at":"2026-02-21T12:57:28Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"The ProviderRunner interface in internal/retro/retro.go has no package-level compile-time satisfaction check. The only check is inside a test function body in provider_only_migration_test.go (line 249), which does not satisfy the rule requiring var _ InterfaceName = (*Impl)(nil) in a non-test production file. Find the concrete implementation type and add the check to the appropriate production file.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-7rj2f","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add production-file compile-time check for retro.ProviderRunner","updated_at":"2026-03-02T19:42:26Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-07T04:05:22Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3c46e303aef1cde83fb8f247b65dc16f924490a2f147f0ceacafa8117d6a52d9","created_at":"2026-03-07T04:03:37Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement FormatCommitMessage and ParseCommitMessage functions in internal/v2/pipeline/commit_message.go that handle both bead-level ([bead:ID/stage/iter:N]) and spec-level ([spec/stage/iter:N]) structured commit messages. Support regex-based parsing to extract BeadID, StageName, Iteration, and Decision fields.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-7smak","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create structured commit message formatter and parser","updated_at":"2026-03-07T04:05:22Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T02:53:15Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5324343b1ac7cf77479ceff30786ecd816b398638fbbe90e7c2e72cdc13984e2","created_at":"2026-02-19T23:53:18Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/prompt/prompt.go is 1295 lines — 2.6x the 500-line limit. Extract context struct definitions into context_types.go, rules phase-filtering into rules_filter.go, and parse/format helpers into parse.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-7snxt","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Split prompt.go (1295 lines) into multiple files","updated_at":"2026-02-20T02:53:15Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"59161de57ecf08df1ab12f014a13ec693b8f864635a2cb6303933396398f989b","created_at":"2026-03-10T10:39:20Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Write integration test in internal/v2/loop/spec_loop_integration_test.go that exercises: bead loop → accept fails → specreview fails → combined findings passed to remediation → decompose creates targeted beads from findings (not plan re-decomposition) → targeted beads execute through bead loop. Mock LLM responses at invoker level. Assert decompose receives findings and created beads map to specific findings.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-7t6ch","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Integration test for remediation-with-findings pipeline","updated_at":"2026-03-10T10:39:20Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-03T18:59:18Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"0915b8adb8ef0502c53d8ee34920621cac057db72cbd2d4f8e599ab172f06794","created_at":"2026-03-03T12:13:11Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/pipeline/qualitygate/wiring/symbols.go defining a Symbol struct (Name, File, Line) and an extraction function that parses unified diff added lines to identify newly-exported Go symbols. Create symbols_test.go with comprehensive test coverage for all extraction and exclusion rules.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-7ti5h","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement Go symbol extraction from unified diff","updated_at":"2026-03-03T18:59:18Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T13:39:12Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"0892476584ae0bef302aa6c15f3acc7218c87b02fb80f80ac3ea741befcc3157","created_at":"2026-03-06T11:59:10Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"The spec and plan were written assuming modifications to the existing runner. The actual implementation created a new internal/v2/ package with a run2 command. Update the spec and plan to document the architectural decision and reflect the actual design.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-7tpvy","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update spec and plan to reflect v2 architecture","updated_at":"2026-03-06T13:39:12Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Test verifies gromit add without arg returns non-zero exit\nTest verifies gromit decompose without arg returns non-zero exit\nTest verifies --help commands return exit code 0","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-06T23:19:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7bb9b05a63ea2f10f534f9b282354b3718d580adb4ce6ea4b77e894938d57684","created_at":"2026-02-06T22:43:29Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement TestCLIContract_ExitCodes in cmd/gromit/cli_contract_test.go with table-driven test cases for missing args, invalid flag values, and help commands.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-7uf","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add exit code contract tests","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} @@ -663,6 +670,7 @@ {"acceptance_criteria":"MethodologyConfig struct defined with ATDD and TDD boolean fields with yaml tags\nConfig struct includes Methodology field with yaml tag methodology\nTable-driven tests verify parsing for present true, present false, and absent (defaults to false)","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T08:29:47Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"1a33a0ac8afd9177836ea0ccbcc6db71be6fe4bc468381a5acb51dfb545aebf0","created_at":"2026-02-07T05:48:27Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add MethodologyConfig struct with ATDD and TDD boolean fields to internal/config/config.go. Add Methodology field to Config struct with yaml tag. No defaults needed since false is correct zero-value.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-89b","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add MethodologyConfig to config package","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T19:11:21Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"33b83ef1f88e700aec1557897f8893ab72ed19100392f281344c2ae76adc1617","created_at":"2026-02-07T19:00:51Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"The 6 confirmed learnings entries lost their human-readable titles (Shell Safety, Test Helper Delegation, Documentary Test Replacement, Mock Implementation Patterns, Status File Management, Output Formatting) and now show '0001-01-01' — the Go zero-value for time.Time. This is a bug in the consolidation/retro tooling that formats dates for confirmed entries. The Archived section still cross-references the old titles, creating broken references. Investigate internal/retro/ or internal/learnings/ for the date-formatting bug and restore meaningful headers.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-8a52","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix LEARNINGS.md confirmed entries showing 0001-01-01 instead of descriptive titles","updated_at":"2026-02-07T19:11:21Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Runner parses estimated-files:N label from bead labels and populates IterationResult.EstimatedFiles\nwriteIterationLog writes EstimatedFiles to JSONL output","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-21T06:59:07Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"98bc5fce1d497ec79b09226dad1fcabb51ca0dd0e7beadd5f8f3d185174b988f","created_at":"2026-02-14T09:39:01Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create parseEstimatedFilesLabel helper in internal/runner/process.go that scans labels for estimated-files: prefix and parses integer using strconv.Atoi, returning 0 on error. Call helper in setupBeadContext to populate bc.Result.EstimatedFiles. Update writeIterationLog in internal/runner/runner.go to add EstimatedFiles field to IterationLog struct literal.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-8acg","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Parse estimated-files label and populate logs in runner","updated_at":"2026-02-21T06:59:07Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T05:03:32Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3492ea87e031586bbd1a9eabac576f7441e55d9957983d40f8e9d355ce10fa81","created_at":"2026-03-10T04:50:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In internal/v2/loop/spec_loop.go, remove duplicate spec-review checks and redundant runSpecReview/runSpecReviewStage calls after ensureAcceptance. Keep ensureAcceptance as the single orchestration point and preserve from-review bead creation and accept commit logic.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-8c38m","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Remove duplicate spec-review orchestration from SpecLoop.Run","updated_at":"2026-03-10T05:03:32Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"/tmp/bd-acceptance-1733957711.txt","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-19T12:00:00Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"66cd0ebbcf2c4255542a56f77340ea8fbc92d158617212d4eb681f1e6314c923","created_at":"2026-02-19T10:05:01Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create `internal/coverage/validator.go` defining `SelfReport` and `ValidationResponse` structs with `ParseSelfReport(output string)` and `ParseValidationResponse(output string)` functions. Both parsers scan for JSON blocks within surrounding text using string scanning rather than requiring the entire output to be JSON. Create `internal/coverage/validator_test.go` covering valid, embedded, and malformed JSON cases.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-8cj56","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement SelfReport and ValidationResponse parsing","updated_at":"2026-02-19T12:00:00Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"cf4f045b48a5a72c430cd9fdaa2d20a0e3e30b8c73d5ef1ec74ee22f98329ae9","created_at":"2026-03-09T21:26:49Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Running go test ./internal/v2/loop currently fails on pre-existing drift unrelated to gromit-jyqo9 (duplicate scriptedSpecReviewStage declarations, outdated stagepkg.Finding references, and stale specreview constructor usage in integration tests). Stabilize loop package baseline so full package tests can run.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-8co7o","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Resolve internal/v2/loop baseline test compile drift","updated_at":"2026-03-09T21:26:49Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"runLightReview uses LoadRulesForPhase(\"review\") for rules content\nrunThoroughReview uses LoadRulesForPhase(\"review\") for rules content\nExisting tests pass with updated mock","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T00:39:04Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3fed79be2dc6ce3367f058013857c2869a2003697068b81b0ed5a94692639248","created_at":"2026-02-12T17:55:41Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Update runLightReview and runThoroughReview in runner.go to call LoadRulesForPhase(\"review\") instead of LoadRules when setting reviewCtx.Rules. Update mock implementations to support the new method. Modify internal/runner/runner.go with tests.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-8d1c","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Wire phase-filtered rules into review invocations","updated_at":"2026-02-20T00:39:04Z","waiters":"","wisp_type":"","work_type":""} @@ -827,6 +835,7 @@ {"acceptance_criteria":"Command() returns a configured *exec.Cmd without running the process\nLaunch() continues to work unchanged with existing tests passing\nCommand() respects all three prompt delivery modes (FileRef, PromptFileArg, Stdin)","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-12T09:36:15Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5ce337ee8310a5fa99400c75fe67cc23c74247b684c284b431ef34f6d39fab65","created_at":"2026-02-11T10:39:05Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add Command(promptPath string) (*exec.Cmd, error) to Agent interface in internal/agent/agent.go. Implement in cliAgent: verify prompt file exists, build command args based on promptDelivery mode (same logic as Launch but without cmd.Run), return configured *exec.Cmd without starting it. For Stdin delivery, do NOT set up the pipe. Update internal/agent/agent_test.go with tests for all three prompt delivery modes and error case.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-b0xw","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add Command() method to Agent interface","updated_at":"2026-02-12T09:36:15Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T13:15:16Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"48e43befd9286be005b77038c2860748914ae16fe08cb414aa7cffb23d251ac0","created_at":"2026-03-06T11:58:59Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"stage/plan/plan.go defines its own LLM interface with Invoke(ctx, prompt, model) (string, error) instead of using llm.LLMProvider like all other stages. This prevents sharing the same adapter and loses cost/token telemetry.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-b1l1i","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Align plan stage LLM interface with other stages","updated_at":"2026-03-06T13:15:16Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Test verifies bead Close and Sync called on PRECHECK_PASSED\nTest verifies iteration log written with precheck_skipped outcome\nTest verifies iteration counter not incremented","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T13:03:03Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9c5a92715e3c0ed6ddacaade18acbcbfec50cf65068c2562d0361a979062fd9b","created_at":"2026-02-07T11:47:13Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add TestRunWithMocks_PrecheckPassed to internal/runner/interfaces_test.go. Mock Claude.Run to return PRECHECK_PASSED. Verify bead is closed, synced, logged with precheck_skipped, and iteration counter NOT incremented.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-b1w","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add unit tests for precheck PASSED behavior","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d36dfa1419d58a2f68f2ac64937302de5f9724ca1c29f7e47c87d4b447c0cd4d","created_at":"2026-03-10T10:39:19Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify internal/v2/loop/spec_loop.go to create from-review beads when specreview passes with findings. Classify findings by scope: spec-scoped findings produce beads with labels \"from-review\" and \"spec:\u003cspec-id\u003e\", general-scoped findings produce beads with label \"from-review\" only. Beads are created but not executed in the current run.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-b39ja","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Create from-review beads on pass-with-improvements","updated_at":"2026-03-10T10:39:19Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-22T03:45:27Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"475151d8222bc492f54cb6bfcc23b92b6d0930a59fb26d9baced965f48711239","created_at":"2026-02-22T02:44:50Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"NewRunnerLegacy (runner.go lines 124-236) is a 112-line constructor duplicating wiring from newRunnerImpl. It exists for backward compatibility with internal tests (per TODO comment). The dual architecture (Orchestrator vs Runner, each with their own Run loop) creates maintenance burden and risk of wiring drift. Create a concrete plan: identify which tests depend on Runner directly, convert them to use Orchestrator or acceptance tests, then remove NewRunnerLegacy.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-b3ope","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create migration plan for NewRunnerLegacy removal","updated_at":"2026-02-22T03:45:27Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"PickerStdin(\"refine\", \"something_new\", 2) returns \"3\\n\"\nPickerStdin(\"plan\", \"item\", 2) returns \"2\\n\"\nUnknown picker types panic with descriptive message","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T09:50:09Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"1cd79296608d408e11867556b09e62f465254a92ba4a301b753327c686d91b62","created_at":"2026-02-07T05:59:51Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement test/testutil/picker.go with PickerStdin function that computes picker stdin from type/target/count. Encode layout logic for refine (items 1..N, something_new at N+1), plan (items 1..N), and decompose (items 1..N, decompose_all at N+1).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-b3s","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create PickerStdin helper function","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- [ ] Load(path) parses RULES.md into structured representation\n- [ ] Save() writes back to file\n- [ ] AddRule(section, rule) adds a rule under a section\n- [ ] ModifyRule(section, old, new) modifies an existing rule\n- [ ] Parses ## Section headers + - Rule bullets\n- [ ] Tests in internal/rules/rules_test.go\n- [ ] go build ./... passes\n- [ ] go test ./internal/rules/... passes","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-06T05:32:58Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"09292af4ff1dafedeef3e65796b4f655d46a47d6deca99132e78940bf85d67c2","created_at":"2026-02-06T05:20:17Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"New package internal/rules/rules.go. Load(path), Save(), AddRule(section, rule), ModifyRule(section, old, new). Parses ## Section headers + - Rule bullets. Replaces old bead gromit-6x8.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-b51","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add rules file editing package","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} @@ -856,6 +865,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-05T17:08:57Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7628a8f1a0dab56e0bebb1a2c36cac8b50d9dc2471626d4c26333e4e132a1090","created_at":"2026-03-05T01:47:53Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/integrationqueue/gitops.go has no dedicated test file. This package handles git operations for the integration queue (branch management, worktree operations) and should have test coverage to prevent regressions.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-bkia1","is_template":0,"issue_type":"chore","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add tests for internal/integrationqueue/gitops.go","updated_at":"2026-03-05T17:08:57Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"test/fakes/codex supports call logging, fixture output, and failure toggles through env vars\nJSONL stream fixture mode is supported for provider stream parsing tests\nContract fake-integration tests validate fake Codex success and failure behavior","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-16T03:27:50Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"eee07745e2ca3ce0495938a27657a6c794a335cb093e954bbb776e3d978ac3a7","created_at":"2026-02-16T02:27:00Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create test/fakes/codex executable that mirrors fake Claude ergonomics: call logging via TEST_CALL_LOG, stdin consumption, fixture-driven output for plain and JSONL modes, configurable non-zero failures, and optional delay toggles. Implement contract tests in test/contracts/fakes_integration_test.go validating fake Codex success and failure behavior.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-bkij","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add fake Codex CLI with fixture-driven behavior","updated_at":"2026-02-16T03:27:50Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"ReadStatus returns parsed Status pointer for valid file\nReadStatus returns nil, nil when status.json doesn't exist\nReadStatus returns error for malformed JSON","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T11:09:55Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"898adde2d3c164a2433903b6a9bd6d2b55cb94588969e0fc0bce4b63d39832bb","created_at":"2026-02-07T08:38:38Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add ReadStatus(gromitDir string) (*Status, error) function to internal/runner/status.go that reads and parses .gromit/status.json. Return nil, nil when file doesn't exist (not an error). Use os.ReadFile and json.Unmarshal to load the status.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-bkk","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement ReadStatus function","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T09:43:12Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ac0a5f3419309b16e5cbf7741fc6b6c8b3f51d11e659022fe3200a67ff8ebc8b","created_at":"2026-03-10T09:24:06Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify internal/v2/remediation/remediation.go to accept findings []stage.Finding in executeRemediation. Add extractFindings helper mirroring extractGapSummary. When findings non-empty, populate req.Findings on decompose request; when empty, use existing gap-analysis path.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-bkqc6","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update remediation runner to accept and forward findings","updated_at":"2026-03-10T09:43:12Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Makefile has install-skill target that depends on build\nTarget runs ./gromit install-skill\n.PHONY includes install-skill","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T05:59:04Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"573d365e9e6c644df10fd1e07bab8b1f7eacfedcaf043ca94e7a26b4f5d4d1df","created_at":"2026-02-07T04:50:46Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify Makefile to add install-skill target that builds and runs gromit install-skill. Update .PHONY to include install-skill.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-bky","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add Makefile target for install-skill","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"1. Two input modes: spec name arg or no args (picker listing .gromit/specs/*.md)\n2. --force flag added\n3. Refuses if .gromit/plans/\u003cname\u003e.md exists and no --force\n4. Loads spec via frontmatter.ReadFile()\n5. System prompt includes full spec content, plans dir, spec name, open beads, gromit-plan skill reference\n6. Uses same interactive exec.Command launch pattern","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-06T14:05:39Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a1d4612676525deb93b6b7d0fb3e36c50c42a72a8aaf63c21d8f6334175022df","created_at":"2026-02-06T13:41:46Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Rewrite cmd/gromit/plan.go. Two input modes: spec name arg or no args (picker listing .gromit/specs/*.md). Add --force flag. Check if .gromit/plans/\u003cname\u003e.md exists (refuse unless --force). Load spec via frontmatter.ReadFile(). System prompt includes full spec content, plans dir, spec name, open beads, gromit-plan skill reference. Also depends on Task 2 (config, gromit-osg) and Task 5 (plan skill, gromit-g9g).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-bl8","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"Cross-dependencies: also depends on gromit-osg (config/init) and gromit-g9g (plan skill). Both should be completed first.","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Rewrite plan command for spec input and plan output","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Acceptance file retains only true streaming E2E behavior\nReclassified tests run under normal go test ./internal/provider/...\ngo test -tags acceptance ./internal/provider/... passes with reduced test count","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-16T02:19:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ea09c616e0af0f23d62d502b46bc5291387fa7d1dde5c0413a15ddbc0df6efb3","created_at":"2026-02-16T01:08:16Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Move internal-behavior and wiring validation tests from codex_streaming_acceptance_test.go into corresponding *_test.go unit suite. Preserve assertions while reducing acceptance-tag execution footprint.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-bl9k","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Reclassify provider acceptance tests to unit tests","updated_at":"2026-02-16T02:19:20Z","waiters":"","wisp_type":"","work_type":""} @@ -906,6 +916,7 @@ {"acceptance_criteria":"go test ./internal/pipeline passes\\nTestDecomposeWorkflow_RetriesOnValidationViolation passes\\nTestDecomposeWorkflow_UsesScoreBasedComplexitySummaryAndReasons passes\\nTestDecomposeWorkflow_RetryLoopSuccessPathSetsValidationFlag passes","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-23T03:39:05Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"687ff211a4f9bb188491cbf923c2e7cfdc038741deb88f0b4413501b00b2edb7","created_at":"2026-02-23T03:34:13Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Verification task gromit-vj4fq.3 found failing pre-existing decomposition tests in internal/pipeline while internal/validate remained green.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-ccy3e","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix pre-existing decomposition regressions in internal/pipeline","updated_at":"2026-02-23T03:39:05Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-06T10:53:27Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5bcb3f24902aa3959ad27aa464c5c541cfafb241c929aef6435046a153859cdd","created_at":"2026-02-06T09:29:33Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add getGitDiff(fromCommit string) (string, error) function to internal/runner/runner.go. Returns full git diff output (not just --stat). Existing getGitDiffStat returns stats only. See docs/plans/2026-02-06-review-system-plan.md Task 8.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-ce1","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add getGitDiff helper to runner","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"/tmp/bd-acceptance-2099377552.txt","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T07:49:35Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"b3aa3c6fdd732ad5a97e5c6a88354ad4c38ac35856c3c483d3ae2c832a941c2f","created_at":"2026-02-19T03:15:29Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add 4 rolling phase-rate entries to the series map in buildProcessTrend() in internal/logger/process_trend.go. Add three tests in process_trend_test.go: control limit count and names, spike anomaly detection, and UCL/LCL clamping for rate metrics.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-ce51l","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add phase-rate series to buildProcessTrend with tests","updated_at":"2026-02-20T07:49:35Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T09:29:55Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"6cefda24976275ae71b2ccda74d1694806e187c681347bd1f1fc7532dfecc9c7","created_at":"2026-03-10T09:24:06Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add Findings []stage.Finding field to AcceptArtifacts in internal/v2/stage/accept/accept.go. For each failing criterion, create a Finding with severity critical, category acceptance, scope spec, and description from criterion text. Retain GapSummary for backward compatibility.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-ce7ua","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add structured findings output to accept stage artifacts","updated_at":"2026-03-10T09:29:55Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-05T18:29:11Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"6dfd124ccb90de4e2b1cdb190a70f3a4073d1f053714aa29043e47d843e57dc4","created_at":"2026-03-05T17:51:17Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"cmd/gromit/main.go has 12+ package-level var declarations used as test seams (newRunnerWithStageContextFn, retroResolveAgentFn, retroSessionLauncherFn, etc.). Create a runDeps struct that bundles these dependencies and thread it through runLoop and runRetro. This eliminates global mutable state and enables t.Parallel() in tests.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-cf3m0","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Introduce runDeps struct to replace package-level test seam vars in cmd/gromit","updated_at":"2026-03-05T18:29:11Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T12:41:09Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"b05b70471f69a7bc59ddf46b7cdc0df24c36161c1b01e97478d377af1af271cb","created_at":"2026-03-08T11:51:47Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Ensure each retry increments the iteration number in commit messages and creates a new commit rather than amending. Implement in internal/v2/loop/retry.go to increment iteration counter per retry attempt.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-cfepn","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Preserve retry attempts as separate commits","updated_at":"2026-03-08T12:41:09Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Tests verify TDD prompt used when TDD active\nTests verify standard prompt when inactive and no regression\nTests verify label override behavior for tdd:true","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T09:44:18Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8d04c8a2e860097b6f22876dbc91bdf23cd2aeeafd33ae8b085e6577b8fe6a2b","created_at":"2026-02-07T05:54:37Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add tests in internal/runner/runner_test.go using NewRunnerWithDeps. Test TDD-active bead verifies RenderTDDBuildFn called with mock renderer tracking. Test TDD-inactive bead verifies standard RenderBuildFn used and RenderTDDBuildFn not called. Test tdd:true label overrides global tdd:false config.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-cfh","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add TDD prompt selection tests","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} @@ -1097,6 +1108,7 @@ {"acceptance_criteria":"Timing script supports measuring/reporting default and smoke lanes distinctly\nBudget output identifies lane context for exceeded thresholds\nScript remains backward compatible for existing timing workflow","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:38Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a9043ed365f038cf5ea0702230588bc06ed456eda9ecab5e8b31cca5ea167914","created_at":"2026-02-16T02:27:05Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify scripts/test_timing.sh to support measuring/reporting default and smoke lanes distinctly. Update scripts/test_package_budgets.txt if per-lane budget entries are needed. Make budget violations visible with explicit lane context. Ensure backward compatibility for existing timing workflow.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-el7d","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"Experiment: demoted P0→P2 (haiku). Mechanical: bash timing scripts. Tracking tier-demotion-2026-02-20.","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":4,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add lane-aware timing and runtime budget visibility","updated_at":"2026-03-02T19:42:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"ResolveEpic scans all .md files in specsDir and reads frontmatter\nReturns label array for specs where epic field equals epicID parameter\nReturns empty slice when no specs match the epic","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-08T11:49:44Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3b9f399f8488342811f0bcc2ec5eca54ff454cd2c3b0fdd28bddd1876e16ab0c","created_at":"2026-02-08T08:10:56Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add ResolveEpic function to internal/scope/scope.go that scans spec files in specsDir, reads frontmatter using internal/frontmatter.ReadFile, and returns labels for specs where epic field matches epicID. Use spec id field for label construction.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-elej","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement ResolveEpic in scope resolver","updated_at":"2026-02-08T11:49:44Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"All-pass verdict returns Passed=true\nSome-fail verdict returns Passed=false with correct failures\nTest failure or LLM error returns error","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-18T19:47:11Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"83a2e1c28ff6aeebd4d1fc0e16f89d448a96c32ec453d3e23c58f6b6eb3d58d8","created_at":"2026-02-18T18:21:34Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create `internal/specgate/gate.go` with function types `RunTestsFn`, `InvokeLLMFn`, `RenderPromptFn`, `GetDiffFn`. Create `Gate` struct with these deps plus `Model string` and `MaxCycles int`. Implement `Gate.Run(ctx, specName, acceptanceCriteria) (*GateVerdict, error)` that runs tests, gets diff, renders prompt, invokes LLM, and parses verdict. Add tests in `internal/specgate/gate_test.go` covering all-pass, some-fail, test error, and LLM error cases.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-elmd4","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement Gate orchestration with function-type deps","updated_at":"2026-02-18T19:47:11Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a9c792b43b8a46a8a4d8783fb3f979fd2260891f47b9fbad846c4179734682c6","created_at":"2026-03-10T10:06:12Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Post-rebase quality gates for gromit-r9zlh fail: go test/go vet ./internal/v2/loop cannot compile because internal/v2/stage/stage.go redeclares type Finding (lines 21 and 54). Remove duplicate declaration and restore compile parity.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-en4ct","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Fix duplicate Finding declaration in internal/v2/stage/stage.go","updated_at":"2026-03-10T10:06:12Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-05T04:08:39Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"aa56b4ab54aba5878487a03e2ba98c9078dd46e1addff00b954192ca43154ff5","created_at":"2026-03-04T12:11:09Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/provider/codex_helpers.go classifyCodexFailure and internal/provider/gemini_failure_classification.go classifyGeminiFailure implement nearly identical pattern-matching for auth, startup, transport, and rate-limit failures. Extract shared classifyFailure helper with provider-specific patterns injected. Also fix inconsistent IsUsageLimitError heuristics (Claude checks Output but ignores Stderr).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-enjl6","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Deduplicate failure classification logic across Codex and Gemini providers","updated_at":"2026-03-05T04:08:39Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"ReadModelStats returns correct per-model success, failure, escalation, and cost totals from multiple JSONL files\nCostPerCompletedBead attributes full retry/escalation chain cost to completed beads and excludes incomplete beads\nReadRunModelStats correctly filters stats by run ID","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-11T14:21:59Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"2811d3693993b745e816bd21c3a681bd07dbc193472d750e09c6a110cc532ce1","created_at":"2026-02-11T08:24:54Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create ModelStats struct and aggregation functions in internal/logger/modelstats.go. Implement ReadModelStats to aggregate per-model success/failure/escalation/cost from JSONL logs, ReadRunModelStats to filter by run ID, and CostPerCompletedBead to compute chain costs for completed beads. Reuse existing readLogFile() function and follow ReadAllLogs/ReadPerBeadStats patterns.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-eo57","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement ModelStats aggregation logic","updated_at":"2026-02-11T14:21:59Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-05T13:54:11Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"bcd644d9c1441590b88497b8bd321b65b05769ceb60656aca812f5426839c998","created_at":"2026-03-05T13:27:03Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/runner/runner.go:34 calls addCoverageCommentWithClient(context.Background(), ...) which bypasses the caller's context cancellation. If the parent context is cancelled (timeout, shutdown), this network call continues indefinitely. Should propagate the caller's context to respect cancellation.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-epd9o","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Use caller context instead of context.Background() in reportCoverage","updated_at":"2026-03-05T13:54:11Z","waiters":"","wisp_type":"","work_type":""} @@ -1142,6 +1154,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-16T19:40:04Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5f9826aef48f14b411850e083ef02f5cc372601d909114b3da0c7069bba19266","created_at":"2026-02-16T18:38:57Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Update policy decision logic to consume the classified failure class and select decisions using class-to-decision behavior instead of class-agnostic branching.\n\nAcceptance criteria:\n- Public policy entry points route through classification and then class-aware decision selection.\n- Decision logic includes at least one explicit branch/path per failure class.\n- Behavior for non-class-specific inputs remains deterministic and backward-compatible where intended.\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-f8x2.3.2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Make decision selection class-aware","updated_at":"2026-02-16T19:40:04Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-16T19:51:34Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"40dfd3d108bdb48f4ebcbf3bd7093dad787bb20ca491f036b3e6ba8c15911d81","created_at":"2026-02-16T18:38:58Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Extend `internal/runner/andon/policy_test.go` with end-to-end policy tests that validate class-to-decision behavior and at least one L1/L2 boundary case via public entry points.\n\nAcceptance criteria:\n- `internal/runner/andon/policy_test.go` includes at least one decision path each for Transient, Workflow, Quality, Intent, and Data.\n- Tests assert at least one L1/L2 threshold boundary case through a public policy entry point.\n- Tests verify class outputs feed decision selection (not bypassed) and pass in CI/local test run.\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-f8x2.3.3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Cover class paths and L1/L2 boundary in policy tests","updated_at":"2026-02-16T19:51:34Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"AuthorAcceptanceTests called before first bead of each spec\nNot called for second+ beads of same spec\nNot called when granularity is \"bead\"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-18T21:31:57Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"79b816df91e5f7376dbb3b89ff909bce3e51a080c56bdc675c429bb9e0d9896c","created_at":"2026-02-18T18:21:39Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add `specOrchestrator *SpecOrchestrator` field to Runner in `internal/runner/runner.go`. In `NewRunner`, initialize when `cfg.Methodology.Granularity == \"spec\"`. In the bead processing loop, before `processBead()`, check if orchestrator is active and this is the first bead for its spec — call `specOrchestrator.AuthorAcceptanceTests()`. Track \"tests authored\" per spec in `runLoopState`. Add tests in `internal/runner/runner_test.go`.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-f95ip","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Wire SpecOrchestrator into runner.Run() bead loop","updated_at":"2026-02-18T21:31:57Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T05:05:18Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"abc978c1bef60c4ccddb20486ce971c0c9105bc1d2cd432e2da7cad23bbefba5","created_at":"2026-03-10T04:50:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In internal/v2/stage/specreview/specreview.go, change selectModel fallback from config.ModelSonnet to config.ModelOpus. In specreview_test.go, add TestSelectModelDefaultsToOpus test and fix imports (remove unused reflect, add missing fmt).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-f99rv","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add model fallback test and fix selectModel default to opus","updated_at":"2026-03-10T05:05:18Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-07T15:31:58Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a90af236d3648693c2effebaba0e0029c3a37c323fb8f08bd2b9a9c26aac229b","created_at":"2026-03-07T15:06:47Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify internal/v2/routing/routing.go to add MarkUnavailable() method marking providers unavailable for cooldown duration. Enhance Select() to skip unavailable providers and fallback to next available. Enhance tests in routing_test.go to verify cooldown expiry and fallback behavior.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-f9c0p","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Router fallback and cooldown handling","updated_at":"2026-03-07T15:31:58Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"runDirectValidationCheck delegates to r.validationRunner.RunDirect\nrunValidationWithRecovery delegates to r.validationRunner.RunWithRecovery\nvalidation_summary.go deleted\ngo test ./internal/runner/... -count=1 passes","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-13T22:36:24Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3f8482bdf9cd1c2854bae7a0adf7288c8e4c41ccafe4ba0b5fda8762ede2c36f","created_at":"2026-02-13T21:04:46Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Make the facade's runValidation() (process.go:754) and runValidationWithRecovery() (process.go:851) delegate core logic to the existing validation.Runner methods. Keep only orchestration concerns (preflight, logging, review trigger) in the facade. Delete validation_summary.go backward-compat wrapper (it just forwards to validation.ExtractValidationSummary). Update any tests that reference extractValidationSummary to use the validation package directly.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-fa4v","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Wire validation/ facade delegation and delete compat wrapper","updated_at":"2026-02-13T22:36:24Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-17T03:20:54Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a26372a31bb6550add5c22a3a00574a5bb6eaf347133599983804cd9b6e2484a","created_at":"2026-02-16T15:43:17Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Detect hard-stop classes (bulk delete outside scoped tmp dirs, irreversible migration, credential/secrets changes) and force explicit approval/escalation behavior rather than autonomous execution.\n\nFiles:\n- Modify: internal/runner/andon/policy.go\n- Modify: internal/runner/escalation/handler.go\n- Test: internal/runner/andon/policy_test.go\n\nAcceptance Criteria:\n- Hard-stop actions bypass L1/L2 autonomous execution and trigger escalation\n- Bulk delete allowlist behavior is explicit and test-covered\n- Tests verify no autonomous path proceeds without approval flag/state\n\nNotes: Use conservative matching first; expand detection patterns iteratively.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-fdak","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add hard-stop action guardrails","updated_at":"2026-02-17T03:20:54Z","waiters":"","wisp_type":"","work_type":""} @@ -1257,6 +1270,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-09T12:05:44Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"e0dd599546a244fa2e30bf076707e2095102662b69fbb6a49b1ed8d1b005efc8","created_at":"2026-03-09T11:55:29Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/v2/stage/specreview/specreview.go with Stage struct implementing the stage interface. Load cumulative diff, plan from worktree, and review_spec_v2.md fragment. Invoke highest-tier model to generate structured JSON findings, parse output into ReviewResult, and retry once on parse failure. Create review_spec_v2.md with guidance for correctness, security, error handling, and testing.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-hab86","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement spec-level review stage","updated_at":"2026-03-09T12:05:44Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"TUI code deleted from codebase; closing stale beads","closed_at":"2026-03-05T14:45:00Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"938eea30ebac66cd9183e04d64f82af9d8f5800975090e0b8b80e8eb6848cc04","created_at":"2026-03-03T21:55:26Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/tui/view_pipeline.go with ListItem adapters: IdeaListItem wrapping backlog.Idea, SpecListItem wrapping a spec filename string, PlanListItem wrapping a plan filename string, and BeadListItem wrapping bead.Bead. Each implements Title() and Summary() with appropriate formatting.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-haosl","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement ListItem adapters for pipeline data types","updated_at":"2026-03-05T14:45:00Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-18T15:45:57Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"e5cd1f25827723ded7511ced8068527f656f0cda2dd0e8f9622df3522c317409","created_at":"2026-02-18T11:16:37Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"test/contracts/codex_harness_test.go references ApplyCodexFixtureEnv, FilterToolCalls, ToolCallCodex, ToolCallClaude, ToolCallBD which do not exist in the contracts package. Similarly test/e2e/codex_harness_test.go. Tests have 'Expected failure' comments but symbols are undefined so packages won't compile when contract/e2e build tags are active.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-hbew","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Contract test codex_harness_test.go references undefined symbols","updated_at":"2026-02-18T15:45:57Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T09:35:52Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"220974520302d422541a937b03008f5453df1455f2ac6e19c280b277d0fc913a","created_at":"2026-03-10T09:24:06Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/v2/stage/specreview/ package with Stage type implementing stage.Stage. The Run method invokes the LLM with cumulative diff and spec-review prompt, parsing JSON output into verdict and findings. Verdict logic: any critical finding → DecisionFail; otherwise DecisionProceed.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-hcio0","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement specreview Stage with JSON parsing and verdict logic","updated_at":"2026-03-10T09:35:52Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-03T05:07:11Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9503160e1ca0f6f8202bb6b82b075365eb290d2916c21ab08bcff47a41481477","created_at":"2026-03-03T04:32:59Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add `GromitDir string` to `QueueInput` in `internal/pipeline/queue.go` and update `Queue()` to load the restart point store and call `ReadPerBeadStatsAfter` with filtered stats before passing to `PartitionQueueBeads`. Update all `QueueInput` construction sites including `cmd/gromit/queue.go`. Tests in `internal/queue/snapshot_test.go` verify stuck/ready partitioning with restart points.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-hg222","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update queue display to respect restart points","updated_at":"2026-03-03T05:07:11Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Tests verify ResolveSpec returns correct label format\nTests verify ResolveEpic finds specs by epic frontmatter field\nTests verify ValidateFlags enforces mutual exclusivity","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-08T11:50:12Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"1645aa8f98d38f4bb7f2de2fa3f4f589c1c0fb842f93e7b09a513a1f94a61a06","created_at":"2026-02-08T08:10:56Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/scope/scope_test.go with tests covering ResolveSpec label format, ResolveEpic frontmatter scanning with temp directories, empty results handling, and ValidateFlags mutual exclusivity. Use table-driven test pattern.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-hgu3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add unit tests for scope resolver","updated_at":"2026-02-08T11:50:12Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- Option A: export procutil's constant as DefaultProcessCapacityMaxWait and reference it from bead instead of defining commandProcessCapacityWait locally\n- Option B: remove commandProcessCapacityWait from bead and pass 0 to WaitForProcessCapacity (the 0 path already uses the procutil default)\n- Either option: only one source of truth for the 1500ms value\n- All existing tests pass","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-03T01:19:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7b14f08b1809ea9a097dc6a6175e24b06d96e958d6bc7b45802722882fd4a37d","created_at":"2026-03-02T19:53:27Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/bead/bead.go defines commandProcessCapacityWait = 1500ms, duplicating defaultProcessCapacityMaxWait = 1500ms in internal/procutil/procutil.go. Values are identical today but will silently diverge if either is tuned. Since bead already imports procutil, the duplication is unnecessary.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-hj49d","is_template":0,"issue_type":"chore","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Eliminate duplicate commandProcessCapacityWait constant in bead package","updated_at":"2026-03-03T01:19:20Z","waiters":"","wisp_type":"","work_type":""} @@ -1411,6 +1425,7 @@ {"acceptance_criteria":"internal/pipeline/decompose_test.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-22T20:38:50Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9447ebf653a129f2154fd8e777b6d51e1166510471fb47b5897d0e6ec78a4a44","created_at":"2026-02-22T20:30:09Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-jzqqu.3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add Decompose tier selection tests (explicit tier and default medium)","updated_at":"2026-02-22T20:38:50Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Remove dead nil-result check in verifyTestsFail","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:30Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f661b4e43b73d1315b8cc8f344aa3a1f0f409347cf5fc9ac3207dc4aeba8eb88","created_at":"2026-02-12T11:33:36Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In internal/runner/process.go verifyTestsFail(), the check 'if valResult == nil { return error }' after runDirectValidationCheck() is dead code. runDirectValidationCheck() always returns a non-nil *claude.Result when err is nil. The nil check can never be reached because the preceding error check handles the only case where result could be nil. Remove the dead check.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k0bh","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Remove dead nil-result check in verifyTestsFail","updated_at":"2026-03-02T19:42:30Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"LaunchInDir with non-empty dir sets cmd.Dir on subprocess\nLaunchInDir with empty dir behaves identically to Launch\nretro.LaunchClaudeCode accepts dir parameter and passes it through","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-14T17:04:06Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"0af8224d1d74569dfb8474ede23c8501c253a0c3e6063e1a06b57fa0ffaf8322","created_at":"2026-02-12T16:38:33Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add LaunchInDir(promptPath, dir string) method to Agent interface in internal/agent/agent.go. Implement on cliAgent to set cmd.Dir when dir is non-empty. Update retro.LaunchClaudeCode in internal/retro/retro.go to accept dir parameter and set cmd.Dir.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k0qi","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add LaunchInDir to Agent interface","updated_at":"2026-02-14T17:04:06Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T11:16:17Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"bffac0e51a4666a130add4c0653d3099fb86ca47c71d5006d3fd82683bcc1dee","created_at":"2026-03-10T10:39:19Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/v2/stage/specreview/specreview.go implementing the Stage interface. The Run method assembles a prompt from cumulative diff, original plan, and project context; invokes the LLM (highest tier); parses structured JSON response into []Finding; computes verdict via ComputeVerdict. Returns SpecReviewArtifacts{Findings, Verdict}. Include comprehensive tests in specreview_test.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k1iky","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement spec-level review stage","updated_at":"2026-03-10T11:16:17Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Interactive early exit prompts user and runs the end-of-loop command when user answers yes, skips when user answers no\nNon-interactive early exit skips the command and prompt entirely\nCommand failure after user confirms causes Run() to return an error; no prompt appears when command is absent or empty","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T06:46:09Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d37e7596c1021b5aaf6d811534cf5fbf4f6001ff460e557772ac1b65b8e91934","created_at":"2026-02-19T18:22:23Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add early-exit handling in internal/runner/runner.go that checks for a configured end-of-loop command when Run() hits an error return path. Use the interactivity and prompt helpers: prompt on interactive stdin, skip silently on non-interactive stdin, propagate command failure if user confirms. Add table-driven tests covering all branches in internal/runner/runner_test.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k1nj4","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Wire early-exit prompt/skip flow in Run() with tests","updated_at":"2026-02-20T06:46:09Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-06T08:50:00Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ba7b55ce32cc7278b86434a1d9d8cf63e6fd54bf0b8d02ba3995ff14f8580a2f","created_at":"2026-02-06T07:07:31Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Walk through open beads one at a time for quick triage decisions.\n\nExample:\n[1/3] ralph-runner-abc: Fix critical auth bug (P0)\n Created: 2 days ago\n (k)eep (r)eprioritize (c)lose (s)kip (q)uit\n\nImplementation:\n- New cobra command in cmd/ralph/triage.go\n- Read from stdin for interactive input\n- Walk beads in priority order (P0 first)\n- Actions: keep (no-op), reprioritize (change priority via bd), close (with reason), skip, quit\n- Show count progress [N/total]\n- No external dependencies — just fmt.Scan or bufio.Reader\n\nKey files: cmd/ralph/triage.go (new), internal/bead/bead.go (update/reprioritize capability)","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k20","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"ralph triage interactive mode","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"gromit init creates PROMPT_tdd_build.md in .gromit/templates/\ngromit init help text lists PROMPT_tdd_build.md template","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T09:47:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"6a9393e8719c375fcb38243a078b86495b625f85fec0c3fa540584d9f63d5b80","created_at":"2026-02-07T05:54:37Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify cmd/gromit/init.go to register TDD build template. Add defaultTDDBuildTemplate constant with template content from Task 1. Add writeFileIfNotExists call for .gromit/templates/PROMPT_tdd_build.md in runInit function. Add PROMPT_tdd_build.md to Long description of init command help text.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k3j","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Register PROMPT_tdd_build.md in gromit init","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} @@ -1422,6 +1437,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-19T20:58:32Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9b6622c9034472b25731554b883f1f66f750129970de8b3f777ae9ada2cc590e","created_at":"2026-02-19T19:37:12Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add `CoverageValidationContext` and `RenderCoverageValidation(ctx *CoverageValidationContext) (string, error)` in the prompt renderer, and update `PromptRenderer` in `internal/runner/interfaces.go` so callers can render the new template.\n\nAcceptance criteria:\n- `CoverageValidationContext` is defined with `TestCode string`, `CriterionNumber int`, and `CriterionText string`\n- `RenderCoverageValidation` is implemented in `internal/prompt/prompt.go` and renders from the new coverage validation template\n- `internal/runner/interfaces.go` includes `RenderCoverageValidation(ctx *CoverageValidationContext) (string, error)` on `PromptRenderer` and the code compiles\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k5lbt.2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement coverage validation render API","updated_at":"2026-02-19T20:58:32Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-19T20:49:32Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"490077ee20fd6552d5b5a5bcb2dbb23b7fe6abc3cb7d6748b289ce7ca56a2636","created_at":"2026-02-19T19:37:13Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Extend `internal/prompt/prompt_test.go` with tests that verify `RenderCoverageValidation` correctly interpolates context values and preserves the structured-response contract in the rendered prompt.\n\nAcceptance criteria:\n- Tests call `RenderCoverageValidation` with sample context and assert rendered output contains the provided test code and criterion fields\n- Tests assert the rendered prompt includes instructions for JSON fields `covers` and `reason`\n- Prompt package tests pass with the new coverage validation cases\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k5lbt.3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add prompt tests for coverage validation rendering","updated_at":"2026-02-19T20:49:32Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-19T18:20:34Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"88061e48a1a4cd12a3f5271528e9b3318029ea55d54630f8f84f9d97b4f404cb","created_at":"2026-02-19T14:11:03Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/runner/process.go -- when ScopeCheck.Enabled is true and complexity is high, escalation to TierHigh fires twice: first in setupBeadContext (line 82-85), then again in buildPromptForBead (line 117-119). The second call may also trigger a redundant LLM invocation. Guard the scope check in buildPromptForBead to skip when tier is already high.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k6onw","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix double scope-check escalation in process.go","updated_at":"2026-02-19T18:20:34Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T09:39:27Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"479299f97fe2b8e6f838eedec8ca7c9e6c97a9285d14c77c2778e69373750b61","created_at":"2026-03-10T09:24:06Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add findingsDecomposePromptTemplate constant to internal/v2/stage/decompose/decompose.go. In Run, branch when req.Findings non-empty to use findings template (ignoring GapAnalysis). Include architectural context from plan file as optional reference.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k7gel","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add findings-based decompose prompt template","updated_at":"2026-03-10T09:39:27Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-03T04:48:39Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ad920028ff1907cdc7fc7da1272eb52b1d1191e9466386600a4eabf33e7afdac","created_at":"2026-03-03T04:33:00Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create `cmd/gromit/unstick.go` defining `unstickExecutor` interface and `unstickCmd` cobra command. With a bead ID arg, call `Unstick` and print confirmation. Without args, call `ListStuck`; print \"No stuck beads\" if empty, otherwise show a numbered list and read a stdin integer selection. Wire via `createUnstickPipelineFn`. Tests in `unstick_test.go` use a mock `unstickExecutor`.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k8kax","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add gromit unstick CLI command","updated_at":"2026-03-03T04:48:39Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Resolution priority is: --agent flag \u003e picker \u003e agents.phases config \u003e \"claude\" default\nUser-defined definition fields override preset defaults; missing fields use preset\nUnknown agent name returns clear error","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-08T17:47:41Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"08c5d140119693be5cb5ed57ab1fb41b80e53d886ec950becc24db83c5ed2edd","created_at":"2026-02-08T09:09:11Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement Resolve(cfg *config.Config, phase string, flagOverride string, chooseAgent bool, r io.Reader, w io.Writer) (Agent, error) in internal/agent/resolve.go. Follow resolution priority: flag override, picker (if chooseAgent or agents.prompt), phase config, \"claude\" default. Merge user-defined definitions with preset defaults.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k9mi","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement Resolve function with priority logic","updated_at":"2026-02-08T17:47:41Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"BuildComplexityRepromptFeedback(highComplexity []CandidateComplexityResult) string function\nFeedback section for split-concerns guidance\nFeedback section for reduce-breadth guidance\nFeedback section for preserve-semantics guidance\nFeedback section for avoid-overlap guidance\nPer-candidate reason citations in feedback output\nTest: feedback is empty when no high-complexity candidates\nTest: feedback includes all flagged candidate reasons\nTest: feedback follows existing reprompt composition patterns","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-23T02:08:37Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"b8cba836e7d152143ca886436ae62f2310c5db506472913daa6b8b5a4eac4473","created_at":"2026-02-22T21:20:28Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add BuildComplexityRepromptFeedback in internal/validate/reprompt.go that takes high-complexity candidates with their reasons and generates structured feedback instructing finer decomposition while preserving semantic intent and preventing sibling overlap. Follow existing reprompt composition patterns. Cover formatting and inclusion rules in reprompt_test.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k9qyt","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Extend reprompt feedback with complexity-reduction guidance","updated_at":"2026-02-23T02:08:37Z","waiters":"","wisp_type":"","work_type":""} @@ -1429,6 +1445,7 @@ {"acceptance_criteria":"internal/validate/reprompt.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-23T03:02:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7b80692f0bc0c767c271164fa67c3696df7ec5825c9fea0c13204c85091f30b2","created_at":"2026-02-23T02:08:35Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k9qyt.2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement structured complexity-reduction guidance sections and per-candidate reason citations","updated_at":"2026-02-23T03:02:01Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"internal/validate/reprompt_test.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-23T02:59:55Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3dcc27f77acda6123e44e1de278b868b51a02d2942c4a7eacd050c4337e7a7d1","created_at":"2026-02-23T02:08:36Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-k9qyt.3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add coverage for reason inclusion and composition-pattern conformance in complexity reprompt output","updated_at":"2026-02-23T02:59:55Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"User can set push_timeout: 0 in config to disable git push timeout","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:27Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"69a90710328cd370ab70c94a8bab887b6e24411d9aa75715b3e2807e451babc8","created_at":"2026-02-19T16:25:41Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"config.go:693-694 sets PushTimeout to 60 when it is 0, but PushTimeoutDuration() documents 0 disables the timeout. A user who sets push_timeout: 0 in gromit.yaml to disable push timeouts gets silently overridden to 60 seconds. Fix: use a pointer type (*int) or sentinel value (-1) to distinguish not set from explicitly zero.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-ka3fp","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix PushTimeout default overriding user zero value","updated_at":"2026-03-02T19:42:27Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T05:37:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"4736c66245453d9027eb76a97200b898143c80f872100cabe4dbd46e2e51606c","created_at":"2026-03-10T05:35:24Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Update internal/v2/stage/specreview/specreview.go to normalize the aggregate verdict from individual findings, emitting 'fail' instead of 'issue' when criteria are not met. Modify verdictFromFindings() to return 'fail' when any finding has verdict 'issue', update decisionFromArtifacts() to check for 'fail', and update tests in specreview_test.go to match.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-kavnv","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix spec-review verdict to normalize 'issue' to 'fail'","updated_at":"2026-03-10T05:37:20Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- [ ] Retry counter (attempts int) added before the for loop at runner.go:251\n- [ ] Counter incremented at the top of each loop iteration\n- [ ] When attempts \u003e= cfg.Escalation.MaxRetriesPerBead, exits loop with error: \"bead exceeded max retries (\u003cN\u003e attempts)\"\n- [ ] Check happens before both recoverable retry and escalation paths\n- [ ] Partial progress is shown (showPartialProgress) when limit hit\n- [ ] Counter value logged on each attempt: \"Attempt 2/3...\"\n- [ ] go build ./... passes","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Breaking down into smaller tasks","closed_at":"2026-02-05T19:59:04Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f76a4c3d1753cbaf6183380dcba6807a57530fd345b106d7be61023b5be4327c","created_at":"2026-02-05T19:44:15Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add a retry counter to the escalation loop in runner.go processBead(). Increment on each attempt (recoverable retry or escalation). When MaxRetriesPerBead is reached, stop retrying and return a clear error.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-kaz","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Enforce per-bead retry limit in runner escalation loop","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-08T15:02:32Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8cbe0309a825dafa3edbe14ed537986e0cb1716efab236c0aee9e15d8f4a4d2c","created_at":"2026-02-08T13:01:06Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"## Problem\nParallel post-success tests have two categories of failures blocking every iteration:\n\n### Timing flakiness\n- TestParallelPostSuccess_BothStagesExecuteConcurrently: hardcoded \u003c450ms threshold fails under load\n- TestAcceptance_ParallelPostSuccess_ConcurrentExecution: same issue\n\n### Logic bugs\n- TestParallelPostSuccess_NeitherEnabled: review called when disabled\n- TestAcceptance_ParallelPostSuccess_ReviewRevalidationErrorPropagates: Run() succeeds when it should fail\n- TestRunValidationPostSuccess_ParallelExecution: review never starts\n\n## Acceptance criteria\n1. Replace timing-based concurrency assertions with channel/synchronization-based assertions that prove concurrency without wall-clock thresholds\n2. All parallel post-success tests (unit and acceptance) pass reliably\n3. go test -tags acceptance ./internal/runner/ passes with no flaky failures","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-kcdt","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix flaky parallel post-success tests and logic bugs","updated_at":"2026-02-08T15:02:32Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- [ ] Default ralph retro: analysis -\u003e display -\u003e parse JSON -\u003e interactive review -\u003e apply\n- [ ] --non-interactive flag skips interactive review\n- [ ] --suggest flag preserves legacy write-to-file behavior\n- [ ] If JSON parse fails, falls back to --suggest behavior with warning\n- [ ] go build ./... passes","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-06T05:46:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"0ff1e01bb2752e035df0c7da0ee84762c68b6fcb9b5749841f1711f120f9e112","created_at":"2026-02-06T05:20:44Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Update cmd/ralph/main.go. Default ralph retro flow: analysis -\u003e display -\u003e parse JSON -\u003e interactive review -\u003e apply. --non-interactive / --suggest: legacy write-to-file behavior. Fallback: if JSON parse fails, fall back to --suggest behavior.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-kcl","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"CLI integration — make interactive retro the default","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} @@ -1459,6 +1476,7 @@ {"acceptance_criteria":"The `err != nil` fallback block no longer contains duplicated branch formatting logic.\nThe path passes correct `failureClass`, primary, and fallback context values into `fallbackErrorResult`.\nBehavioral tests for the `err != nil` fallback outcomes still pass.","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-21T08:41:33Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"407dde71cf82166778edc704d6b7a928c24419feda45bf0d9bf08bf4b97e3add","created_at":"2026-02-21T08:35:03Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Refactor the `err != nil` path inside `makeMethodologyExec()` to call `fallbackErrorResult` instead of duplicating the three-branch fallback formatting logic.\n\nAcceptance criteria:\n- The `err != nil` fallback block no longer contains duplicated branch formatting logic.\n- The path passes correct `failureClass`, primary, and fallback context values into `fallbackErrorResult`.\n- Behavioral tests for the `err != nil` fallback outcomes still pass.\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-kkss1.2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Use helper in err!=nil fallback flow","updated_at":"2026-02-21T08:41:33Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"The `!result.Success` fallback block no longer duplicates the three-branch formatting logic.\nBoth primary failure paths now rely on the same helper for fallback error construction.\nAll affected callback/ATDD tests pass with no regression in emitted error text.","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-21T08:46:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"27150663595d01329627b09466e25321c6b9dabcc2da874656e87accaca6446a","created_at":"2026-02-21T08:35:04Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Refactor the `!result.Success` path inside `makeMethodologyExec()` to reuse `fallbackErrorResult`, removing the second duplicated fallback formatting block.\n\nAcceptance criteria:\n- The `!result.Success` fallback block no longer duplicates the three-branch formatting logic.\n- Both primary failure paths now rely on the same helper for fallback error construction.\n- All affected callback/ATDD tests pass with no regression in emitted error text.\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-kkss1.3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Use helper in !result.Success flow","updated_at":"2026-02-21T08:46:20Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Fix DiffFiles returning nil slice instead of empty slice","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:30Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"476ef42995c365f7c0754515c503ad836c1e52b1a72263431ecb249708411cfa","created_at":"2026-02-12T11:33:33Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/pipeline/helpers.go DiffFiles() uses 'var diff []string' which returns nil when no differences found. This violates the project rule that nil slices should be converted to empty slices (normalizeNilFields pattern). Change to 'diff := []string{}' for JSON serialization consistency (null vs []).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-kkst","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix DiffFiles returning nil slice instead of empty slice","updated_at":"2026-03-02T19:42:30Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T05:12:35Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"6f9c5e817d85d41cf3aa39ccc9d036bca0b7a0d64a809915330a674367394d32","created_at":"2026-03-10T04:50:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In cmd/gromit/run2_test.go or internal/v2/loop test file, write a test demonstrating that the from-review execution path calls BeadLoop.Run/RunWithoutReview directly and never invokes accept or spec-review stages. Use instrumented/fake stages that record whether they were called and assert accept and spec-review were NOT called while bead loop WAS called.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-klkbj","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add test proving from-review beads bypass spec-level stages","updated_at":"2026-03-10T05:12:35Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"When providers are present and routing is empty, defaults are applied (equal ratio, 30m cooldown, fallback enabled for multi-provider)\nWhen providers are present and routing has user values, those values are preserved\nWhen no providers are present, routing section is untouched","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-12T17:02:11Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"df50476294d212730c0dd44dcb79a82edbd45f021b235253e09281947a237a69","created_at":"2026-02-12T16:45:01Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify SetDefaults() in internal/config/config.go to fill in missing routing defaults when providers are present: initialize empty PhasePreferences map, build equal-split Ratio from provider names, set Fallback.Cooldown to 30m, and enable Fallback for multi-provider configs. Add tests in internal/config/config_test.go verifying defaults are applied when routing is empty, user values are preserved, and routing is untouched when no providers present.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-klxl","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add routing defaults to SetDefaults() with tests","updated_at":"2026-02-12T17:02:11Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T17:59:16Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ff34d6d352996d136bad3f3ed54c0b492e3d4e664733687e4ddcd3a2e28e3f2e","created_at":"2026-02-07T03:11:08Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Three separate implementations of yes/no user prompts exist: (1) confirmPrompt() in chain.go using bufio.Reader with full y/yes/n/no parsing, (2) promptReviewBeads() in decompose.go using bufio.Reader with y/yes check, (3) various other commands using similar patterns. promptReviewBeads should call confirmPrompt instead of reimplementing the logic. This prevents divergent behavior (e.g. confirmPrompt handles YES but promptReviewBeads may not handle all cases consistently).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-km8","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Consolidate duplicate yes/no prompt patterns","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T20:58:39Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5ea9df9987b1928d2d38f5c5fd2b010b2d36bd5da188b7f432d2037ec5fe040a","created_at":"2026-02-07T10:14:25Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"cmd/gromit/review.go runReviewInteractive returns cmd.Run() errors directly, including *exec.ExitError when the user exits Claude normally. Both plan.go:204-210 and refine.go:206-212 correctly handle this by returning nil for ExitError. Apply the same pattern in review.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-knc","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Handle ExitError consistently for interactive Claude sessions","updated_at":"2026-02-07T20:58:39Z","waiters":"","wisp_type":"","work_type":""} @@ -1683,6 +1701,7 @@ {"acceptance_criteria":"Scope gate attempts decomposition before blocking oversized beads\nFalls back to Block if Decomposer is nil or decomposition fails\nUnit tests for scope-triggered decomposition in gate_test.go\nDecomposer wired in constructor.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-22T18:10:22Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"219d215358f35f8e93cd0e3ed69180037ec70caa6640bafc7b319208cf5e593d","created_at":"2026-02-22T14:03:55Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"When the scope gate detects a bead with \u003e5 expected outputs, it currently returns Block. It should instead attempt decomposition via the Decomposer interface (already defined in gate.go) and return Skip on success, falling back to Block only if decomposition fails or Decomposer is nil. Changes needed: (1) gate.go:113-122 - call g.decomposer.Decompose() before blocking, (2) gate_test.go - add test for scope-triggered decomposition, (3) constructor.go - wire a Decomposer implementation into the Gate stage. Note: the Decomposer interface and WithDecomposer() already exist; this is about using them for scope gate violations, not just proactive keyword-based decomposition.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-nwhgo","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Scope gate should auto-decompose oversized beads instead of blocking","updated_at":"2026-02-22T18:10:22Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-05T12:50:45Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"241d2e1d80eda4586fc99ee063d799606dceab61eeccb7e033f1e3211e316c9a","created_at":"2026-02-05T11:49:07Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement the `ralph retro` command that:\n1. Reads LEARNINGS.md\n2. Uses opus to analyze patterns and consolidate learnings\n3. Proposes changes to RULES.md\n4. Outputs a summary of proposed changes\n5. Supports `--apply` flag to apply changes\n\nThe retro prompt should:\n- Identify duplicate/related learnings\n- Consolidate them into single entries\n- Propose promoting patterns to RULES.md\n- Suggest archiving stale learnings\n\nCreate cmd/ralph/retro.go and internal/retro/retro.go","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-nwl","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add ralph retro command","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T20:58:24Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8335d4dd6e0e86c4ab7044771acb0d597f17aa35deb22ff83d2d5506f0fff2c9","created_at":"2026-03-06T19:54:05Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Out-of-scope review findings never reach the success-path presenter summary. The spec requires: 'Out-of-scope review findings are emitted as events and included in the Present stage summary.'\n\nRoot cause: BeadRunner interface only returns error — no mechanism to propagate out-of-scope findings from review stages back to spec loop. buildSuccessSummary() never populates OutOfScopeFindings.\n\nFix options (pick simplest):\n1. Have spec loop subscribe to ReviewFinding events from the typed emitter and accumulate out-of-scope findings during bead execution\n2. Add an OutOfScopeFindings accumulator to BeadLoop that collects them from review stage artifacts, return via BeadLoopResult\n3. Store findings in a shared callback/channel\n\nThen populate OutOfScopeFindings in buildSuccessSummary().\n\nFiles: internal/v2/loop/spec_loop.go, internal/v2/loop/bead_loop.go","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-nwqme","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"fix: surface out-of-scope review findings in success-path presenter summary","updated_at":"2026-03-06T20:58:24Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T10:20:29Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a65749ddcaf27bfdd77b2bfcaeacd4d21d12eabe71337b7b0281434114c331f7","created_at":"2026-03-10T09:24:07Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create review_spec_v2.md at project root with spec-level review prompt instructing holistic diff review for correctness, security, error handling, test coverage, quality, and architectural fit. In internal/v2/loop/run2_components.go, load the prompt fragment, create specreview.Stage using highest-tier LLM provider, and wire into SpecLoop via WithSpecReviewStage option.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-nxhpg","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create review_spec_v2.md and wire spec-review stage in run2","updated_at":"2026-03-10T10:20:29Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-03T07:13:19Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"4bb43028dab3e45ad990032df2d7ddb7f89bb191dd5188e775845adb6cd8292f","created_at":"2026-03-03T04:24:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Remove the FreshContextPerCycle bool field and its yaml tag from MethodologyConfig in internal/config/config_types.go. Find and delete any test functions in config test files that set or assert on FreshContextPerCycle or fresh_context_per_cycle.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-nxp9w","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Remove FreshContextPerCycle from MethodologyConfig","updated_at":"2026-03-03T07:13:19Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T07:13:44Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7ddad98fedd4261d46eb8dafdf142a68ab40b72f18d6d1178210c0cc117bbce8","created_at":"2026-03-08T06:53:45Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create utilities in internal/v2/commit/message.go and message_test.go to encode and decode commit messages in the format [bead:\u003cid\u003e/\u003cstage\u003e/iter:\u003cn\u003e] \u003cDecision\u003e. Include validation that messages contain required fields and extraction of bead ID, stage name, iteration, and decision components.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o00gs","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add structured commit message formatting and parsing","updated_at":"2026-03-08T07:13:44Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Dropped-event observability added","closed_at":"2026-03-05T16:17:35Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"92a02daa911f949cffb8bf25641e25256834b7b0d863d0bde6775685f65a03aa","created_at":"2026-03-05T15:27:58Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Emitter.Emit (internal/events/emitter.go:64-71) silently drops events when the subscriber channel is full (100 buffered). No counter, log, or metric exists to detect this. Add a DroppedCount() method or periodic DroppedEventsEvent so operators can detect when important events like BeadFailedEvent are being lost.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o0cjy","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add dropped-event observability to events.Emitter","updated_at":"2026-03-05T16:17:35Z","waiters":"","wisp_type":"","work_type":""} @@ -1701,6 +1720,7 @@ {"acceptance_criteria":"executeClaudeInvocation returns provider.Result and no caller converts to claude.Result\nAll claude.IsValidationPassed/IsScopeTooLarge/GetScopeTooLargeBreakdown calls in runner replaced with provider package equivalents\nAll existing runner tests pass without modification","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-21T07:49:03Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"4a2f02af89dee2eddcdf241319132039ccd43897b89b690f7aaa5d3dd0ac38f2","created_at":"2026-02-12T15:44:11Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Refactor internal/runner/process.go and runner.go to use provider.Result instead of claude.Result. Change executeClaudeInvocation return type, update heartbeat channel type to provider.ToolEvent, remove handler type conversions, and replace all claude.IsValidationPassed/IsScopeTooLarge/GetScopeTooLargeBreakdown calls with provider package equivalents. Update runDirectValidationCheck to return provider.Result.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o5i4","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update runner to use provider-level abstractions","updated_at":"2026-02-21T07:49:03Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Review command accepts --spec flag\nReview --spec scopes to commits for that spec's beads\nReview --epic uses frontmatter-based resolver (not parent-child)","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-10T09:08:36Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8ea6d7b836056a95ae401a89dacfd6db57cc0fcfeda39e02cfb873f7e8d8fad3","created_at":"2026-02-08T17:00:34Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add --spec string flag to cmd/gromit/review.go. Update determineReviewScope() to add mutual exclusivity check between --epic, --spec, and --since. For --spec, resolve to bead IDs via scope.ResolveSpec() + bead.ListWithLabel(), then find earliest commit. For --epic, use scope.ResolveEpic() instead of parent-child resolution.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o5py","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add spec flag and update epic resolution in review command","updated_at":"2026-02-10T09:08:36Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"/tmp/bd-acceptance-1618735128.txt","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-18T23:18:02Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"713dc6b833c659d3819d9f150836185e3c0dfc0206ad0a23a012af5c5f651c11","created_at":"2026-02-18T22:51:48Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"In setupBeadContext() in internal/runner/process.go, call bead.FindSpecLabel(b.Labels) and store result on bc.Result.SpecID. In writeIterationLog() in internal/runner/logging.go, add SpecID: result.SpecID to the IterationLog struct literal. Add tests in internal/runner/process_test.go and internal/runner/logging_test.go covering extraction and propagation.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o869e","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Wire SpecID through bead context and logging pipeline","updated_at":"2026-02-18T23:18:02Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"29c3a2e9c0e6ab3e03d36d4ff2ce80a0a688659832c0cf39a4eef5e9fa8c2ee1","created_at":"2026-03-10T10:39:20Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify internal/v2/stage/decompose/decompose.go to add findingsDecomposePromptTemplate. Implement template selection logic: if req.Findings is non-empty, use findings template; else if req.Remediation \u0026\u0026 req.GapAnalysis != \"\", use remediation template; else use default. Findings template instructs creating one bead per finding (or grouped if related), including finding description in acceptance criteria, referencing affected_files. Include test coverage in decompose_test.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o8uk4","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Add findings-based decompose prompt template","updated_at":"2026-03-10T10:39:20Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-08T07:30:28Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"863e050080808a47f3bf866af7d7b9975ee3d742d2ba282ccd863a58caed1863","created_at":"2026-02-07T22:42:31Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/bead/bead.go adds ListReadyIDs() (lines 278-302) but no corresponding tests exist in bead_test.go. Should have tests for: empty result, multiple beads returned, JSON parse error, nil client, and bd command failure. Follows same pattern as existing CountReady tests.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o93z","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add unit tests for ListReadyIDs in bead package","updated_at":"2026-02-08T07:30:28Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Pipeline retry decisions use the same classification source as validate.ValidateDecomposeCandidates\\nReprompt complexity feedback includes non-estimated-files high-complexity reasons when present\\nRegression tests cover broad-scope and dependency-sequencing signals through pipeline retry flow","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-23T09:14:29Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"64b7c50e6d0b2b7756e82e196aa07b029d64062b703f43f232f94f1af7e2b6cf","created_at":"2026-02-23T09:02:07Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Complexity signals now include estimated_files, broad-scope language, and dependency-sequencing language in validate logic, but pipeline retry/feedback still uses estimated_files-only helpers. Replace split logic with one shared complexity classification path so retry behavior, warnings, and feedback reflect the same rules in all entry points.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o9i5v","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Unify complexity classification source across decompose validate and pipeline retry","updated_at":"2026-02-23T09:14:29Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Phase timeout fields parse from YAML: methodology.phase_timeouts.red_seconds, green_seconds, refactor_seconds and validation.phase_timeout_seconds\nResolver methods return existing bead_timeout defaults when phase timeout fields are zero or unset\nTests verify YAML override behavior and backward compatibility with existing configs","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-16T20:31:21Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7c0c31f1c592e3959dffc5f153d34a23263bc415f7f55044aac377af5232dccd","created_at":"2026-02-16T18:11:57Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add optional phase_timeouts struct to methodology config and phase_timeout_seconds to validation config in internal/config/config.go. Implement resolver methods that fallback to existing bead_timeout when unset. Update gromit.yaml with commented examples. Add tests in config_test.go covering YAML parsing, SetDefaults behavior, and backward compatibility when fields are omitted.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-o9ix","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add phase timeout configuration fields with defaults","updated_at":"2026-02-16T20:31:21Z","waiters":"","wisp_type":"","work_type":""} @@ -1757,6 +1777,7 @@ {"acceptance_criteria":"internal/config/config_test.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-22T22:37:02Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"0a73d78ea79361379c69c62e13646ba47fb1f31ead28d72c2103c0577cbe1a98","created_at":"2026-02-22T22:24:15Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-p0iei.4","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add config tests for Tier parsing, legacy Model auto-mapping, and MatchBuildModel deprecation warning","updated_at":"2026-02-22T22:37:02Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-22T04:01:53Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f800bde90277aaf667ff8a3629c60257fdf116905a71a14a6f1daade1fe64b68","created_at":"2026-02-22T02:44:25Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Seven production files in internal/runner/ exceed the 550-line limit: process_methodology.go (779), callbacks.go (756), lifecycle.go (655), runner.go (571), process.go (570), run_iteration.go (565), constructor.go (561). Priority targets: (1) process_methodology.go — extract ATDD red-phase logic into process_methodology_atdd.go, (2) callbacks.go — extract makeMethodologyExec (335 lines) into callbacks_methodology_exec.go, (3) constructor.go — extract adapter types into constructor_adapters.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-p1jek","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Split 7 runner production files exceeding 550-line limit","updated_at":"2026-02-22T04:01:53Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-09T12:53:25Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a29078a119df380cd4f05aa66e6763cfde3ae18ab209aca2ef4b687550f26a8e","created_at":"2026-03-09T11:55:30Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Update cmd/gromit/run2.go to add --from-review boolean flag and --spec string flag for scoping. When --from-review is set, skip plan/decompose/accept/specreview stages, query tracker for beads with from-review label (optionally filtered by spec label), and run bead loop directly without remediation cycles.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-p1t55","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add --from-review flag to run2 command","updated_at":"2026-03-09T12:53:25Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"0c1e2c0de66b3cb5ebbb0198f315669bd887af444c8db3db867b4e2a20d94e34","created_at":"2026-03-10T10:39:19Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify internal/v2/stage/accept/accept.go to extend AcceptArtifacts with Findings []Finding field. For each failed criterion, create a Finding with severity=critical, category=acceptance, scope=spec, description from criterion text and failure reason, affected_files from criterion mapping. Keep GapSummary for backward compat. Add test coverage in accept_test.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-p24bl","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Extend accept stage to emit structured findings","updated_at":"2026-03-10T10:39:19Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"flagContract struct defined with Name, Shorthand, Type, Default fields\nFlag contract table covers all commands with their expected flags\nTest verifies flags in help output match declared contract structs","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-06T23:16:32Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"b6151c63b75e77c14e0465f4bb87c6653afbf4c371e7b9da70595e81d68f8fea","created_at":"2026-02-06T22:43:29Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add flagContract struct type and TestCLIContract_Flags function to cmd/gromit/cli_contract_test.go. Define expected flags for all commands (root, run, init, decompose, plan, review, retro, backlog). Parse help text to verify flag presence.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-p2a","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add flag contract tests","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"IsActive honors atdd:true/atdd:false label overrides over config default\nPhaseTimeout falls back to bead timeout when phase timeout is unset\nShouldDeferPostSuccess returns true only when both atddActive and tddActive are false","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-18T18:14:30Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"33397337dcd7aa0deedec66818f1ade1cb5f9d67edd27e42b7693c862dd014ee","created_at":"2026-02-18T18:04:50Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/runner/policy/methodology.go with the MethodologyPolicy interface (IsActive, PhaseTimeout, MinRefactorBudget, MinRevalidationBudget, ShouldDeferPostSuccess) and ConfigMethodologyPolicy wrapping *config.Config. Create internal/runner/policy/methodology_test.go with tests covering label overrides, phase timeout fallback, budget durations, and deferral logic.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-p2hei","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement MethodologyPolicy interface and ConfigMethodologyPolicy","updated_at":"2026-02-18T18:14:30Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Completed","closed_at":"2026-03-09T05:51:09Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"c792c579e6aa4206ed411cdd2fdbbc540c398fffffd501a58eb10d42a0ce66f4","created_at":"2026-03-09T05:50:41Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Resolve run2 --from-review edge cases: avoid early case-sensitive spec validation, skip unlabeled from-review beads without failing run, and keep spec success path resilient when creating from-review beads fails. Also tighten label behavior to match scope rules and add regression tests.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-p3akg","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix from-review execution and non-blocking review bead creation","updated_at":"2026-03-09T05:51:09Z","waiters":"","wisp_type":"","work_type":""} @@ -1817,6 +1838,7 @@ {"acceptance_criteria":"All internal git commands in `lifecycle.go` call `r.runArgv` with explicit argv slices; no internal git command uses `r.runCmd`\n`BetweenIterationsCommand` remains on `r.runCmd` (shell path unchanged)\nTests verify `argvRunnerFn` receives correct program and args for at least git pull, git push, and git commit flows","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T05:40:54Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f3ce27f6e6c08969f9e6d661db63030026eec626627677f5481c1d6511880263","created_at":"2026-02-19T18:27:46Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Replace all `r.runCmd` calls for internal git operations in `lifecycle.go` with `r.runArgv` using explicit argv vectors. Covers: `git pull --rebase`, `git push`, `git status --short --branch`, `git status --porcelain -- .gromit/metrics`, `git add .gromit/metrics`, `git commit -m ...` (metrics), `git status --porcelain -- .gromit/state.json`, `git add .gromit/state.json`, `git commit -m ...` (state). Pass commit messages as a separate arg to `git commit -m`. Update `runner_test.go` (or `lifecycle_test.go`) with assertions on argv vectors.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-q1k8n","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Migrate lifecycle.go internal git commands to runArgv","updated_at":"2026-02-20T05:40:54Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"gromit.yaml includes state section with stale_threshold documentation\nComments explain crash detection and timestamp staleness\nDefault value of 60 is documented","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-08T00:14:06Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"cf0afc7c1684fee48689a2863bd0b47ce2656355f6540246b1eccd24c38604a1","created_at":"2026-02-07T22:39:04Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add commented state section to gromit.yaml with stale_threshold field documenting default of 60 minutes and explaining crash detection vs timestamp staleness.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-q224","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add state config section to gromit.yaml","updated_at":"2026-02-08T00:14:06Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"1. Default case behavior matches the comment (either update comment to match code OR update code to match comment — determine correct behavior from existing tests)\n2. Test covers unrecognized profile name input\n3. No silent fallthrough for typos in profile names","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-03T03:09:36Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"44bc263be463854a5ac5e753be92e5de16e9a34fd9d4b4354fc16e80e4e604f6","created_at":"2026-03-03T02:12:56Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/config/compatibility_resolution.go:39-51 — comment says 'Returns passthrough for all other profiles' but the default case returns 'go'. An unrecognized profile name (typo like 'goo') silently gets the 'go' adapter instead of failing or falling through to 'passthrough'.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-q3xsi","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix profileToAdapterName default case comment/code mismatch","updated_at":"2026-03-03T03:09:36Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"","closed_at":null,"closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"dad78dd79172bb0d1f6c63d96084afdb50cc32291f537c6ef3bb2127f499afb5","created_at":"2026-03-10T10:39:20Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Write integration test in internal/v2/loop/spec_loop_integration_test.go that exercises: bead loop → accept passes → specreview passes with warning/suggestion findings → from-review beads created with correct labels → spec proceeds to present. Mock LLM responses. Assert beads are created but not executed, and spec-scoped vs general labeling is correct.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-q436q","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"open","target":"","timeout_ns":0,"title":"Integration test for pass-with-improvements flow","updated_at":"2026-03-10T10:39:20Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Test verifies 3 consecutive skips triggers error\nTest verifies real build iteration resets counter\nTest verifies custom MaxConsecutiveSkips limit is respected","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-08T06:14:44Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f7467ee920ce96257a7ee69b5d791d9830e85fb23f9707e0815475c5477439f5","created_at":"2026-02-07T23:36:10Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add tests to internal/runner/interfaces_test.go for consecutive skip counter: limit reached (3 consecutive skips returns error), counter reset (skip, build, skip continues without error), and custom limit (config set to 2 stops at 2 skips).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-q4l8","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add tests for consecutive skip counter","updated_at":"2026-02-08T06:14:44Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"formatPipeline shows up to 3 items per category with \"and X more\" for overflow\nformatRun handles nil status and all running/not-running variants\nformatRun includes limit information when MaxIterations or TimeBudgetMinutes are set","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-07T11:44:09Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"bb9754813fb5a7c1baeb2421ee042319f63b20f06e150ac11f4fa67513996904","created_at":"2026-02-07T09:09:56Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/runner/format.go with formatPipeline(ps *pipeline.PipelineStatus) string and formatRun(s *Status) string. Pipeline shows counts and up to 3 items per category with overflow. Run handles four variants: running with/without limits, not running with/without history.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-q58","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement formatPipeline and formatRun functions","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-05T04:04:33Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"1052c80d6a0ac719e556bfa9a8e822a01fbb6057bc13812263c6b91c8a40a599","created_at":"2026-03-04T13:00:05Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/unstick/store.go Save() uses os.WriteFile directly to the target path. A crash mid-write leaves a corrupted file. The integrationqueue.Store already uses the correct pattern: write to a temp file, then os.Rename to the target (atomic on POSIX). Apply the same atomic write pattern to unstick.Store.\n\nAcceptance criteria:\n- Save() writes to a temp file in the same directory, then renames to the target path\n- Existing tests still pass\n- Add a test that verifies partial writes don't corrupt the store (e.g., simulate write error after partial content)\n- Pattern matches integrationqueue.Store's implementation\n\nKey file: internal/unstick/store.go","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-q64o1","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Make unstick.Store.Save() atomic via write-temp-then-rename","updated_at":"2026-03-05T04:04:33Z","waiters":"","wisp_type":"","work_type":""} @@ -1889,6 +1911,7 @@ {"acceptance_criteria":"buildThoroughReviewContext returns *ThoroughReviewInput\nCallers in pipeline.go work with typed return","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-14T09:13:55Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"368621b5f5ebb9599cbb75f1e5a94f4f715c709f787df5d2795caf61b7561e67","created_at":"2026-02-12T15:20:57Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Change buildThoroughReviewContext() in internal/pipeline/review.go to return *ThoroughReviewInput instead of map[string]interface{}. Update function body to construct typed struct.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-r8xq","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update review helpers to return typed structs","updated_at":"2026-02-14T09:13:55Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Completed","closed_at":"2026-03-04T09:50:53Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"37b8527374b56aafb53f6322dfca179f510b5236808c3a6866eb2a56851921bc","created_at":"2026-03-03T21:55:25Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add SetItems(items []ListItem) to ListModel clamping cursor to new length. Implement Render(width int) string producing a line-per-item view with a cursor marker on the selected row and scroll offset tracking. Add list_model_test.go covering boundary and scroll behavior.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-r9afc","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add SetItems and Render to ListModel with tests","updated_at":"2026-03-04T09:50:53Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Completed","closed_at":"2026-03-04T15:21:59Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"155b9149e440702e20541ceee4a30a3497cc217c6f36beb4e660ad0eadfd9c46","created_at":"2026-03-04T12:11:03Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/config/config_normalize.go NormalizeNilFields() re-applies defaults for Methodology.BuildStrategy, PhaseModels, and Refactor.MinFilesChanged -- identical logic already in config_defaults.go SetDefaults(). NormalizeNilFields should only normalize nil slices/maps to empty values per CLAUDE.md convention, not re-apply defaults. This creates a maintenance trap where changes to SetDefaults may not be mirrored.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-r9lmv","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Remove duplicated default logic between SetDefaults() and NormalizeNilFields() in config","updated_at":"2026-03-04T15:21:59Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T10:06:40Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a1a279925076c9776e9e367191e55522bbc9e61cf6206bda97ecee9133314097","created_at":"2026-03-10T09:24:06Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add specReviewStage field and WithSpecReviewStage option to SpecLoop in internal/v2/loop/spec_loop.go. After accept passes, run specReviewStage if present. Handle verdicts: critical findings trigger remediation with findings; pass with warnings trigger from-review bead creation scoped by Finding.Scope. Update remediationRunner interface to accept findings parameter.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-r9zlh","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Integrate spec-level review stage with combined verdict logic","updated_at":"2026-03-10T10:06:40Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T02:18:34Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"faad9377b7fa9411b354c396ed803f988d3df1a1eb31de78be795d9e02b8e8cf","created_at":"2026-02-19T23:53:30Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/retro/retro.go:674 computes (efficiency.CostDelta / efficiency.HistoricalAvgCostPerBead) * 100 but HistoricalAvgCostPerBead can be zero on first run. The guard on line 669 only checks CostDelta != 0, not the denominator. Add a guard: if efficiency.HistoricalAvgCostPerBead != 0.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-raebx","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix division by zero in retro cost delta percentage","updated_at":"2026-02-20T02:18:34Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Migrate remaining non-streaming provider.Run stages to StreamRun","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:29Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3e9e88e9819d8ce1ee82e18512d9ed5799951300c00aa4518a5bd1ad6e477096","created_at":"2026-02-16T17:55:50Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Follow-up from refactor-stage streaming fix. Remaining non-streaming provider.Run paths include precheck/scope-check gates, review stages, decompose, success-learning, and analyzer; migrate selectively where live stream visibility is desired and preserve intentional non-streaming behavior where appropriate.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rbjh","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Migrate remaining non-streaming provider.Run stages to StreamRun","updated_at":"2026-03-02T19:42:29Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T15:02:27Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"95bd0ee6a28c1b5b31cec425df340896e599a84fd304c7f13f15d7afb1770b64","created_at":"2026-03-08T13:37:58Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/v2/stage/present/branch_cleanup.go that deletes the spec's worktree branch after successful PR merge confirmation. Integrate into success path of Present stage.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rc6q8","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement branch cleanup on success","updated_at":"2026-03-08T15:02:27Z","waiters":"","wisp_type":"","work_type":""} @@ -1910,6 +1933,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:29Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a831e37e21d5840de96c0c3d8d42f62513850dca263c491b85eabf226f167648","created_at":"2026-02-18T18:37:20Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Created by LLM during thorough code review. The LLM should make as many design decisions as possible during refinement.\n\ninternal/learnings/learnings.go:629 writes headers as '### YYYY-MM-DD | BEAD_ID | CATEGORY'. RULES.md line 59 explicitly requires 'human titles (not bead IDs)'. The Learning struct has no Title field, which is the root cause. Fixing requires: adding Title field to Learning, updating all learning creation sites to generate descriptive titles, and migrating existing entries. Needs design decisions on: how to generate descriptive titles (LLM-generated from bead title? derived from learning content?), migration strategy for existing 100+ learnings, whether to backfill titles or only apply going forward.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rlucz","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"LEARNINGS.md header format uses bead IDs instead of descriptive titles","updated_at":"2026-03-02T19:42:29Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T03:18:47Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7d201f7000697da2b6a8a931d1c62169eed822913ef25058c9a706cbc1b4fbcc","created_at":"2026-02-19T23:53:13Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/logger/process_trend.go is 773 lines. Extract AsyncTrendUpdater into trend_updater.go and statistical utilities (percentileInt64, percentileFloat64, meanAndStdDev, etc.) into math_helpers.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rm417","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Split process_trend.go (773 lines) into multiple files","updated_at":"2026-02-20T03:18:47Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- [ ] CategoryTaskTooComplex constant added with comment 'Task scope too large for one iteration'\n- [ ] Added to validation switch in parseAnalysisOutput()\n- [ ] LearningCategory() maps task_too_complex to 'conventions'\n- [ ] go build ./... passes","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-05T21:03:18Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d77750f8a3d26d658968f7547b24fec42331ff83091a0e75e7fcaab80f2df81e","created_at":"2026-02-05T19:59:16Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add the task_too_complex failure category constant to the analyzer package. File: internal/analyzer/analyzer.go","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rmk","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add CategoryTaskTooComplex constant to analyzer","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T09:25:55Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7e84243fd3eb2e429624b2438620a6d0ed06027b9491684cbd0a56e34f91344a","created_at":"2026-03-10T09:24:06Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add a Finding struct to internal/v2/stage/stage.go with Severity, Category, Scope, Description, and AffectedFiles fields. Define string constants for severity (Critical, Warning, Suggestion), category (Bug, Acceptance, Security, Quality, TestGap, Architecture), and scope (Spec, General). Add Findings []Finding field to StageRequest.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rmmaq","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Define Finding type and constants in stage package","updated_at":"2026-03-10T09:25:55Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Codex acceptance tests no longer create inline shell mock binaries for core scenarios\nTests assert behavior via fixtures and call logs through the shared fake harness\nDefault lane tests run hermetically without Codex auth or network","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:25Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"c1abcb2c0f0431ed5439cda70496076c6004b1e0fb5259476a21a2457b5156ac","created_at":"2026-02-16T02:27:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Replace ad-hoc temp mock scripts in internal/provider/codex_streaming_acceptance_test.go and test/contracts/*codex* files with fake Codex binary and fixture files. Preserve behavioral assertions for args, parsing, and failure handling while removing inline shell scaffolding. Update internal/provider/codex_test.go if fixture plumbing needs minor updates.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rmv6","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Migrate Codex acceptance/contract tests to canonical fake","updated_at":"2026-03-02T19:42:25Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-21T22:00:30Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"4de96fc418130ce709fee8533dfdc0169e186585e5a64f94ead7f5a2aba70096","created_at":"2026-02-21T15:02:16Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"The 12 acceptance tests in internal/runner/ need to move to their own package before the runner is refactored, and they need fake implementations to compile. Create internal/runner/acceptance/ directory with helpers_test.go (package acceptance_test) containing mockBeadClient, mockClaudeClient, mockProvider, and other fakes extracted from existing runner _test.go files.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rmzva","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create runner acceptance package with fake helpers","updated_at":"2026-02-21T22:00:30Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-19T13:54:34Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"1fc29d3f848968d396bd2e58ab7c9dd5acf7326ea24d4759534d3f8e12143c78","created_at":"2026-02-19T09:08:30Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/logger/modelstats.go: ModelStats (lines 9-17) and SpecCost (lines 121-126) lack JSON tags. They are serialized via outputJSON in cmd/gromit/stats.go, producing PascalCase field names (TotalCostUSD, EscalationsTo) instead of snake_case (total_cost_usd, escalations_to), violating the project snake_case JSON convention.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-rn3h1","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add JSON tags to ModelStats and SpecCost structs","updated_at":"2026-02-19T13:54:34Z","waiters":"","wisp_type":"","work_type":""} @@ -2151,6 +2175,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-10T20:23:14Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a254cdfc648d3fce1b42468837728d9e82dd10684df6e97f3edf460eb03d927d","created_at":"2026-02-10T19:36:57Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Sonnet hit 7 invocation timeouts at exactly 10m0s (the old default). Per-model timeout infrastructure exists (config.go ModelTimeoutOverrides, TimeoutsForModel()) but gromit.yaml has no model_timeouts section configured. Add per-model timeout overrides to gromit.yaml: sonnet should get a longer invocation timeout (e.g. 1200s) since it consistently needs more time than the base 900s, and haiku should get shorter stall/bead timeouts for faster failure detection. Acceptance criteria: (1) gromit.yaml has a model_timeouts section with sonnet and haiku overrides, (2) go test ./internal/config/... passes with new config values loading correctly.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vbdo","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Configure per-model timeout overrides for sonnet in gromit.yaml","updated_at":"2026-02-10T20:23:14Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-17T02:22:54Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"2ce4a01271be61bcb66d82483bc68c66ab631791bffcaf7ff5ad2ecefb3da6b1","created_at":"2026-02-16T15:42:59Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement a standard escalation packet model/formatter containing failed command, exact error excerpt, L1/L2 attempts, state snapshot, risk level, and exactly three options with tradeoffs plus recommendation.\n\nFiles:\n- Create: internal/runner/andon/packet.go\n- Test: internal/runner/andon/packet_test.go\n\nAcceptance Criteria:\n- Packet includes all required fields from spec\n- Formatter outputs exactly three options and one explicit recommendation\n- Tests verify missing required fields fail validation\n\nNotes: Keep packet data structure separate from rendering so CLI/UI formatting can evolve.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vd7f","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement Andon escalation packet builder","updated_at":"2026-02-17T02:22:54Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-05T13:51:49Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d537869fbf949c24edf7e91efc03bdc16ca9f7ca9bd37a858e347b826c375b03","created_at":"2026-03-05T13:27:11Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/runner/validation/runner.go:184 silently discards the auto-fix error with `_ = r.autoFixFn(bc.StartCommit)`. If auto-fix fails (e.g., gofmt crashes), the failure is invisible. Should log the error so operators can diagnose why auto-fix didn't help.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vdhpv","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Log auto-fix errors instead of discarding them","updated_at":"2026-03-05T13:51:49Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T10:54:55Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"b190d24b1e6b1565ae4c1f265021dff518d0f279b57104224c466ee7bd7beb52","created_at":"2026-03-10T10:39:18Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create the Finding struct in internal/v2/stage/ with fields for severity (critical/warning/suggestion), category (bug/security/quality/test-gap/architecture/acceptance), scope (spec/general), description, and affected_files. Add Findings field to StageRequest. Implement ComputeVerdict function that returns \"fail\" for any critical finding, otherwise \"pass\". Include JSON serialization tags.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-veios","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Define shared Finding type with verdict logic","updated_at":"2026-03-10T10:54:55Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:39Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d8222c4e14682e303074a175aa092f2b7033f655467ad497d4f205d595dca581","created_at":"2026-02-22T22:16:58Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Write the concurrent session test using sync barriers (not real timing) to verify two sessions handle conflicts correctly. Depends on the fixture helper and single-session test being done first.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vf3h7","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add dual-session timing-isolated conflict test with sync barriers","updated_at":"2026-03-02T19:42:39Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"ReadStatus populates all new count fields when bead client is available\nWhen startedAt is nil, HasRunInfo is false and ClosedThisRunCount is 0\nAll existing pipeline tests pass with updated signature","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-11T11:52:41Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8fdcf83dbb3dddd0f0d81a1615f936c4b1e0bbbc57f06f09d9fd31fd51e28b76","created_at":"2026-02-11T07:42:16Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Change ReadStatus signature in internal/pipeline/status.go to accept startedAt *time.Time parameter. Query all bead statuses using the new Client methods, compute blocked count as open minus ready, and populate ClosedThisRunCount when startedAt is non-nil. Update internal/pipeline/status_test.go to pass nil for the new parameter in existing tests.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vflg","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Update ReadStatus signature and populate counts","updated_at":"2026-02-11T11:52:41Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- [ ] Promotes provisional learnings listed in Promotions to confirmed\n- [ ] Removes stale learnings listed in StaleRemovals\n- [ ] Preserves unchanged learnings\n- [ ] go build ./... passes","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Replaced by interactive retro plan","closed_at":"2026-02-06T05:19:53Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f9d1e5c73aef2a6a5ce0a76b70677234aa804c8d86e497abcfcb8bbd8c3c1927","created_at":"2026-02-05T20:01:55Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Given parsed RetroChanges, promote specified provisional learnings to confirmed and remove stale ones. File: internal/retro/retro.go (or internal/learnings/learnings.go)","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vg2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Apply learning promotions and removals to LEARNINGS.md","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} @@ -2158,6 +2183,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Breaking down into smaller focused test beads","closed_at":"2026-02-05T19:33:35Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"e6b9716bbbb32694e735188aa3543d76e59727f12c938f8ec92e6ce4c114d04c","created_at":"2026-02-05T18:38:42Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"The config package (158 lines) has no tests.\n\n## What to test\n- SelectModel() logic (priority vs label precedence)\n- NextEscalationModel() chain traversal\n- Default value application\n- Invalid config handling\n- YAML parsing edge cases\n\n## Files\n- internal/config/config.go\n- internal/config/config_test.go (create)","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vgy","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add unit tests for config package","updated_at":"2026-02-07T18:29:38Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Retro struct no longer has claude field\nNewRetro() constructor removed — only NewRetroWithProvider exists\ncreateLearningsAdapter() and runAnalysis() use provider exclusively\nAll call sites updated and tests pass","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-12T16:50:30Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7b92b07a1cd33f49ced1baeb2502f0bb53efecc65210909c9b5d481fb41dee2e","created_at":"2026-02-12T06:34:47Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Remove the claude *claude.Client field from Retro struct. Remove NewRetro() constructor (keep only NewRetroWithProvider). Simplify createLearningsAdapter() and runAnalysis() to use provider exclusively — remove dual-branch claude/provider logic. Update all call sites that use NewRetro() to use NewRetroWithProvider(). Touches: retro.go, retro tests, caller updates.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vgzh","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Migrate retro.go to Provider-only","updated_at":"2026-02-12T16:50:30Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"No time.Sleep calls remain in default-suite test files except heartbeat tests\ngo test ./internal/runner/... passes with all sleep replacements","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-17T22:05:32Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"1d89aa1471f379e7ecb511a50ab16e49c1e4bdc9b87b4e63c0a8f14e149d03fc","created_at":"2026-02-16T02:32:44Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Replace time.Sleep calls in globalstats_integration_test.go:168 (2s sleep for timestamp separation), status_test.go (remaining 100ms sleeps after Task 1), and process_test.go:1463 (50ms sleep). Use explicit timestamp offsets, direct file/state writes, or channel-based synchronization instead. If no clean deterministic fix exists for globalstats test, move it to acceptance.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vh9j","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Replace time.Sleep calls in default suite tests","updated_at":"2026-02-17T22:05:32Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T05:43:52Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"6f7d4855c500165f45b869f81b9a0b86e0c30ae71c5820a2a41133c58950869a","created_at":"2026-03-10T05:35:24Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add integration test in internal/v2/loop/spec_loop_test.go that verifies the spec fails when accept passes but spec-review verdict is 'fail'. The test confirms ensureAcceptance() returns the combined failure and remediation is triggered, validating the verdict-level failure path.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vhvbr","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add integration test for combined accept+review gating","updated_at":"2026-03-10T05:43:52Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:39Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"73f9f41f879d082caa6ea2f24775ff75b5ec1617918f784757401629ed7c3568","created_at":"2026-02-22T22:17:13Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement the SPC formatter that renders control chart data into human-readable output. Tests must use deterministic sorting of metrics to avoid flaky assertions on map iteration order.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vipl2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add SPC formatter tests with deterministic metric sorting","updated_at":"2026-03-02T19:42:39Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-09T00:34:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"479391d35b041e666771c74028f2ef256d4b29d5f513675ef4fb770e2948f381","created_at":"2026-03-08T23:10:29Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify internal/v2/remediation/remediation.go to receive structured findings array from accept and review stages instead of gap analysis text. Pass findings to decompose stage via new field on stage.Request. Update executeRemediation to take findings parameter.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vj32h","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Refactor remediation runner to accept findings instead of gap analysis","updated_at":"2026-03-09T00:34:20Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Regression test: complexity evaluator called during decompose plan path\nRegression test: complexity evaluator NOT called during runtime decomposition path\nRegression test: reprompt feedback with complexity content present only in decompose path\nRegression test: retry loop stop conditions only active in decompose path\nConfirmation that all pre-existing validate_test.go tests pass\nConfirmation that all pre-existing decompose_test.go tests pass","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-23T02:12:26Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f8bec1650bc149033137016c84eff9e74fd4248c21826948e50a7152c215c5bc","created_at":"2026-02-22T21:20:31Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add focused regression tests in internal/pipeline/decompose_test.go and internal/validate/validate_test.go proving complexity optimization is active in the gromit decompose path and that non-plan/runtime decomposition behavior is unchanged. Ensure all pre-existing decomposition tests remain green.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-vj4fq","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add regression tests scoping complexity behavior to decompose only","updated_at":"2026-02-23T02:12:26Z","waiters":"","wisp_type":"","work_type":""} @@ -2305,6 +2331,7 @@ {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-03T06:36:57Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9222d3eda4b35a9e25e4271b1728c49ff62b37d54bbc491af5b62b1ffe7dce5c","created_at":"2026-03-03T04:28:09Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add a GateConfig struct with AutoGenerateCriteria *bool field and EffectiveAutoGenerateCriteria() helper to internal/config/config_types.go. Wire it as a Gate field on the top-level Config struct following the ReadinessCheckConfig pattern. Add tests in internal/config/config_types_test.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-xri0d","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add GateConfig to config types","updated_at":"2026-03-03T06:36:57Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-08T22:29:28Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"72633328dbf01256e9924c10da37f3258ff996d5891ae845ab0db8f23ae688d2","created_at":"2026-03-08T21:51:58Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create internal/v2/loop/integration_branch_lifecycle_test.go with integration tests to verify that worktree branch is preserved on failure (Andon or generation cap) with full history, and deleted on success (PR merged). Verify that event log remains accessible on preserved branch for debugging.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-xrjs0","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add integration tests for branch lifecycle","updated_at":"2026-03-08T22:29:28Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Completed","closed_at":"2026-03-04T21:07:39Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d1a5bd7d852fb209e9356770aa97f603ef0d87208527ceb4a990895bcf50b084","created_at":"2026-03-04T19:37:02Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement `PruneStaleSessionWorktrees()` in `internal/runner/specbranch/git_ops.go` (or a new `internal/worktree/worktree.go`) that lists all worktrees via `git worktree list --porcelain`, filters for dead session worktrees using the same liveness check introduced in Bead 0, and removes them. Call this function near the top of `Run()` in `internal/runner/orchestrator.go` before iteration begins.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-xtbdn","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add proactive stale worktree pruning at run startup","updated_at":"2026-03-04T21:07:39Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T05:44:51Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"2bbac4f850ab61b7c4af522ff5c61c690a048ac0daa7d017e91d2864f4b1225d","created_at":"2026-03-10T05:35:24Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Verify that TestGateClosesSatisfiedBead in internal/v2/stage/gate/gate_test.go passes and that WithSatisfactionCheck is wired in internal/v2/loop/run2_components.go during gate stage creation. Confirm the satisfaction check closes open beads whose acceptance criteria are met.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-xuo34","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Verify gate satisfaction check is wired and passing","updated_at":"2026-03-10T05:44:51Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T02:46:12Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"bacaf63875d5ef32dc9babac095b6444ed771ac563031dbb5c348ef2c5db7576","created_at":"2026-02-19T23:53:21Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/learnings/learnings.go is 791 lines. Extract parseLearnings into parser.go, FilterProvisional into filter.go, and text utility functions (similarity, trigrams, hashContent) into text_helpers.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-xv99p","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Split learnings.go (791 lines) into multiple files","updated_at":"2026-02-20T02:46:12Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"lifecycle.go is being deleted and rewritten as pipeline/epilogue/ stage — splitting a file that won't exist is wasted work","closed_at":"2026-02-21T14:29:39Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"e84f5740edb23470b4f20ad268f585f455e8e4d97a20cc9b5ba0ef934a904e09","created_at":"2026-02-19T23:53:26Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/runner/lifecycle.go is 608 lines. Extract worktree-merging and between-iterations-command methods into a separate file to bring it under the limit.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-xvurl","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Split lifecycle.go (608 lines) to meet 500-line limit","updated_at":"2026-02-21T14:29:39Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Remove dead code: wrapPhaseError and no-op interface assertions","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"runner.go and callbacks.go rewritten from scratch — dead code simply won't be ported to new orchestrator.go","closed_at":"2026-02-21T14:30:08Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d646d4a7645e8613f9c58ff5fa7cd13ddedb666b60c41602f3a676a018e792f5","created_at":"2026-02-19T01:20:31Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Two dead code items found in runner package: (1) wrapPhaseError in runner.go:319-330 is defined but never called — it overlaps with setPhaseAttribution + wrapRefactorValidationError. (2) var _ provider.Provider = nil and var _ execution.Provider = nil in callbacks.go:491-492 are no-op assertions — nil always satisfies any interface. Either remove them or change to verify concrete types (e.g. var _ provider.Provider = (*someType)(nil)).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-xx3z7","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Remove dead code: wrapPhaseError and no-op interface assertions","updated_at":"2026-02-21T14:30:08Z","waiters":"","wisp_type":"","work_type":""} @@ -2318,6 +2345,7 @@ {"acceptance_criteria":"`applyRefactorStreamStats` increases `bc.CumulativeInputTokens` by the same refactor input-token amount it applies to `bc.Result.InputTokens`.\nA unit test covering refactor stream stats fails before the change and passes after, asserting both counters move together.\nNo existing non-refactor token accounting behavior regresses in package tests.","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T15:35:28Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3a876b1b8b8603a183a2ac33c6dbf43498296f7cdbfbed7ff5d60601a1fc2877","created_at":"2026-02-20T11:56:30Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Update `methodology/refactor.go` so `applyRefactorStreamStats` increments `bc.CumulativeInputTokens` whenever it adds refactor-phase input tokens to `bc.Result.InputTokens`.\n\nAcceptance criteria:\n- `applyRefactorStreamStats` increases `bc.CumulativeInputTokens` by the same refactor input-token amount it applies to `bc.Result.InputTokens`.\n- A unit test covering refactor stream stats fails before the change and passes after, asserting both counters move together.\n- No existing non-refactor token accounting behavior regresses in package tests.\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-y5r3i.1","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Count refactor input in cumulative token totals","updated_at":"2026-02-20T15:35:28Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"When cumulative tokens cross the configured cap due to refactor usage, `checkRetryBudgetBeforeAttempt` rejects the next attempt.\nA targeted retry-budget test demonstrates a sequence where refactor tokens alone can trigger budget exhaustion.\nA control case under the cap still permits retry attempts.","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T15:38:21Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"02c896de9149b14e74de6b9681395959797a7abcd3aa017e02056fae54863c14","created_at":"2026-02-20T11:56:31Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Ensure retry-budget evaluation uses the updated cumulative totals so refactor tokens are included when `checkRetryBudgetBeforeAttempt` decides whether another attempt is allowed.\n\nAcceptance criteria:\n- When cumulative tokens cross the configured cap due to refactor usage, `checkRetryBudgetBeforeAttempt` rejects the next attempt.\n- A targeted retry-budget test demonstrates a sequence where refactor tokens alone can trigger budget exhaustion.\n- A control case under the cap still permits retry attempts.\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-y5r3i.2","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Gate retries on refactor-augmented token budget","updated_at":"2026-02-20T15:38:21Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"A workflow-level test with multiple refactor cycles stops once the configured token budget is reached.\nThe failure path is attributable to token-budget enforcement, not an unrelated termination condition.\nThe regression test would fail if refactor-phase tokens were excluded from cumulative accounting.","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T16:16:19Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ecf12ef7e642bb3ff345e831b0971a23b762c4dc409617594758b3a898c58458","created_at":"2026-02-20T11:56:32Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add an end-to-end regression test for repeated refactor cycles to verify a bead cannot exceed token budget by looping through refactors.\n\nAcceptance criteria:\n- A workflow-level test with multiple refactor cycles stops once the configured token budget is reached.\n- The failure path is attributable to token-budget enforcement, not an unrelated termination condition.\n- The regression test would fail if refactor-phase tokens were excluded from cumulative accounting.\n","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-y5r3i.3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add regression for refactor-loop budget overrun","updated_at":"2026-02-20T16:16:19Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T04:54:34Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"c8f1bf68ed61d6d59c783eb332d3503efae4fbdbd049601623baa524465dcabf","created_at":"2026-03-10T04:50:01Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Change TaskTracker to TaskTrackerAdapter in cmd/gromit/run2.go line 65 to fix production compilation error.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-y67or","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix TaskTracker type in run2.go","updated_at":"2026-03-10T04:54:34Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"MergeBack reports conflict-specific errors only when git indicates an active conflict state\\nNon-conflict merge failures preserve root cause without conflict wording\\nTests cover both conflict and non-conflict merge failure paths","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-23T15:32:45Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9c7f1e3b666ad8e6f762bd5e0b00e1aa02b7d8e602af0c4c4f75ce3e88b6cba1","created_at":"2026-02-23T15:25:00Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"internal/worktree/worktree.go currently labels regular merge failures as merge conflicts and always attempts git merge --abort. This can misreport non-conflict errors (missing branch, invalid repo state, unrelated git failures) and hide root cause semantics.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-y7flm","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Differentiate MergeBack conflict vs non-conflict failures","updated_at":"2026-02-23T15:32:45Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Codex agent preset uses Stdin delivery mode with exec and mandatory flags in flags slice\nTestResolveCodexPreset verifies promptDelivery is Stdin, flags include exec and operational flags, and promptFlag is empty\nGemini agent preset unchanged and existing claude/gemini tests pass","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-14T14:23:52Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"923cfb7374c386b74d778abee5ada2d43ac72240e77bf76218a56bfc12abec48","created_at":"2026-02-12T15:55:04Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Update internal/agent/resolve.go to create Codex agent with Stdin prompt delivery instead of PromptFileArg. Add codex-specific preset function setting promptDelivery to Stdin, flags to ['exec', '--full-auto', '--skip-git-repo-check', '--color', 'never'], and empty promptFlag. Update TestResolveCodexPreset in resolve_test.go to verify new delivery mode and flags.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-y8uq","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix Codex agent preset to use stdin delivery","updated_at":"2026-02-14T14:23:52Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"Gate fires when last spec bead closes in a scoped run with auto_trigger enabled and no remaining open beads for the spec label\nGate does not fire when: open beads remain, auto_trigger is disabled, SpecGate is disabled, not in a scoped run, or max_cycles is exhausted\nCycle count increments per spec name and stops gate at max_cycles; fix beads are created and picked up by subsequent loop iterations","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-20T16:29:59Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"b52533607171922bf5c5843e9234472575dd38fb9529f96e567cfe0ae9888fdf","created_at":"2026-02-18T17:22:05Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Add specGateCycles map[string]int to runLoopState in internal/runner/run_init.go. Add specGate *specgate.Gate field to Runner in runner.go, constructed in NewRunner when enabled. Add maybeRunSpecGate() method in run_iteration.go called from handleSuccessfulIteration() after beads.Sync(). Logic: check enabled/auto_trigger, extract spec label from bead, check remaining open beads, check cycle limit, run gate, synthesize fix beads on failure. Update run_iteration_test.go with the full auto-trigger decision matrix.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-y9p0g","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Wire spec gate auto-trigger into runner","updated_at":"2026-02-20T16:29:59Z","waiters":"","wisp_type":"","work_type":""} @@ -2406,6 +2434,7 @@ {"acceptance_criteria":"Remove dead code: convertToClaudeResult, processStreamJSON, contains/containsString","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"stale: db reset","closed_at":"2026-03-02T19:42:29Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ba5b13e7bc4120837774b8971455c039ab964b50e11926a634320fb077e23dfe","created_at":"2026-02-18T18:37:09Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Three dead code sites: (1) internal/provider/claude.go:86-94 convertToClaudeResult is never called, (2) internal/claude/claude.go:439-441 processStreamJSON wraps processStreamJSONWithCost but is never invoked, (3) cmd/gromit/init.go:218-229 custom contains/containsString reimplements strings.Contains. Delete all three and replace init.go usage with strings.Contains.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-zpqdj","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dabrams@example.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Remove dead code: convertToClaudeResult, processStreamJSON, contains/containsString","updated_at":"2026-03-02T19:42:29Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T10:09:07Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"dbe5ca0cb41a3c87d6cabfc814a730a56aa17de154efa29089a7c9ed3fb000c5","created_at":"2026-03-05T20:31:25Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Create cmd/gromit/run2.go with run2 subcommand accepting a spec file path arg. Loads spec and checks dependencies via spec.CheckDependencies. Loads config. Wires Claude LLM, bd TaskTracker, GitHub Presenter, and exec Git adapters. Creates SpecLoop with wired adapters. Subscribes CLI progress and log writer event consumers. Runs spec loop. Exits 0 on success, non-zero on failure. Register in main.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-zq7iy","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement gromit run2 CLI command","updated_at":"2026-03-06T10:09:07Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-07T21:45:13Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"69ab5b9595f2bc3251228133e4eb1a78b4af3e2edbd4fd821a97a62d811ed4f7","created_at":"2026-03-07T20:41:50Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Modify internal/v2/loop/spec_loop.go to run validation commands scoped to flagged beads. If validation fails, mark bead incomplete and re-queue it. Execute this before starting bead loop on resume.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-zrrn7","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement selective revalidation in spec loop","updated_at":"2026-03-07T21:45:13Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-10T10:56:10Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a778bf12ca3e85518df5aaff4a6d4a0d32156ad93467464c3fdc81c24dbf9908","created_at":"2026-03-10T10:39:19Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Write review_spec_v2.md prompt fragment that instructs the model to evaluate cumulative diff holistically across six dimensions: correctness, security (OWASP top 10), error handling, test coverage, code quality, and architectural fit. Specify exact JSON output schema matching Finding struct. Include examples of critical/warning/suggestion findings and clear scope classification instructions (spec vs general scope).","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-zs7g7","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create spec-level review prompt fragment","updated_at":"2026-03-10T10:56:10Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-08T07:27:05Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"8d5e87550f7d79d2c4d5f9dca98a75905b5c86a03d4686edf086b574e51cdbb8","created_at":"2026-02-07T22:42:29Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Runner tests that don't specifically test precheck (e.g. TestRunWithMocks_SkipsStuckBeads, TestRunWithMocks_ClosesBeadOnSuccess at interfaces_test.go) don't set Precheck config. Since NewRunnerWithDeps doesn't call setDefaults(), precheck is disabled by default (nil Enabled pointer → IsEnabled() returns true, but empty Model means Claude.Run gets empty model string). This works accidentally but could break if defaults change. Consider either: (1) having NewRunnerWithDeps call setDefaults(), or (2) explicitly disabling precheck in tests that don't test it.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-zt4n","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"dan@danabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add precheck config to non-precheck runner tests to prevent accidental precheck execution","updated_at":"2026-02-08T07:27:05Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T10:09:07Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"754b0197d796e88d63b4463daf4f7fbc15e281dd38b81842da8c8bc8c7d6ef38","created_at":"2026-03-06T06:40:24Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"Implement internal/v2/event/emitter.go with a thread-safe Emitter. Supports Subscribe(func(Event)) and ensures each emitted event fans out to all subscribers without blocking on panicking or slow handlers. Tests should cover concurrency, backpressure isolation, and panic resilience. Follow TDD (red/green) workflow.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-zv7y1","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement thread-safe event emitter","updated_at":"2026-03-06T10:09:07Z","waiters":"","wisp_type":"","work_type":""} {"acceptance_criteria":"- SpecflowStoreFactory and SpecBranchCreatorFactory are passed as parameters (e.g., on a deps struct or as function args) rather than mutated as globals\n- No package-level mutation of runner.* factory globals in main.go\n- Existing tests still pass\n- go test ./cmd/gromit/... passes\n- go vet ./... passes\n\nKey file: cmd/gromit/main.go","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-04T19:10:33Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a810d05e53db6ac3b0f9acaf48d6a285340c82d730823b1c34a9237071f23508","created_at":"2026-03-04T13:05:25Z","created_by":"Dan Abrams","crystallizes":0,"defer_until":null,"description":"main.go runLoop temporarily replaces runner.SpecflowStoreFactory and runner.SpecBranchCreatorFactory package-level globals, calls functions, then restores them. This is not thread-safe — if multiple goroutines execute runLoop concurrently, they race on the global state. Unlike gromit-4tt9w which covers test seam vars, this is production code in main.go.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"gromit-zvc8u","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"me@thedanabrams.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Pass SpecflowStoreFactory and SpecBranchCreatorFactory as parameters instead of mutating globals","updated_at":"2026-03-04T19:10:33Z","waiters":"","wisp_type":"","work_type":""} diff --git a/.beads/backup/labels.jsonl b/.beads/backup/labels.jsonl index c82e1ef98..96f503be5 100644 --- a/.beads/backup/labels.jsonl +++ b/.beads/backup/labels.jsonl @@ -86,6 +86,9 @@ {"issue_id":"gromit-166sc","label":"spec:dynamic-code-map"} {"issue_id":"gromit-16zu4","label":"spec:tdd-cycle-coverage-tracker"} {"issue_id":"gromit-17zd","label":"spec:pipeline-extraction"} +{"issue_id":"gromit-181wx","label":"estimated-files:1"} +{"issue_id":"gromit-181wx","label":"gen:0"} +{"issue_id":"gromit-181wx","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-187wy","label":"gen:0"} {"issue_id":"gromit-187wy","label":"spec:immutable-pipeline"} {"issue_id":"gromit-188e6","label":"spec:v2-run-loop"} @@ -215,10 +218,16 @@ {"issue_id":"gromit-2na","label":"spec:immutable-pipeline"} {"issue_id":"gromit-2ndj","label":"spec:tskip-audit"} {"issue_id":"gromit-2ns","label":"spec:claude-skill"} +{"issue_id":"gromit-2octl","label":"estimated-files:2"} +{"issue_id":"gromit-2octl","label":"gen:1"} +{"issue_id":"gromit-2octl","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-2opey","label":"estimated-files:2"} {"issue_id":"gromit-2opey","label":"gen:1"} {"issue_id":"gromit-2opey","label":"spec:immutable-pipeline"} {"issue_id":"gromit-2pm","label":"spec:atdd-methodology"} +{"issue_id":"gromit-2q0ft","label":"estimated-files:3"} +{"issue_id":"gromit-2q0ft","label":"gen:1"} +{"issue_id":"gromit-2q0ft","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-2qf1","label":"from-review"} {"issue_id":"gromit-2qf1","label":"spec:immutable-pipeline"} {"issue_id":"gromit-2s2q","label":"spec:layered-failure-triage"} @@ -304,6 +313,9 @@ {"issue_id":"gromit-3i1ko","label":"estimated-files:2"} {"issue_id":"gromit-3i1ko","label":"gen:1"} {"issue_id":"gromit-3i1ko","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-3i6ff","label":"estimated-files:2"} +{"issue_id":"gromit-3i6ff","label":"gen:1"} +{"issue_id":"gromit-3i6ff","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-3i71i","label":"spec:spec-level-atdd-gates"} {"issue_id":"gromit-3ibd","label":"bug"} {"issue_id":"gromit-3ibd","label":"from-review"} @@ -469,6 +481,9 @@ {"issue_id":"gromit-50ggy","label":"benchmark"} {"issue_id":"gromit-50ggy","label":"from-review"} {"issue_id":"gromit-50ggy","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-50wzq","label":"estimated-files:2"} +{"issue_id":"gromit-50wzq","label":"gen:1"} +{"issue_id":"gromit-50wzq","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-51s","label":"spec:atdd-methodology"} {"issue_id":"gromit-51t64","label":"spec:tdd-cycle-coverage-tracker"} {"issue_id":"gromit-51t64","label":"tdd:true"} @@ -658,6 +673,9 @@ {"issue_id":"gromit-76o","label":"spec:tdd-methodology"} {"issue_id":"gromit-77xe5","label":"from-review"} {"issue_id":"gromit-77xe5","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-78vah","label":"estimated-files:1"} +{"issue_id":"gromit-78vah","label":"gen:1"} +{"issue_id":"gromit-78vah","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-791l5","label":"bug"} {"issue_id":"gromit-791l5","label":"from-review"} {"issue_id":"gromit-791l5","label":"spec:immutable-pipeline"} @@ -859,6 +877,9 @@ {"issue_id":"gromit-7snxt","label":"from-review"} {"issue_id":"gromit-7snxt","label":"refactor"} {"issue_id":"gromit-7snxt","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-7t6ch","label":"estimated-files:1"} +{"issue_id":"gromit-7t6ch","label":"gen:1"} +{"issue_id":"gromit-7t6ch","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-7ti5h","label":"estimated-files:2"} {"issue_id":"gromit-7ti5h","label":"spec:strengthen-quality-gates"} {"issue_id":"gromit-7tpvy","label":"spec:v2-run-loop"} @@ -927,6 +948,9 @@ {"issue_id":"gromit-8a52","label":"from-review"} {"issue_id":"gromit-8a52","label":"spec:immutable-pipeline"} {"issue_id":"gromit-8acg","label":"spec:decompose-complexity-estimation"} +{"issue_id":"gromit-8c38m","label":"estimated-files:1"} +{"issue_id":"gromit-8c38m","label":"gen:1"} +{"issue_id":"gromit-8c38m","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-8cj56","label":"spec:tdd-cycle-coverage-tracker"} {"issue_id":"gromit-8d1c","label":"spec:reduce-iteration-cost"} {"issue_id":"gromit-8dr","label":"spec:system-verification"} @@ -1147,6 +1171,9 @@ {"issue_id":"gromit-b0xw","label":"spec:pipeline-extraction"} {"issue_id":"gromit-b1l1i","label":"spec:v2-run-loop"} {"issue_id":"gromit-b1w","label":"spec:precheck-already-done"} +{"issue_id":"gromit-b39ja","label":"estimated-files:1"} +{"issue_id":"gromit-b39ja","label":"gen:1"} +{"issue_id":"gromit-b39ja","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-b3ope","label":"from-review"} {"issue_id":"gromit-b3ope","label":"refactor"} {"issue_id":"gromit-b3ope","label":"spec:runner-pipeline"} @@ -1190,6 +1217,9 @@ {"issue_id":"gromit-bkia1","label":"test-gap"} {"issue_id":"gromit-bkij","label":"spec:provider-cli-test-pyramid"} {"issue_id":"gromit-bkk","label":"spec:status-json-staleness"} +{"issue_id":"gromit-bkqc6","label":"estimated-files:1"} +{"issue_id":"gromit-bkqc6","label":"gen:0"} +{"issue_id":"gromit-bkqc6","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-bky","label":"spec:claude-skill"} {"issue_id":"gromit-bl8","label":"spec:pipeline-stages"} {"issue_id":"gromit-bl9k","label":"spec:acceptance-runtime-optimization"} @@ -1244,6 +1274,9 @@ {"issue_id":"gromit-ccy3e","label":"spec:decompose-low-complexity-bias"} {"issue_id":"gromit-ce1","label":"spec:review-system"} {"issue_id":"gromit-ce51l","label":"spec:phase-failure-rate-control-limits"} +{"issue_id":"gromit-ce7ua","label":"estimated-files:1"} +{"issue_id":"gromit-ce7ua","label":"gen:0"} +{"issue_id":"gromit-ce7ua","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-cfepn","label":"estimated-files:2"} {"issue_id":"gromit-cfepn","label":"gen:1"} {"issue_id":"gromit-cfepn","label":"spec:immutable-pipeline"} @@ -1580,6 +1613,9 @@ {"issue_id":"gromit-f8x2.3.3","label":"atdd:true"} {"issue_id":"gromit-f8x2.3.3","label":"tdd:true"} {"issue_id":"gromit-f95ip","label":"spec:spec-level-atdd-gates"} +{"issue_id":"gromit-f99rv","label":"estimated-files:2"} +{"issue_id":"gromit-f99rv","label":"gen:1"} +{"issue_id":"gromit-f99rv","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-f9c0p","label":"estimated-files:2"} {"issue_id":"gromit-f9c0p","label":"gen:0"} {"issue_id":"gromit-f9c0p","label":"spec:v2-loop-routing-and-resume"} @@ -1743,6 +1779,9 @@ {"issue_id":"gromit-hab86","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-haosl","label":"estimated-files:1"} {"issue_id":"gromit-haosl","label":"spec:tui-pipeline-view"} +{"issue_id":"gromit-hcio0","label":"estimated-files:2"} +{"issue_id":"gromit-hcio0","label":"gen:0"} +{"issue_id":"gromit-hcio0","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-hg222","label":"estimated-files:4"} {"issue_id":"gromit-hg222","label":"spec:unstick-beads"} {"issue_id":"gromit-hgu3","label":"spec:epic-scoped-execution"} @@ -2002,6 +2041,9 @@ {"issue_id":"gromit-k0bh","label":"from-review"} {"issue_id":"gromit-k0bh","label":"spec:immutable-pipeline"} {"issue_id":"gromit-k0qi","label":"spec:concurrent-interactive-worktrees"} +{"issue_id":"gromit-k1iky","label":"estimated-files:2"} +{"issue_id":"gromit-k1iky","label":"gen:1"} +{"issue_id":"gromit-k1iky","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-k1nj4","label":"spec:end-of-loop-command"} {"issue_id":"gromit-k3j","label":"spec:tdd-methodology"} {"issue_id":"gromit-k3o3","label":"spec:run-loop-reliability-speed"} @@ -2012,6 +2054,9 @@ {"issue_id":"gromit-k6onw","label":"from-review"} {"issue_id":"gromit-k6onw","label":"spec:immutable-pipeline"} {"issue_id":"gromit-k6onw","label":"tdd:false"} +{"issue_id":"gromit-k7gel","label":"estimated-files:1"} +{"issue_id":"gromit-k7gel","label":"gen:0"} +{"issue_id":"gromit-k7gel","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-k8kax","label":"estimated-files:2"} {"issue_id":"gromit-k8kax","label":"spec:unstick-beads"} {"issue_id":"gromit-k9mi","label":"spec:multi-agent-phases"} @@ -2022,6 +2067,9 @@ {"issue_id":"gromit-k9qyt.3","label":"spec:decompose-low-complexity-bias"} {"issue_id":"gromit-ka3fp","label":"from-review"} {"issue_id":"gromit-ka3fp","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-kavnv","label":"estimated-files:2"} +{"issue_id":"gromit-kavnv","label":"gen:1"} +{"issue_id":"gromit-kavnv","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-kcszq","label":"spec:bead-client-runfn-consolidation"} {"issue_id":"gromit-kcszq.1","label":"tdd:true"} {"issue_id":"gromit-kcszq.2","label":"tdd:true"} @@ -2066,6 +2114,9 @@ {"issue_id":"gromit-kkss1.3","label":"tdd:true"} {"issue_id":"gromit-kkst","label":"from-review"} {"issue_id":"gromit-kkst","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-klkbj","label":"estimated-files:2"} +{"issue_id":"gromit-klkbj","label":"gen:1"} +{"issue_id":"gromit-klkbj","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-klxl","label":"spec:wire-router-from-config"} {"issue_id":"gromit-km8","label":"consistency"} {"issue_id":"gromit-km8","label":"from-review"} @@ -2438,6 +2489,9 @@ {"issue_id":"gromit-nwe9y","label":"spec:runner-pipeline"} {"issue_id":"gromit-nwhgo","label":"spec:runner-pipeline"} {"issue_id":"gromit-nwqme","label":"spec:v2-run-loop"} +{"issue_id":"gromit-nxhpg","label":"estimated-files:2"} +{"issue_id":"gromit-nxhpg","label":"gen:0"} +{"issue_id":"gromit-nxhpg","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-nxp9w","label":"estimated-files:2"} {"issue_id":"gromit-nxp9w","label":"spec:remove-tdd-fresh-context"} {"issue_id":"gromit-o00gs","label":"estimated-files:2"} @@ -2472,6 +2526,9 @@ {"issue_id":"gromit-o5i4","label":"spec:codex-streaming-parity"} {"issue_id":"gromit-o5py","label":"spec:epic-scoped-execution"} {"issue_id":"gromit-o869e","label":"spec:cost-per-spec-metric"} +{"issue_id":"gromit-o8uk4","label":"estimated-files:2"} +{"issue_id":"gromit-o8uk4","label":"gen:1"} +{"issue_id":"gromit-o8uk4","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-o93z","label":"from-review"} {"issue_id":"gromit-o93z","label":"spec:immutable-pipeline"} {"issue_id":"gromit-o93z","label":"test-gap"} @@ -2572,6 +2629,9 @@ {"issue_id":"gromit-p1t55","label":"estimated-files:1"} {"issue_id":"gromit-p1t55","label":"gen:0"} {"issue_id":"gromit-p1t55","label":"spec:spec-level-review-and-targeted-remediation"} +{"issue_id":"gromit-p24bl","label":"estimated-files:2"} +{"issue_id":"gromit-p24bl","label":"gen:1"} +{"issue_id":"gromit-p24bl","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-p2a","label":"spec:system-verification"} {"issue_id":"gromit-p2hei","label":"spec:orchestration-policy-interfaces"} {"issue_id":"gromit-p44z","label":"spec:learning-quality-filter"} @@ -2656,6 +2716,9 @@ {"issue_id":"gromit-q3xsi","label":"bug"} {"issue_id":"gromit-q3xsi","label":"from-review"} {"issue_id":"gromit-q3xsi","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-q436q","label":"estimated-files:1"} +{"issue_id":"gromit-q436q","label":"gen:1"} +{"issue_id":"gromit-q436q","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-q4l8","label":"spec:precheck-loop-guard"} {"issue_id":"gromit-q58","label":"spec:expanded-status"} {"issue_id":"gromit-q64o1","label":"bug"} @@ -2761,6 +2824,9 @@ {"issue_id":"gromit-r9lmv","label":"from-review"} {"issue_id":"gromit-r9lmv","label":"refactor"} {"issue_id":"gromit-r9lmv","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-r9zlh","label":"estimated-files:1"} +{"issue_id":"gromit-r9zlh","label":"gen:0"} +{"issue_id":"gromit-r9zlh","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-raebx","label":"from-review"} {"issue_id":"gromit-raebx","label":"spec:immutable-pipeline"} {"issue_id":"gromit-rc6q8","label":"estimated-files:1"} @@ -2793,6 +2859,9 @@ {"issue_id":"gromit-rm417","label":"from-review"} {"issue_id":"gromit-rm417","label":"refactor"} {"issue_id":"gromit-rm417","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-rmmaq","label":"estimated-files:1"} +{"issue_id":"gromit-rmmaq","label":"gen:0"} +{"issue_id":"gromit-rmmaq","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-rmv6","label":"spec:provider-cli-test-pyramid"} {"issue_id":"gromit-rmv6","label":"tdd:false"} {"issue_id":"gromit-rmzva","label":"spec:runner-pipeline"} @@ -3165,11 +3234,17 @@ {"issue_id":"gromit-vdhpv","label":"bug"} {"issue_id":"gromit-vdhpv","label":"from-review"} {"issue_id":"gromit-vdhpv","label":"spec:immutable-pipeline"} +{"issue_id":"gromit-veios","label":"estimated-files:2"} +{"issue_id":"gromit-veios","label":"gen:1"} +{"issue_id":"gromit-veios","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-vflg","label":"spec:status-bead-breakdown"} {"issue_id":"gromit-vgsvw","label":"estimated-files:2"} {"issue_id":"gromit-vgsvw","label":"spec:unstick-beads"} {"issue_id":"gromit-vgzh","label":"spec:multi-provider-routing"} {"issue_id":"gromit-vh9j","label":"spec:reduce-runner-test-runtime"} +{"issue_id":"gromit-vhvbr","label":"estimated-files:1"} +{"issue_id":"gromit-vhvbr","label":"gen:1"} +{"issue_id":"gromit-vhvbr","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-vj32h","label":"estimated-files:3"} {"issue_id":"gromit-vj32h","label":"gen:0"} {"issue_id":"gromit-vj32h","label":"spec:spec-level-review-and-targeted-remediation"} @@ -3501,6 +3576,9 @@ {"issue_id":"gromit-xrjs0","label":"spec:immutable-pipeline"} {"issue_id":"gromit-xtbdn","label":"estimated-files:2"} {"issue_id":"gromit-xtbdn","label":"spec:fix-stale-worktree-branch-checkout"} +{"issue_id":"gromit-xuo34","label":"estimated-files:2"} +{"issue_id":"gromit-xuo34","label":"gen:1"} +{"issue_id":"gromit-xuo34","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-xv99p","label":"from-review"} {"issue_id":"gromit-xv99p","label":"refactor"} {"issue_id":"gromit-xv99p","label":"spec:immutable-pipeline"} @@ -3521,6 +3599,9 @@ {"issue_id":"gromit-y5r3i.1","label":"tdd:true"} {"issue_id":"gromit-y5r3i.2","label":"tdd:true"} {"issue_id":"gromit-y5r3i.3","label":"tdd:true"} +{"issue_id":"gromit-y67or","label":"estimated-files:1"} +{"issue_id":"gromit-y67or","label":"gen:1"} +{"issue_id":"gromit-y67or","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-y7flm","label":"bug"} {"issue_id":"gromit-y7flm","label":"from-review"} {"issue_id":"gromit-y7flm","label":"spec:concurrent-interactive-worktrees"} @@ -3668,6 +3749,9 @@ {"issue_id":"gromit-zrrn7","label":"estimated-files:2"} {"issue_id":"gromit-zrrn7","label":"gen:0"} {"issue_id":"gromit-zrrn7","label":"spec:v2-loop-routing-and-resume"} +{"issue_id":"gromit-zs7g7","label":"estimated-files:1"} +{"issue_id":"gromit-zs7g7","label":"gen:1"} +{"issue_id":"gromit-zs7g7","label":"spec:spec-level-review-and-targeted-remediation"} {"issue_id":"gromit-zt4n","label":"from-review"} {"issue_id":"gromit-zt4n","label":"spec:immutable-pipeline"} {"issue_id":"gromit-zt4n","label":"test-gap"} diff --git a/.gromit/v2/events.jsonl b/.gromit/v2/events.jsonl index 31fda1912..40fac914f 100644 --- a/.gromit/v2/events.jsonl +++ b/.gromit/v2/events.jsonl @@ -191,3 +191,46 @@ {"schema_version":1,"timestamp":"2026-03-07T16:45:12.866532-05:00","type":"stage.started","stage_name":"epilogue:default","bead_id":"gromit-zrrn7","iteration":24} {"schema_version":1,"timestamp":"2026-03-07T16:45:13.022158-05:00","type":"stage.completed","stage_name":"epilogue:default","bead_id":"gromit-zrrn7","iteration":24,"success":true,"duration":155617458} {"schema_version":1,"timestamp":"2026-03-07T16:45:13.022172-05:00","type":"bead.completed","bead_id":"gromit-zrrn7","bead_title":"Implement selective revalidation in spec loop","iteration":24,"success":true} +{"schema_version":1,"timestamp":"2026-03-10T07:32:01.610575-04:00","type":"spec.started","spec_id":"spec-level-review-and-targeted-remediation","worktree":"/Users/dabrams/gromit/.gromit/spec-worktrees/spec-level-review-and-targeted-remediation"} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.183383-04:00","type":"bead.started","bead_id":"gromit-2q0ft","bead_title":"Wire spec-level review into spec loop and run2","iteration":1} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.183396-04:00","type":"stage.started","stage_name":"gate:default","bead_id":"gromit-2q0ft","iteration":1} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.458662-04:00","type":"stage.completed","stage_name":"gate:default","bead_id":"gromit-2q0ft","iteration":1,"success":true,"duration":275263833} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.458677-04:00","type":"bead.started","bead_id":"gromit-3i6ff","bead_title":"Add --from-review flag to run2","iteration":2} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.458678-04:00","type":"stage.started","stage_name":"gate:default","bead_id":"gromit-3i6ff","iteration":2} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.607188-04:00","type":"stage.completed","stage_name":"gate:default","bead_id":"gromit-3i6ff","iteration":2,"success":true,"duration":148508708} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.607198-04:00","type":"bead.started","bead_id":"gromit-7t6ch","bead_title":"Integration test for remediation-with-findings pipeline","iteration":3} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.607199-04:00","type":"stage.started","stage_name":"gate:default","bead_id":"gromit-7t6ch","iteration":3} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.757873-04:00","type":"stage.completed","stage_name":"gate:default","bead_id":"gromit-7t6ch","iteration":3,"success":true,"duration":150673042} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.757882-04:00","type":"bead.started","bead_id":"gromit-b39ja","bead_title":"Create from-review beads on pass-with-improvements","iteration":4} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.757883-04:00","type":"stage.started","stage_name":"gate:default","bead_id":"gromit-b39ja","iteration":4} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.915529-04:00","type":"stage.completed","stage_name":"gate:default","bead_id":"gromit-b39ja","iteration":4,"success":true,"duration":157645458} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.915538-04:00","type":"bead.started","bead_id":"gromit-p24bl","bead_title":"Extend accept stage to emit structured findings","iteration":5} +{"schema_version":1,"timestamp":"2026-03-10T07:44:32.915539-04:00","type":"stage.started","stage_name":"gate:default","bead_id":"gromit-p24bl","iteration":5} +{"schema_version":1,"timestamp":"2026-03-10T07:44:33.059966-04:00","type":"stage.completed","stage_name":"gate:default","bead_id":"gromit-p24bl","iteration":5,"success":true,"duration":144425791} +{"schema_version":1,"timestamp":"2026-03-10T07:44:33.059984-04:00","type":"model.selected","bead_id":"gromit-p24bl","model":"gpt-5.1-codex-mini","provider":"openai","tier":"low","reason":"router"} +{"schema_version":1,"timestamp":"2026-03-10T07:44:33.059985-04:00","type":"stage.started","stage_name":"build:default","bead_id":"gromit-p24bl","iteration":5} +{"schema_version":1,"timestamp":"2026-03-10T07:44:33.059985-04:00","type":"build_invocation.start","bead_id":"gromit-p24bl","model":"gpt-5.1-codex-mini","provider":"openai","tier":"low","attempt":1,"max_attempts":2} +{"schema_version":1,"timestamp":"2026-03-10T07:53:52.731496-04:00","type":"build_invocation.complete","bead_id":"gromit-p24bl","model":"gpt-5.1-codex-mini","provider":"openai","success":true,"duration":559669512375,"input_tokens":5746848,"output_tokens":61559,"prompt_size":29994} +{"schema_version":1,"timestamp":"2026-03-10T07:53:52.731503-04:00","type":"stage.completed","stage_name":"build:default","bead_id":"gromit-p24bl","iteration":5,"success":true,"duration":559669512375} +{"schema_version":1,"timestamp":"2026-03-10T07:53:52.802986-04:00","type":"stage.started","stage_name":"validate:default","bead_id":"gromit-p24bl","iteration":5} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.164983-04:00","type":"stage.completed","stage_name":"validate:default","bead_id":"gromit-p24bl","iteration":5,"success":true,"duration":361988834} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.224776-04:00","type":"stage.started","stage_name":"review:default","bead_id":"gromit-p24bl","iteration":5} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.224787-04:00","type":"stage.completed","stage_name":"review:default","bead_id":"gromit-p24bl","iteration":5,"success":true,"duration":2792} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.274176-04:00","type":"stage.started","stage_name":"epilogue:default","bead_id":"gromit-p24bl","iteration":5} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.429107-04:00","type":"stage.completed","stage_name":"epilogue:default","bead_id":"gromit-p24bl","iteration":5,"success":true,"duration":154920750} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.429129-04:00","type":"bead.completed","bead_id":"gromit-p24bl","bead_title":"Extend accept stage to emit structured findings","iteration":5,"success":true,"model":"gpt-5.1-codex-mini","provider":"openai","input_tokens":5746848,"output_tokens":61559,"duration":559668525667} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.429142-04:00","type":"bead.started","bead_id":"gromit-q436q","bead_title":"Integration test for pass-with-improvements flow","iteration":6} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.429143-04:00","type":"stage.started","stage_name":"gate:default","bead_id":"gromit-q436q","iteration":6} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.577776-04:00","type":"stage.completed","stage_name":"gate:default","bead_id":"gromit-q436q","iteration":6,"success":true,"duration":148631834} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.577787-04:00","type":"bead.started","bead_id":"gromit-2q0ft","bead_title":"Wire spec-level review into spec loop and run2","iteration":7} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.577788-04:00","type":"stage.started","stage_name":"gate:default","bead_id":"gromit-2q0ft","iteration":7} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.889756-04:00","type":"stage.completed","stage_name":"gate:default","bead_id":"gromit-2q0ft","iteration":7,"success":true,"duration":311966458} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.889775-04:00","type":"model.selected","bead_id":"gromit-2q0ft","model":"gpt-5.1-codex-mini","provider":"openai","tier":"low","reason":"router"} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.88978-04:00","type":"stage.started","stage_name":"build:default","bead_id":"gromit-2q0ft","iteration":7} +{"schema_version":1,"timestamp":"2026-03-10T07:53:53.889781-04:00","type":"build_invocation.start","bead_id":"gromit-2q0ft","model":"gpt-5.1-codex-mini","provider":"openai","tier":"low","attempt":1,"max_attempts":2} +{"schema_version":1,"timestamp":"2026-03-10T07:57:07.25476-04:00","type":"build_invocation.complete","bead_id":"gromit-2q0ft","model":"gpt-5.1-codex-mini","provider":"openai","success":true,"duration":193364286333,"input_tokens":1308964,"output_tokens":19596,"prompt_size":29985} +{"schema_version":1,"timestamp":"2026-03-10T07:57:07.254768-04:00","type":"stage.completed","stage_name":"build:default","bead_id":"gromit-2q0ft","iteration":7,"success":true,"duration":193364286333} +{"schema_version":1,"timestamp":"2026-03-10T07:57:07.342396-04:00","type":"stage.started","stage_name":"validate:default","bead_id":"gromit-2q0ft","iteration":7} +{"schema_version":1,"timestamp":"2026-03-10T07:57:07.382663-04:00","type":"stage.completed","stage_name":"validate:default","bead_id":"gromit-2q0ft","iteration":7,"success":true,"duration":40260542} +{"schema_version":1,"timestamp":"2026-03-10T07:57:07.432626-04:00","type":"stage.started","stage_name":"review:default","bead_id":"gromit-2q0ft","iteration":7} +{"schema_version":1,"timestamp":"2026-03-10T07:57:07.432636-04:00","type":"stage.completed","stage_name":"review:default","bead_id":"gromit-2q0ft","iteration":7,"success":true,"duration":625} diff --git a/.gromit/v2/plan.md b/.gromit/v2/plan.md index 3cbe5d1b3..149e3daff 100644 --- a/.gromit/v2/plan.md +++ b/.gromit/v2/plan.md @@ -1 +1,336 @@ -All three exploration agents have completed. The plan is finalized at `.gromit/v2/plan.md`. \ No newline at end of file +Now I have enough to write the plan. Here it is: + +--- + +```markdown +--- +id: spec-level-review-and-targeted-remediation +source_spec: spec-level-review-and-targeted-remediation +created: 2026-03-10 +decomposed: false +--- + +# Spec-Level Review and Targeted Remediation Implementation Plan + +**Goal:** Add a holistic spec-level code review stage after the bead loop, replace plan-re-decomposition with findings-based targeted remediation, and introduce a `--from-review` flag for executing deferred review beads. + +**Architecture:** A new `internal/v2/stage/specreview/` package implements the spec-level review stage using the existing Stage interface pattern. Shared `SpecReviewFinding` types are added to `internal/v2/stage/stage.go` and flow through the spec loop into remediation decompose via a new `Findings` field on `StageRequest`. The accept stage gains structured finding output; the decompose stage gains a findings-based prompt template selected when `req.Findings` is non-empty; the spec loop adds the review call after accept and collects combined findings before delegating to the remediation runner. + +**Spec:** `.gromit/specs/spec-level-review-and-targeted-remediation.md` + +--- + +## Architecture + +**New package:** `internal/v2/stage/specreview/` — implements `stage.Stage`. Receives cumulative diff (DiffFromBase), plan text, base instructions, project context, and a review fragment (`review_spec_v2.md`). Invokes LLM with highest-tier model. Parses structured JSON output into `SpecReviewArtifacts{Verdict, Findings}`. + +**Shared finding types in `stage.go`:** `SpecReviewFinding{Severity, Category, Scope, Description, AffectedFiles}` and `SpecReviewArtifacts{Verdict, Findings}`. `StageRequest` gains `Findings []SpecReviewFinding` so remediation can pass findings to decompose without a separate channel. + +**Accept → findings:** `AcceptArtifacts` gains `Findings []SpecReviewFinding` where each unmet criterion becomes a finding with severity=critical, category=acceptance, scope=spec. + +**Decompose → findings template:** A third prompt template `findingsDecomposePromptTemplate` is selected when `req.Remediation && len(req.Findings) > 0`. Creates targeted fix beads from findings instead of from the original plan. + +**Spec loop changes:** After accept passes, run spec-level review. Gate: succeed only when accept==pass AND review.verdict==pass. On failure from either, collect all findings into `req.Findings` and call `remediationRunner.Run`. On pass-with-improvements, create from-review beads before proceeding to present. + +**Spec loop option:** `WithSpecReviewStage(stage)` added to `spec_loop.go`, wired in `run2_components.go` with highest-tier routing (tier=high / opus). + +**`--from-review` flag:** `run2.go` gains flag; when set, queries beads with label `from-review`, skips plan/decompose/accept/review, runs bead loop only. + +**Key files:** +- Create: `internal/v2/stage/specreview/specreview.go`, `specreview_test.go` +- Create: `review_spec_v2.md` +- Modify: `internal/v2/stage/stage.go` — finding types + Findings field on StageRequest +- Modify: `internal/v2/stage/accept/accept.go` — structured findings in AcceptArtifacts +- Modify: `internal/v2/stage/decompose/decompose.go` — findings-based template +- Modify: `internal/v2/loop/spec_loop.go` — review stage wiring, combined gate, findings → remediation, from-review bead creation +- Modify: `internal/v2/loop/run2_components.go` — wire specreview stage at highest tier +- Modify: `internal/v2/remediation/remediation.go` — pass findings through to decompose +- Modify: `cmd/gromit/run2.go` — `--from-review` flag + +## Test Strategy + +Unit tests for specreview stage: verdict logic (critical→fail, warning/suggestion→pass), JSON parsing, missing fields handling. Unit tests for accept findings extraction: each unmet criterion maps to a critical finding. Unit tests for findings-based decompose template selection and prompt formatting. Unit tests for from-review bead label assignment (spec-scoped vs general). Unit tests for `--from-review` flag: queries from-review label, no plan/decompose, no remediation. + +Integration test: bead loop → accept fail → review findings → targeted bead decompose (not plan re-decompose). +Integration test: pass-with-improvements path → from-review beads created, spec proceeds to present. + +Mocking strategy: use existing `llmtypes.LLMProvider` mock pattern; inject `GitDiffer` (already exists in accept stage); inject fake `TaskTracker` for bead creation assertions. + +--- + +## Implementation Tasks + +### Task 1: Shared Finding Types in stage.go + +**Files:** +- Modify: `internal/v2/stage/stage.go` +- Test: `internal/v2/stage/stage_test.go` + +**What to Do:** +Add `SpecReviewFinding` struct with fields `Severity string`, `Category string`, `Scope string` (values: "spec" | "general"), `Description string`, `AffectedFiles []string`. Add `SpecReviewArtifacts` struct with `Verdict string` (values: "pass" | "fail") and `Findings []SpecReviewFinding`. Add `Findings []SpecReviewFinding` field to `StageRequest`. Add string constants for severity, category, scope values. + +**Acceptance Criteria:** +- `SpecReviewFinding` and `SpecReviewArtifacts` are exported from `internal/v2/stage` +- `StageRequest.Findings` field exists and is a `[]SpecReviewFinding` +- Severity constants `SeverityCritical`, `SeverityWarning`, `SeveritySuggestion` are exported +- Category constants `CategoryBug`, `CategorySecurity`, `CategoryQuality`, `CategoryTestGap`, `CategoryArchitecture`, `CategoryAcceptance` are exported +- Scope constants `ScopeSpec`, `ScopeGeneral` are exported + +**Dependencies:** none + +--- + +### Task 2: review_spec_v2.md Prompt Fragment + +**Files:** +- Create: `review_spec_v2.md` (project root) + +**What to Do:** +Create the spec-level review prompt fragment. It must instruct the LLM to evaluate the cumulative diff holistically across: correctness, security (OWASP top 10), error handling, test coverage gaps, code quality, and architectural fit. Output format must be the JSON schema from the spec: `{"verdict": "pass|fail", "findings": [{"severity": "critical|warning|suggestion", "category": "bug|security|quality|test-gap|architecture", "scope": "spec|general", "description": "...", "affected_files": [...]}]}`. Include verdict logic: any critical finding forces verdict=fail. Scope rule: spec-scope for files changed by this spec, general-scope for issues in existing code not changed by this spec. + +**Acceptance Criteria:** +- File exists at project root as `review_spec_v2.md` +- Fragment describes all 6 review dimensions +- Fragment specifies the JSON output schema exactly matching the spec +- Fragment explains the scope distinction (spec vs general) +- Fragment explains the verdict rule (critical→fail) + +**Dependencies:** none + +--- + +### Task 3: Spec-Level Review Stage Core + +**Files:** +- Create: `internal/v2/stage/specreview/specreview.go` +- Create: `internal/v2/stage/specreview/specreview_test.go` + +**What to Do:** +Implement `specreview.Stage` satisfying `stage.Stage`. Constructor `New(cfg *config.Config, git GitDiffer, llm llmtypes.LLMProvider, baseInstructions, projectContext, fragment string) (*Stage, error)`. The `GitDiffer` interface needs `DiffFromBase(ctx, worktree) (string, error)` — reuse the same interface shape as accept stage. The `Run` method: (1) read plan from `.gromit/v2/plan.md`, (2) call `git.DiffFromBase` for cumulative diff, (3) build prompt from base instructions, project context, fragment, plan, and diff, (4) invoke LLM at the model in `req.Model` (caller sets highest tier), (5) parse JSON response into `SpecReviewArtifacts`, (6) apply verdict override: any critical finding forces verdict=fail, (7) return `DecisionFail` when verdict==fail, `DecisionProceed` when verdict==pass. + +Parse the LLM response with JSON extraction (use `jsonutil.ExtractJSON` as in accept stage). On parse failure, return `DecisionFail` with a synthetic critical finding describing the parse error. + +**Acceptance Criteria:** +- `specreview.Stage` implements `stage.Stage` +- `Run` returns `DecisionFail` when any finding has severity=critical +- `Run` returns `DecisionProceed` when all findings are warning/suggestion +- `Run` returns `DecisionProceed` with empty findings when no issues found (verdict=pass) +- Artifacts are `*stage.SpecReviewArtifacts` with populated Verdict and Findings +- Parse failure returns DecisionFail with a synthetic critical finding + +**Dependencies:** Task 1, Task 2 + +--- + +### Task 4: Spec-Level Review Stage Tests + +**Files:** +- Test: `internal/v2/stage/specreview/specreview_test.go` + +**What to Do:** +Write unit tests covering: (a) critical finding forces verdict=fail and DecisionFail decision, (b) only warning+suggestion findings produce verdict=pass and DecisionProceed, (c) empty findings list produces verdict=pass, (d) LLM parse failure produces DecisionFail with synthetic critical finding, (e) `SpecReviewArtifacts` findings are correctly populated from LLM JSON, (f) `Name()` returns a non-empty string. Use fake LLM provider that returns canned JSON responses. Use fake GitDiffer. Use `t.TempDir()` for worktree with a mock plan file. + +**Acceptance Criteria:** +- All tests pass with `go test ./internal/v2/stage/specreview/...` +- Tests cover all verdict logic paths +- No `os.Chdir` calls — use `t.Chdir()` if directory changes are needed +- Fake dependencies restored via `t.Cleanup` where applicable + +**Dependencies:** Task 3 + +--- + +### Task 5: Accept Stage Structured Findings Output + +**Files:** +- Modify: `internal/v2/stage/accept/accept.go` +- Test: `internal/v2/stage/accept/accept_test.go` + +**What to Do:** +Add `Findings []stage.SpecReviewFinding` to `AcceptArtifacts`. After acceptance evaluation, when criteria fail, convert each unmet criterion to a `stage.SpecReviewFinding{Severity: stage.SeverityCritical, Category: stage.CategoryAcceptance, Scope: stage.ScopeSpec, Description: }`. Populate `AffectedFiles` from the per-criterion diff mapping when available (targeted strategy already has this). Existing `GapSummary` and `Results` fields are preserved unchanged. + +**Acceptance Criteria:** +- `AcceptArtifacts.Findings` is populated for each failed criterion +- Each unmet criterion maps to exactly one finding with severity=critical, category=acceptance +- Findings scope is always "spec" for acceptance failures +- Existing `GapSummary` and `Results` behavior is unchanged +- Existing accept tests still pass + +**Dependencies:** Task 1 + +--- + +### Task 6: Findings-Based Decompose Template + +**Files:** +- Modify: `internal/v2/stage/decompose/decompose.go` +- Test: `internal/v2/stage/decompose/decompose_test.go` + +**What to Do:** +Add `findingsDecomposePromptTemplate` as a package-level var. The template takes: specID, finding list (JSON-serialized), skill instructions, spec label. Prompt preamble: "You are creating TARGETED fix beads to address specific review findings. Do NOT re-implement work that already exists." Include each finding's severity, category, description, and affected_files. Bead output format is the same JSON array as other templates. + +In `Run()`, select the findings template when `req.Remediation && len(req.Findings) > 0`. Format findings as a readable list (one finding per line with severity/category/description). When findings are present, skip reading the plan file (findings are self-contained context for targeted fixes). + +**Acceptance Criteria:** +- Findings template is selected when `req.Remediation && len(req.Findings) > 0` +- When findings template is used, plan file is not required (no error if absent) +- Existing `req.Remediation && gapAnalysis != ""` path is unchanged (gap analysis still works when findings are empty) +- New unit test verifies findings template selection with non-empty findings + +**Dependencies:** Task 1 + +--- + +### Task 7: Remediation Runner Passes Findings to Decompose + +**Files:** +- Modify: `internal/v2/remediation/remediation.go` +- Test: `internal/v2/remediation/remediation_test.go` + +**What to Do:** +In `executeRemediation`, change the signature to accept `findings []stage.SpecReviewFinding` alongside the existing `gapAnalysis string`. Before calling `r.decompose(ctx, req)`, set `req.Findings = findings`. This wires the findings from accept+review into the decompose stage so the findings-based template is activated. + +Update the call site in `Run()` — when `res.Decision == stage.DecisionFail`, extract findings from `AcceptArtifacts.Findings` (add helper `extractFindings(res *stage.Result) []stage.SpecReviewFinding`) and pass them to `executeRemediation`. + +Keep the `gapAnalysis` path as fallback: when `len(findings) == 0 && gapAnalysis != ""`, continue using gap-analysis-based remediation. + +**Acceptance Criteria:** +- When `AcceptArtifacts.Findings` is non-empty, `req.Findings` is set before calling decompose +- When findings are empty, existing gap-analysis path is used unchanged +- Existing remediation tests pass +- New unit test verifies findings are propagated to the decompose request + +**Dependencies:** Task 1, Task 5, Task 6 + +--- + +### Task 8: Spec Loop — Wire Spec-Level Review and Combined Gate + +**Files:** +- Modify: `internal/v2/loop/spec_loop.go` + +**What to Do:** +Add `specReviewStage stage.Stage` field to `SpecLoop`. Add `WithSpecReviewStage(s stage.Stage) SpecLoopOption`. Add the `StageSequence` entry "specreview" after "accept". + +In `Run()`, after `s.ensureAcceptance(...)` succeeds, call spec-level review: +```go +s.recordStage("specreview") +reviewRes, err := s.runSpecReview(ctx, &req, specID) +if err != nil { + handleFailureCleaned = true + return s.handleFailure(ctx, specID, baseSummary, err) +} +``` + +Add `runSpecReview` helper that: +1. If `s.specReviewStage == nil`, return nil (skip — optional stage) +2. Apply routing with phase "specreview" +3. Call `s.specReviewStage.Run(ctx, &req)` +4. If decision == DecisionFail: collect findings from artifacts, combine with any accept findings already in `req.Findings`, set `req.Findings` on the request, call `s.remediationRunner.Run(ctx, specID, req.Worktree, reviewRes)` +5. If decision == DecisionProceed with non-empty findings: call `s.createFromReviewBeads(ctx, specID, reviewArtifacts.Findings)` + +Add `createFromReviewBeads` helper: iterates findings, creates a bead per finding via `s.adapters.TaskTracker.CreateBead`. Spec-scoped findings (scope=="spec") get label `from-review spec:`; general findings get label `from-review`. Priority = P1 for warnings, P2 for suggestions. Skip critical findings (they should have triggered fail and been remediated). + +**Acceptance Criteria:** +- Spec-level review runs after accept passes +- If review returns DecisionFail, remediation runner is called with findings in req.Findings +- If review returns DecisionProceed with findings, from-review beads are created with correct labels +- If review returns DecisionProceed with no findings, spec proceeds unchanged +- If specReviewStage is nil (not configured), spec loop proceeds without error +- Spec-scoped findings get label `from-review spec:`, general get `from-review` + +**Dependencies:** Task 1, Task 3, Task 7 + +--- + +### Task 9: Spec Loop Tests for Review Integration + +**Files:** +- Test: `internal/v2/loop/spec_loop_test.go` + +**What to Do:** +Add unit tests for the spec-level review integration: +- (a) When specReviewStage returns DecisionFail, `remediationRunner.Run` is called +- (b) When specReviewStage returns DecisionProceed with spec-scoped findings, beads are created with `from-review spec:` label +- (c) When specReviewStage returns DecisionProceed with general findings, beads are created with `from-review` label (no spec prefix) +- (d) When specReviewStage is nil, spec loop completes without error +- (e) When specReviewStage returns DecisionProceed with no findings, no beads are created + +Use the existing fake stage pattern in the test file (check for `fakeStage` or similar helpers). Use fake `TaskTracker` that records created beads. + +**Acceptance Criteria:** +- All 5 test cases pass +- Tests use `t.Chdir()` not `os.Chdir()` +- Fake dependency overrides restored via `t.Cleanup` + +**Dependencies:** Task 8 + +--- + +### Task 10: Run2 Components — Wire Spec-Level Review at Highest Tier + +**Files:** +- Modify: `internal/v2/loop/run2_components.go` + +**What to Do:** +Load the review spec fragment: `specReviewFragment, err := loadFragment(cfg.ProjectRoot, "review_spec_v2.md")`. Create the specreview stage: `specReviewStage, err := specreviewstage.New(cfg, adapters.Git, adapters.LLM, baseInstructions, projectContext, specReviewFragment)`. Add to `Run2LoopComponents` struct: `SpecReviewStage stage.Stage`. Wire it into the spec loop via `loop.WithSpecReviewStage(specReviewStage)`. + +Routing for specreview: it must always use the highest configured tier. Apply routing with phase "specreview" — the `phaseModels` map should map "specreview" to "high" tier. Since the spec mandates highest tier always, add a constant or document in `run2_components.go` that specreview is hardcoded to tier "high". In `applyRouting` in `spec_loop.go`, use `routing.TierHigh` as the default for phase "specreview" instead of `routing.TierMedium`. + +Add import: `specreviewstage "github.com/danabrams/gromit/internal/v2/stage/specreview"`. + +**Acceptance Criteria:** +- `NewRun2LoopComponents` creates a specreview stage and wires it to the spec loop +- `SpecReviewStage` field is populated in the returned `Run2LoopComponents` +- The specreview phase routes to "high" tier when router is configured +- Build compiles cleanly: `go build ./...` + +**Dependencies:** Task 3, Task 8 + +--- + +### Task 11: `--from-review` Flag in run2.go + +**Files:** +- Modify: `cmd/gromit/run2.go` +- Test: `cmd/gromit/run2_test.go` (or nearest test file) + +**What to Do:** +Add flag in `init()`: `run2Cmd.Flags().Bool("from-review", false, "Run only beads with the from-review label")`. Add optional scoping: `run2Cmd.Flags().String("spec", "", "Scope from-review run to a specific spec")`. + +In `run2()`, check the flag: if `--from-review` is set, call `runFromReview(ctx, cfg, adapters, ...)` instead of the normal spec loop path. + +`runFromReview` function: (1) build label query: `labels := []string{"from-review"}`; if `--spec ` provided, also add `fmt.Sprintf("spec:%s", specID)` to labels; (2) query beads via TaskTracker; (3) if no beads found, print "no from-review beads found" and return nil; (4) build a `BeadLoop` (reuse `Run2LoopComponents`) and call `beadLoop.Run(ctx, beads, stopCh)`; (5) no plan, no decompose, no accept, no specreview, no remediation cycle. + +Note: `--from-review` is incompatible with providing a spec-file positional arg. When `--from-review` is set, the `Args` validator should accept 0 positional args. + +**Acceptance Criteria:** +- `gromit run2 --from-review` queries beads with label `from-review` and runs them +- `gromit run2 --from-review --spec myspec` additionally filters by `spec:myspec` label +- `--from-review` run does not execute plan, decompose, accept, or specreview stages +- When no from-review beads exist, command exits 0 with a message +- Build compiles cleanly + +**Dependencies:** Task 8, Task 10 + +--- + +### Task 12: Integration Test — Post-Bead-Loop Pipeline + +**Files:** +- Create or modify: `internal/v2/loop/spec_loop_integration_test.go` (or nearest integration test file) + +**What to Do:** +Write an integration test that exercises the full post-bead-loop path: bead loop completes → accept runs and passes → spec-level review runs and returns critical finding → remediation is triggered with findings → decompose creates targeted beads (not plan beads). Use a fake accept stage that always passes (returns DecisionProceed), a fake specreview stage that returns DecisionFail with one critical finding, a fake remediation runner that records whether it was called and what findings it received, and a fake TaskTracker. + +Assert: remediation runner was called; the request passed to it had `Findings` with the critical finding from specreview. + +Also write a pass-with-improvements integration test: specreview returns DecisionProceed with one spec-scoped warning finding → assert that TaskTracker.CreateBead was called with label `from-review spec:` and the spec proceeds to present. + +**Acceptance Criteria:** +- Findings-based remediation path is exercised end-to-end in the test +- Pass-with-improvements path creates from-review beads with correct labels +- All existing spec loop tests still pass + +**Dependencies:** Task 8, Task 9 +``` \ No newline at end of file diff --git a/docs/plans/2026-03-10-spec-level-review-and-targeted-remediation.md b/docs/plans/2026-03-10-spec-level-review-and-targeted-remediation.md new file mode 100644 index 000000000..c8a60ceaa --- /dev/null +++ b/docs/plans/2026-03-10-spec-level-review-and-targeted-remediation.md @@ -0,0 +1,1291 @@ +--- +id: spec-level-review-and-targeted-remediation +source_spec: spec-level-review-and-targeted-remediation +created: 2026-03-10 +decomposed: false +--- + +# Spec-Level Review and Targeted Remediation Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Add a spec-level code review stage that evaluates the cumulative diff after all beads complete, and route its structured findings (combined with accept failures) into targeted remediation decomposition instead of re-decomposing the whole plan. + +**Architecture:** Introduce `internal/v2/stage/specreview/` as a new Stage that runs after accept, produces structured `ReviewFinding` values, and combines with accept's unmet-criteria findings to drive a new findings-based decompose template. The `remediationRunner` interface gains a `Remediate` method that takes findings instead of gap analysis text. SpecLoop's `ensureAcceptance` expands to run specreview, collect combined findings, and call `Remediate`. A `--from-review` flag on `run2` runs open `from-review` beads directly through the bead loop. + +**Tech Stack:** Go 1.24+, existing `internal/v2/stage`, `internal/v2/llmtypes`, `internal/v2/routing`, `internal/v2/trackertypes`, cobra CLI flags, JSON output parsing via `internal/jsonutil`. + +--- + +## Architecture + +### Shared finding type +`ReviewFinding` lives in a new `internal/v2/stage/findings.go` file so every package (`accept`, `specreview`, `decompose`, `remediation`, `loop`) can import it without circular deps. `StageRequest` gains two new fields: `FindingsDecompose bool` and `Findings []ReviewFinding`. + +### Accept stage +`AcceptArtifacts.Findings []ReviewFinding` is populated for each failed criterion with `severity: critical`, `category: acceptance`, `scope: spec`. + +### Specreview stage +New package `internal/v2/stage/specreview/`. Reads `DiffFromBase` and the plan file from the worktree; invokes the highest-tier LLM with the `review_spec_v2.md` fragment prompt; parses structured JSON; derives verdict from findings. Creates `from-review` beads in TaskTracker for pass-with-improvements paths. + +### Decompose stage +New `findingsDecomposePromptTemplate` selected when `req.FindingsDecompose && len(req.Findings) > 0`. Each finding becomes one or more targeted beads. + +### Remediation runner +New `Remediate(ctx, specID, worktree, findings []stage.ReviewFinding) error` method replaces the gap-analysis path. Sets `req.FindingsDecompose = true`, `req.Findings = findings`, then decomposes and runs the bead loop once. Generation cap still applies. + +### Spec loop +`ensureAcceptance` renamed `ensureAcceptanceAndReview`. Runs accept, then specreview. If both pass, return. Otherwise collect combined findings (accept.Findings + specreview.Findings) and call `remediationRunner.Remediate`. The `remediationRunner` interface changes to expose `Remediate`. + +### run2 --from-review +New flag skips spec resolution, plan, decompose, accept, and review. Queries open beads with label `from-review` (scoped to `spec:` when `--spec` is provided). Passes beads directly to the bead loop. + +## Test Strategy + +Unit tests per package: specreview (verdict logic, JSON parsing, bead creation), decompose (findings template selection), remediation (Remediate method), accept (findings field populated), spec loop (specreview runs, combined findings, Remediate called). Integration test for the full post-bead-loop pipeline and pass-with-improvements bead creation. All new packages follow the existing pattern: `var _ stagepkg.Stage = (*Stage)(nil)` compile-time check. + +## Implementation Tasks + +--- + +### Task 1: ReviewFinding type and Request fields + +**Files:** +- Create: `internal/v2/stage/findings.go` +- Modify: `internal/v2/stage/stage.go` +- Create: `internal/v2/stage/findings_test.go` + +**What to Do:** + +Create `internal/v2/stage/findings.go`: + +```go +package stage + +// ReviewFinding represents a single observation from accept or spec-level review. +type ReviewFinding struct { + Severity string // "critical" | "warning" | "suggestion" + Category string // "bug" | "security" | "quality" | "test-gap" | "architecture" | "acceptance" + Scope string // "spec" | "general" + Description string + AffectedFiles []string +} + +// SpecReviewArtifacts captures the output of the spec-level review stage. +type SpecReviewArtifacts struct { + Verdict string // "pass" | "fail" + Findings []ReviewFinding +} +``` + +Add two fields to `StageRequest` in `internal/v2/stage/stage.go` (after the existing `GapAnalysis` field): + +```go + FindingsDecompose bool + Findings []ReviewFinding +``` + +**Step 1: Write the failing test** + +In `internal/v2/stage/findings_test.go`: + +```go +package stage_test + +import ( + "testing" + stagepkg "github.com/danabrams/gromit/internal/v2/stage" +) + +func TestReviewFinding_Fields(t *testing.T) { + f := stagepkg.ReviewFinding{ + Severity: "critical", + Category: "acceptance", + Scope: "spec", + Description: "criterion not met", + AffectedFiles: []string{"foo.go"}, + } + if f.Severity != "critical" { + t.Errorf("expected critical, got %s", f.Severity) + } + if len(f.AffectedFiles) != 1 { + t.Errorf("expected 1 file, got %d", len(f.AffectedFiles)) + } +} + +func TestSpecReviewArtifacts_Fields(t *testing.T) { + a := stagepkg.SpecReviewArtifacts{ + Verdict: "fail", + Findings: []stagepkg.ReviewFinding{{Severity: "critical", Category: "bug", Scope: "spec"}}, + } + if a.Verdict != "fail" { + t.Errorf("expected fail, got %s", a.Verdict) + } +} + +func TestStageRequest_FindingsFields(t *testing.T) { + req := stagepkg.StageRequest{ + FindingsDecompose: true, + Findings: []stagepkg.ReviewFinding{ + {Severity: "warning", Category: "quality", Scope: "general"}, + }, + } + if !req.FindingsDecompose { + t.Error("expected FindingsDecompose true") + } + if len(req.Findings) != 1 { + t.Errorf("expected 1 finding, got %d", len(req.Findings)) + } +} +``` + +**Step 2: Run test to verify it fails** + +```bash +cd internal/v2/stage && go test ./... -run TestReviewFinding -v +``` +Expected: FAIL — `ReviewFinding undefined` + +**Step 3: Implement** + +Create `internal/v2/stage/findings.go` with the types above. Add `FindingsDecompose bool` and `Findings []ReviewFinding` to `StageRequest` in `stage.go`. + +**Step 4: Run test to verify it passes** + +```bash +cd internal/v2/stage && go test ./... -v +``` +Expected: PASS + +**Step 5: Commit** + +```bash +git add internal/v2/stage/findings.go internal/v2/stage/stage.go internal/v2/stage/findings_test.go +git commit -m "red/green: ReviewFinding type + StageRequest fields for findings-based decompose" +``` + +**Acceptance Criteria:** +- `ReviewFinding` struct exists in `internal/v2/stage` with Severity, Category, Scope, Description, AffectedFiles +- `SpecReviewArtifacts` exists with Verdict and Findings +- `StageRequest` has `FindingsDecompose bool` and `Findings []ReviewFinding` + +--- + +### Task 2: Accept stage structured findings output + +**Files:** +- Modify: `internal/v2/stage/accept/accept.go` +- Modify: `internal/v2/stage/accept/accept_test.go` (or create if tests live elsewhere) + +**What to Do:** + +Add `Findings []stage.ReviewFinding` to `AcceptArtifacts`. When criteria fail, populate a `ReviewFinding` per unmet criterion with `Severity: "critical"`, `Category: "acceptance"`, `Scope: "spec"`. + +In `accept.go`, update `AcceptArtifacts`: + +```go +import stagepkg "github.com/danabrams/gromit/internal/v2/stage" + +type AcceptArtifacts struct { + Results []presentation.AcceptanceResult + GapSummary string + Findings []stagepkg.ReviewFinding +} +``` + +In each evaluation path that builds failures (batch, targeted, per-criterion), convert failures to findings. Add a helper: + +```go +func criterionToFinding(criterionText, summary string) stagepkg.ReviewFinding { + return stagepkg.ReviewFinding{ + Severity: "critical", + Category: "acceptance", + Scope: "spec", + Description: fmt.Sprintf("%s — %s", criterionText, summary), + } +} +``` + +Call `criterionToFinding` for every failed criterion and append to `artifacts.Findings`. + +**Step 1: Write the failing test** + +In `accept_test.go`, add: + +```go +func TestAcceptStage_FailedCriteriaPopulateFindings(t *testing.T) { + // Use an LLM provider that returns {"pass": false, "summary": "not done"} + // and a spec with one criterion. + // Verify AcceptArtifacts.Findings has one entry with severity=critical, category=acceptance. + artifacts := runAcceptWithMockFailure(t) + if len(artifacts.Findings) != 1 { + t.Fatalf("expected 1 finding, got %d", len(artifacts.Findings)) + } + f := artifacts.Findings[0] + if f.Severity != "critical" { + t.Errorf("expected critical severity, got %s", f.Severity) + } + if f.Category != "acceptance" { + t.Errorf("expected acceptance category, got %s", f.Category) + } + if f.Scope != "spec" { + t.Errorf("expected spec scope, got %s", f.Scope) + } +} +``` + +The helper `runAcceptWithMockFailure` invokes the stage with a fake LLM that returns `{"pass": false, "summary": "not done"}` against a spec file with one criterion. + +**Step 2: Run test to verify it fails** + +```bash +cd internal/v2/stage/accept && go test ./... -run TestAcceptStage_FailedCriteriaPopulateFindings -v +``` +Expected: FAIL — `Findings` field not yet defined + +**Step 3: Implement** + +Add `Findings []stagepkg.ReviewFinding` to `AcceptArtifacts`. Add `criterionToFinding` helper. In `buildBatchResult`, `runPerCriterionEvaluation`, and `runTargetedEvaluation`, append a finding for each failure. In `allCriteriaFailed`, populate findings for every criterion. + +**Step 4: Run tests** + +```bash +cd internal/v2/stage/accept && go test ./... -v +``` +Expected: all PASS + +**Step 5: Commit** + +```bash +git add internal/v2/stage/accept/accept.go internal/v2/stage/accept/accept_test.go +git commit -m "green: AcceptArtifacts.Findings populated for failed acceptance criteria" +``` + +**Acceptance Criteria:** +- `AcceptArtifacts.Findings []stage.ReviewFinding` field exists +- Each failed criterion produces a finding with `severity: critical`, `category: acceptance`, `scope: spec` +- Passing criteria produce no findings + +--- + +### Task 3: Findings-based decompose template + +**Files:** +- Modify: `internal/v2/stage/decompose/decompose.go` +- Modify: `internal/v2/stage/decompose/decompose_test.go` + +**What to Do:** + +Add a new `findingsDecomposePromptTemplate` constant. In `Run()`, add a new branch before the existing `req.Remediation` check: + +```go +if req.FindingsDecompose && len(req.Findings) > 0 { + promptText = buildFindingsDecomposePrompt(specID, string(planBody), req.Findings) +} else if req.Remediation && gapAnalysis != "" { + promptText = fmt.Sprintf(remediationDecomposePromptTemplate, ...) +} else { + promptText = fmt.Sprintf(s.promptTemplate, ...) +} +``` + +Add the template and builder: + +```go +var findingsDecomposePromptTemplate = `# Targeted Fix Decompose: %s + +You are creating TARGETED beads to address specific review findings. Do NOT re-implement work that has already been completed. + +## Full Plan (for architectural context only) + +%s + +## Findings Requiring Fix Beads + +%s + +## Skill Instructions + +%s + +## Rules + +- Create one or more beads per finding. +- Beads must address the specific finding; do not duplicate existing work. +- acceptance_criteria: each criterion MUST describe an observable behavior, NOT a file path or function name. +- depends_on_index: chain beads that depend on each other. + +## Output + +Output ONLY a JSON array of bead definitions. No markdown, no explanations. +Each bead must include: title, description, priority, acceptance_criteria, expected_outputs, covers_tasks, depends_on_index. + +The spec label will be added automatically: spec:%s +` + +func buildFindingsDecomposePrompt(specID, planBody string, findings []stagepkg.ReviewFinding) string { + var sb strings.Builder + for i, f := range findings { + fmt.Fprintf(&sb, "%d. [%s/%s] %s", i+1, f.Severity, f.Category, f.Description) + if len(f.AffectedFiles) > 0 { + fmt.Fprintf(&sb, " (files: %s)", strings.Join(f.AffectedFiles, ", ")) + } + sb.WriteByte('\n') + } + return fmt.Sprintf(findingsDecomposePromptTemplate, specID, planBody, sb.String(), skills.DecomposeSkill, specID) +} +``` + +**Step 1: Write the failing test** + +In `decompose_test.go`, add: + +```go +func TestDecompose_FindingsDecomposeTemplateSelected(t *testing.T) { + // Arrange: mock LLM that captures prompt text; tracker that records created beads + capturedPrompt := "" + mockLLM := &mockProvider{ + invokeFn: func(ctx context.Context, req llmtypes.LLMInvokeRequest) (*llmtypes.LLMInvokeResponse, error) { + capturedPrompt = req.Prompt + return &llmtypes.LLMInvokeResponse{Success: true, Output: `[{"title":"Fix bug","description":"fix it","priority":"P1","acceptance_criteria":["behavior works"],"expected_outputs":["fixed behavior"],"covers_tasks":[1],"depends_on_index":[]}]`}, nil + }, + } + // ... set up stage, write plan.md to temp dir ... + req := &stagepkg.StageRequest{ + Bead: stagepkg.BeadInfo{ID: "my-spec"}, + Worktree: tmpDir, + Config: cfg, + FindingsDecompose: true, + Findings: []stagepkg.ReviewFinding{ + {Severity: "critical", Category: "bug", Scope: "spec", Description: "nil dereference in handler"}, + }, + } + _, err := stage.Run(ctx, req) + if err != nil { t.Fatal(err) } + if !strings.Contains(capturedPrompt, "Targeted Fix Decompose") { + t.Errorf("expected findings template, got: %s", capturedPrompt[:200]) + } + if !strings.Contains(capturedPrompt, "nil dereference") { + t.Errorf("expected finding description in prompt") + } +} +``` + +**Step 2: Run test to verify it fails** + +```bash +cd internal/v2/stage/decompose && go test ./... -run TestDecompose_FindingsDecomposeTemplateSelected -v +``` +Expected: FAIL + +**Step 3: Implement** + +Add `findingsDecomposePromptTemplate`, `buildFindingsDecomposePrompt`, and the new branch in `Run()`. + +**Step 4: Run tests** + +```bash +cd internal/v2/stage/decompose && go test ./... -v +``` +Expected: PASS + +**Step 5: Commit** + +```bash +git add internal/v2/stage/decompose/decompose.go internal/v2/stage/decompose/decompose_test.go +git commit -m "green: findings-based decompose template for targeted remediation" +``` + +**Acceptance Criteria:** +- When `req.FindingsDecompose == true && len(req.Findings) > 0`, the findings template is used +- Each finding's description appears in the prompt +- The existing remediation and default templates still work when their conditions are met + +--- + +### Task 4: Remediation runner Remediate method + +**Files:** +- Modify: `internal/v2/remediation/remediation.go` +- Modify: `internal/v2/remediation/remediation_test.go` + +**What to Do:** + +Add a `Remediate(ctx context.Context, specID, worktree string, findings []stage.ReviewFinding) error` method to `RemediationRunner`. This replaces the role of `executeRemediation` for the spec-loop-driven path. + +```go +// Remediate runs one targeted remediation cycle for the provided findings. +// It sets req.FindingsDecompose and req.Findings, decomposes targeted beads, +// runs the bead loop, and increments the generation counter. +// Returns an error if the generation cap is reached. +func (r *RemediationRunner) Remediate(ctx context.Context, specID, worktree string, findings []stage.ReviewFinding) error { + if specID == "" { + return ErrSpecIDRequired + } + if !r.canRemediate() { + return r.handleGenerationCap(ctx, specID) + } + + req := &stage.Request{ + Bead: stage.BeadInfo{ID: specID}, + Worktree: worktree, + Remediation: true, + FindingsDecompose: true, + Findings: findings, + } + + // Persist a record of this remediation generation. + if worktree != "" { + var sb strings.Builder + for i, f := range findings { + fmt.Fprintf(&sb, "%d. [%s/%s] %s\n", i+1, f.Severity, f.Category, f.Description) + } + planPath := r.remediationPlanPath(worktree) + if err := os.MkdirAll(filepath.Dir(planPath), 0o755); err != nil { + return fmt.Errorf("create remediation plan dir: %w", err) + } + if err := os.WriteFile(planPath, []byte(sb.String()), 0o644); err != nil { + return fmt.Errorf("persist remediation findings: %w", err) + } + } + + beads, err := r.decompose(ctx, req) + if err != nil { + return err + } + + if r.cfg.BeadRunner == nil { + return ErrBeadRunnerRequired + } + if err := r.cfg.BeadRunner.Run(ctx, beads); err != nil { + return err + } + + r.generationCount++ + return nil +} +``` + +**Step 1: Write the failing test** + +```go +func TestRemediationRunner_Remediate_CallsDecomposeWithFindings(t *testing.T) { + var capturedReq *stage.Request + mockDecompose := &mockStage{ + runFn: func(ctx context.Context, req *stage.Request) (*stage.Result, error) { + capturedReq = req + return &stage.Result{ + Decision: stage.DecisionProceed, + Artifacts: &stage.DecomposeArtifacts{Beads: []*bead.Bead{{ID: "b1"}}}, + }, nil + }, + } + mockBeadRunner := &mockBeadRunner{} + runner := NewRemediationRunner(RemediationRunnerConfig{ + AcceptStage: &mockStage{}, + DecomposeStage: mockDecompose, + BeadRunner: mockBeadRunner, + GenerationCap: 3, + }) + + findings := []stage.ReviewFinding{ + {Severity: "critical", Category: "bug", Scope: "spec", Description: "nil pointer"}, + } + err := runner.Remediate(context.Background(), "my-spec", t.TempDir(), findings) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if capturedReq == nil { + t.Fatal("decompose not called") + } + if !capturedReq.FindingsDecompose { + t.Error("expected FindingsDecompose=true") + } + if len(capturedReq.Findings) != 1 { + t.Errorf("expected 1 finding, got %d", len(capturedReq.Findings)) + } + if !mockBeadRunner.ranBeads { + t.Error("bead runner not called") + } +} + +func TestRemediationRunner_Remediate_RespectsGenerationCap(t *testing.T) { + runner := NewRemediationRunner(RemediationRunnerConfig{ + AcceptStage: &mockStage{}, + DecomposeStage: &mockStage{}, + BeadRunner: &mockBeadRunner{}, + GenerationCap: 0, // cap at 0 means no remediation allowed + }) + err := runner.Remediate(context.Background(), "my-spec", t.TempDir(), nil) + if err == nil { + t.Error("expected error when generation cap reached") + } +} +``` + +**Step 2: Run test to verify it fails** + +```bash +cd internal/v2/remediation && go test ./... -run TestRemediationRunner_Remediate -v +``` +Expected: FAIL — `Remediate` method not defined + +**Step 3: Implement** + +Add `Remediate` method to `remediation.go`. + +**Step 4: Run tests** + +```bash +cd internal/v2/remediation && go test ./... -v +``` +Expected: PASS + +**Step 5: Commit** + +```bash +git add internal/v2/remediation/remediation.go internal/v2/remediation/remediation_test.go +git commit -m "green: RemediationRunner.Remediate takes findings not gap analysis" +``` + +**Acceptance Criteria:** +- `RemediationRunner.Remediate(ctx, specID, worktree, findings) error` exists +- Sets `req.FindingsDecompose = true` and `req.Findings = findings` before calling decompose +- Respects generation cap (returns error when cap reached) +- Persists a findings record to `.gromit/v2/remediation-N.md` + +--- + +### Task 5: Spec-level review stage + +**Files:** +- Create: `internal/v2/stage/specreview/specreview.go` +- Create: `internal/v2/stage/specreview/specreview_test.go` + +**What to Do:** + +Create the specreview stage. It: +1. Reads `DiffFromBase` from the worktree git adapter +2. Reads `plan.md` from `/.gromit/v2/plan.md` +3. Assembles prompt from base + project + fragment + instance (plan + diff) +4. Invokes the LLM (highest tier — uses `req.Provider` / `req.Model` as set by caller) +5. Parses JSON response into `SpecReviewArtifacts` +6. Derives verdict: any `critical` finding → "fail", else "pass" +7. For pass-with-improvements: creates `from-review` beads via TaskTracker (spec-scoped or general per `Scope`) + +Key structs: + +```go +package specreview + +import ( + stagepkg "github.com/danabrams/gromit/internal/v2/stage" + "github.com/danabrams/gromit/internal/v2/llmtypes" + "github.com/danabrams/gromit/internal/v2/trackertypes" + "github.com/danabrams/gromit/internal/config" + // ... +) + +// GitDiffer provides the diff capability. +type GitDiffer interface { + DiffFromBase(ctx context.Context, worktree string) (string, error) +} + +// Stage performs spec-level holistic review after all beads complete. +type Stage struct { + name string + cfg *config.Config + git GitDiffer + llm llmtypes.LLMProvider + tracker trackertypes.TaskTracker + base string + project string + fragment string +} + +var _ stagepkg.Stage = (*Stage)(nil) +``` + +JSON response from LLM: + +```go +type reviewResponse struct { + Verdict string `json:"verdict"` // "pass" | "fail" + Findings []struct { + Severity string `json:"severity"` + Category string `json:"category"` + Scope string `json:"scope"` + Description string `json:"description"` + AffectedFiles []string `json:"affected_files"` + } `json:"findings"` +} +``` + +Verdict derivation: + +```go +func deriveVerdict(findings []stagepkg.ReviewFinding) string { + for _, f := range findings { + if f.Severity == "critical" { + return "fail" + } + } + return "pass" +} +``` + +Pass-with-improvements bead creation (called when verdict is "pass" but findings exist): + +```go +func (s *Stage) createFromReviewBeads(ctx context.Context, specID string, findings []stagepkg.ReviewFinding) error { + for _, f := range findings { + if f.Severity == "critical" { + continue // critical findings go to remediation, not from-review + } + labels := []string{"from-review"} + if f.Scope == "spec" { + labels = append(labels, fmt.Sprintf("spec:%s", specID)) + } + _, err := s.tracker.CreateBead(ctx, trackertypes.TaskTrackerCreateBeadRequest{ + Title: fmt.Sprintf("[%s] %s", f.Category, f.Description[:min(50, len(f.Description))]), + Description: f.Description, + Priority: 2, // P2 for review improvements + Labels: labels, + }) + if err != nil { + return fmt.Errorf("create from-review bead: %w", err) + } + } + return nil +} +``` + +**Step 1: Write the failing tests** + +In `specreview_test.go`: + +```go +func TestSpecReview_CriticalFindingForcesFailVerdict(t *testing.T) { + // LLM returns JSON with a critical finding + // Expect Result.Decision == DecisionFail + // Expect SpecReviewArtifacts.Verdict == "fail" +} + +func TestSpecReview_OnlyWarningsForcesPassVerdict(t *testing.T) { + // LLM returns JSON with only warning findings + // Expect Result.Decision == DecisionProceed + // Expect SpecReviewArtifacts.Verdict == "pass" + // Expect from-review beads created in tracker +} + +func TestSpecReview_PassWithNoFindings(t *testing.T) { + // LLM returns {"verdict": "pass", "findings": []} + // Expect DecisionProceed, no beads created +} + +func TestSpecReview_ParsesStructuredOutput(t *testing.T) { + // Verifies JSON parsing: severity, category, scope, description, affected_files +} +``` + +**Step 2: Run test to verify it fails** + +```bash +cd internal/v2/stage/specreview && go test ./... -v +``` +Expected: FAIL — package does not exist yet + +**Step 3: Implement** + +Create `specreview.go` with `Stage`, `New`, `Name`, `Run`, `deriveVerdict`, `createFromReviewBeads`. + +**Step 4: Run tests** + +```bash +cd internal/v2/stage/specreview && go test ./... -v +``` +Expected: PASS + +**Step 5: Compile check the full module** + +```bash +go build ./... +``` +Expected: no compile errors + +**Step 6: Commit** + +```bash +git add internal/v2/stage/specreview/ +git commit -m "green: spec-level review stage with structured findings and from-review bead creation" +``` + +**Acceptance Criteria:** +- Stage implements `stagepkg.Stage` (compile-time check `var _ stagepkg.Stage = (*Stage)(nil)`) +- Any critical finding produces `DecisionFail` and `SpecReviewArtifacts.Verdict == "fail"` +- Only warning/suggestion findings produce `DecisionProceed` and `Verdict == "pass"` +- For pass-with-improvements: spec-scoped findings create beads with labels `["from-review", "spec:"]`; general findings create beads with `["from-review"]` +- Critical findings do NOT produce from-review beads (they go to remediation) + +--- + +### Task 6: review_spec_v2.md prompt fragment + +**Files:** +- Create: `review_spec_v2.md` (project root) + +**What to Do:** + +Create the spec-level review prompt fragment at the project root. This file is loaded by `run2_components.go` (in Task 8) via `loadFragment`. It instructs the LLM to review the cumulative diff holistically. + +```markdown +# Spec-Level Review Instructions + +You are performing a holistic review of all code changes introduced by this spec. The cumulative diff and the implementation plan are provided in the instance context above. + +This is distinct from the per-bead review that runs during implementation. Your role is to evaluate the complete output as a whole. + +## Review Dimensions + +### 1. Correctness +- Does the implementation satisfy the spec's intent beyond just passing tests? +- Are there logic errors, off-by-one errors, or incorrect assumptions? +- Are error conditions properly handled on all return paths? + +### 2. Security (OWASP Top 10) +- SQL injection, command injection, XSS risks? +- Authentication/authorization bypass? +- Secrets logged or exposed? +- Insecure deserialization, path traversal, SSRF? + +### 3. Error Handling +- Are errors wrapped with context (fmt.Errorf("...: %w", err))? +- Are nil returns guarded before dereferencing? +- Do error paths clean up resources they acquired? + +### 4. Test Coverage Gaps +- Are critical paths untested? +- Are edge cases (empty input, nil, zero values, max values) covered? +- Do tests assert behavior or just absence of panics? + +### 5. Code Quality +- Dead code, unused variables, or imports? +- Overly complex logic that should be simplified? +- Missing or misleading comments on non-obvious logic? + +### 6. Architectural Fit +- Does the new code follow existing patterns in the project? +- Are abstractions introduced only when they provide clear value? +- Are there layering violations (e.g., infrastructure leaking into domain logic)? + +## Severity Classification + +- **critical**: Bug, security vulnerability, or logic error that will cause incorrect behavior. +- **warning**: Code quality issue, test gap, or architectural concern worth fixing soon. +- **suggestion**: Minor improvement; optional. + +## Scope Classification + +- **spec**: The finding is in code introduced or modified by this spec. +- **general**: The finding is in pre-existing code not changed by this spec. + +## Output Format + +Output ONLY a JSON object: +```json +{ + "verdict": "pass", + "findings": [ + { + "severity": "critical", + "category": "bug", + "scope": "spec", + "description": "what is wrong and why", + "affected_files": ["path/to/file.go"] + } + ] +} +``` + +Verdict rules: +- "fail": any finding with severity "critical" +- "pass": no critical findings (may have warnings or suggestions) + +Do NOT output markdown, commentary, or anything other than the JSON object. +``` + +**Step 1: Create the file** + +Create `review_spec_v2.md` at project root with the content above. + +**Step 2: Verify it loads** + +```bash +# From project root, verify the file exists and is non-empty +cat review_spec_v2.md | head -5 +``` + +**Step 3: Commit** + +```bash +git add review_spec_v2.md +git commit -m "feat: review_spec_v2.md prompt fragment for spec-level holistic review" +``` + +**Acceptance Criteria:** +- File exists at project root +- Contains JSON output format instructions with `verdict` + `findings` fields +- Severity/scope classification instructions are present + +--- + +### Task 7: Spec loop orchestration + +**Files:** +- Modify: `internal/v2/loop/spec_loop.go` +- Modify: `internal/v2/loop/spec_loop_test.go` (or relevant test file) + +**What to Do:** + +**Change the `remediationRunner` interface** to use `Remediate` instead of `Run`: + +```go +type remediationRunner interface { + Remediate(ctx context.Context, specID, worktree string, findings []stagepkg.ReviewFinding) error +} +``` + +**Add a `specReviewStage` field and option to `SpecLoop`:** + +```go +// In SpecLoop struct: +specReviewStage stagepkg.Stage + +// New option: +func WithSpecReviewStage(stage stagepkg.Stage) SpecLoopOption { + return func(s *SpecLoop) { + s.specReviewStage = stage + } +} +``` + +**Refactor `ensureAcceptance` to `ensureAcceptanceAndReview`** (keep the existing name for backward compat, or rename — rename is cleaner): + +```go +func (s *SpecLoop) ensureAcceptance(ctx context.Context, req *stagepkg.Request, specID string) (*stagepkg.Result, error) { + retriesRemaining := maxAcceptanceRetries + for { + if err := s.ctxErr(ctx); err != nil { + return nil, err + } + + // Run accept stage + s.applyRouting(req, "accept") + acceptRes, err := s.runAcceptStage(ctx, req) + if err != nil { + return acceptRes, err + } + + // Run spec-level review stage (highest tier) + var reviewRes *stagepkg.Result + if s.specReviewStage != nil { + s.applyRouting(req, "specreview") + reviewRes, err = s.specReviewStage.Run(ctx, req) + if err != nil { + return reviewRes, err + } + } + + // Both must pass + acceptPassed := !s.acceptFailed(acceptRes) + reviewPassed := !s.reviewFailed(reviewRes) + if acceptPassed && reviewPassed { + return acceptRes, nil + } + + // Collect combined findings + findings := s.collectFindings(acceptRes, reviewRes) + + if s.remediationRunner == nil { + return acceptRes, fmt.Errorf("accept or review failed") + } + if retriesRemaining <= 0 { + return acceptRes, fmt.Errorf("%w: limit %d reached", ErrAcceptanceRetriesExceeded, maxAcceptanceRetries) + } + if err := s.remediationRunner.Remediate(ctx, specID, req.Worktree, findings); err != nil { + return acceptRes, err + } + retriesRemaining-- + } +} + +func (s *SpecLoop) reviewFailed(res *stagepkg.Result) bool { + if res == nil { + return false // no review stage = pass + } + return res.Decision == stagepkg.DecisionFail +} + +func (s *SpecLoop) collectFindings(acceptRes, reviewRes *stagepkg.Result) []stagepkg.ReviewFinding { + var findings []stagepkg.ReviewFinding + + // Extract from accept artifacts + if acceptRes != nil && acceptRes.Artifacts != nil { + if a, ok := acceptRes.Artifacts.(*stageaccept.AcceptArtifacts); ok { + findings = append(findings, a.Findings...) + } + } + + // Extract from specreview artifacts + if reviewRes != nil && reviewRes.Artifacts != nil { + if a, ok := reviewRes.Artifacts.(*stagepkg.SpecReviewArtifacts); ok { + for _, f := range a.Findings { + if f.Severity == "critical" { + findings = append(findings, f) + } + } + } + } + + return findings +} +``` + +Also update `Run()` to record the specreview stage name: + +```go +// After accept in StageSequence and Run(): +s.recordStage("specreview") +``` + +Add `"specreview"` to `StageSequence`. + +**Step 1: Write failing tests** + +```go +func TestSpecLoop_SpecReviewRunsAfterAccept(t *testing.T) { + // Wire spec loop with a mock accept (pass) and mock specreview (fail) + // Verify specreview is invoked after accept + // Verify remediationRunner.Remediate is called with specreview findings +} + +func TestSpecLoop_CombinesAcceptAndReviewFindings(t *testing.T) { + // Accept fails with 1 finding, specreview fails with 1 critical finding + // Verify Remediate receives 2 findings +} + +func TestSpecLoop_SkipsSpecReviewWhenNotConfigured(t *testing.T) { + // No specReviewStage configured + // Accept passes → succeeds without error +} +``` + +**Step 2: Run test to verify it fails** + +```bash +cd internal/v2/loop && go test ./... -run TestSpecLoop_SpecReview -v +``` +Expected: FAIL + +**Step 3: Implement** + +Apply changes to `spec_loop.go` as described. + +**Step 4: Run all loop tests** + +```bash +cd internal/v2/loop && go test ./... -v +``` +Expected: PASS + +**Step 5: Verify full module compiles** + +```bash +go build ./... +``` + +**Step 6: Commit** + +```bash +git add internal/v2/loop/spec_loop.go internal/v2/loop/spec_loop_test.go +git commit -m "green: spec loop runs specreview after accept, combines findings for Remediate" +``` + +**Acceptance Criteria:** +- `SpecLoop` has `specReviewStage` field and `WithSpecReviewStage` option +- `remediationRunner` interface uses `Remediate(ctx, specID, worktree, findings) error` +- Specreview runs after accept on every iteration +- When both accept and specreview pass, loop exits successfully +- Findings from both stages are combined and passed to `Remediate` +- `"specreview"` appears in `StageSequence` + +--- + +### Task 8: Wire specreview in run2_components + +**Files:** +- Modify: `internal/v2/loop/run2_components.go` + +**What to Do:** + +Load `review_spec_v2.md` fragment, create the specreview stage, set highest tier for it, and expose it via `Run2LoopComponents`. + +In `NewRun2LoopComponents`, after loading `acceptFragment`: + +```go +specReviewFragment, err := loadFragment(cfg.ProjectRoot, "review_spec_v2.md") +if err != nil { + cleanup() + return nil, err +} +``` + +Create the stage: + +```go +import specreviewstage "github.com/danabrams/gromit/internal/v2/stage/specreview" + +specReviewStage, err := specreviewstage.New(cfg, adapters.Git, adapters.LLM, adapters.TaskTracker, baseInstructions, projectContext, specReviewFragment) +if err != nil { + cleanup() + return nil, err +} +``` + +Add to `Run2LoopComponents`: + +```go +type Run2LoopComponents struct { + // existing fields ... + SpecReviewStage stagepkg.Stage +} +``` + +And return it: + +```go +return &Run2LoopComponents{ + // existing fields ... + SpecReviewStage: specReviewStage, +}, nil +``` + +In `run2.go`, wire `WithSpecReviewStage`: + +```go +loopInstance, err := newSpecLoopFn(adapters, cfg, gate, + // ... existing options ... + loop.WithSpecReviewStage(components.SpecReviewStage), +) +``` + +Also update the `phaseModels` / routing to route specreview as "high" tier. Add to routing: `TierForPhase("specreview", ...)` should return `TierHigh`. This can be done by adding `"specreview": "high"` to the phase models map in config or by hardcoding it in `run2_components.go`: + +```go +// In NewRun2LoopComponents, after building phaseModels: +// Ensure specreview always uses the high tier (highest-quality model). +if phaseModels == nil { + phaseModels = make(map[string]string) +} +// Don't overwrite if explicitly configured +if _, ok := phaseModels["specreview"]; !ok { + phaseModels["specreview"] = routing.TierHigh +} +``` + +**Step 1: Run existing tests to establish baseline** + +```bash +cd internal/v2/loop && go test ./... -v +``` +Expected: PASS (all existing tests) + +**Step 2: Implement the wiring** + +Apply changes to `run2_components.go`. + +**Step 3: Run all tests** + +```bash +go test ./... -count=1 +``` +Expected: PASS + +**Step 4: Verify the build** + +```bash +go build ./... +``` + +**Step 5: Commit** + +```bash +git add internal/v2/loop/run2_components.go +git commit -m "green: wire specreview stage into run2 components with high-tier routing" +``` + +**Acceptance Criteria:** +- `Run2LoopComponents.SpecReviewStage` field exists and is populated +- `review_spec_v2.md` fragment is loaded and passed to the specreview stage +- Specreview stage is wired to `WithSpecReviewStage` on the spec loop +- Routing routes "specreview" phase to `TierHigh` + +--- + +### Task 9: --from-review flag in run2.go + +**Files:** +- Modify: `cmd/gromit/run2.go` +- Create: `cmd/gromit/run2_from_review_test.go` + +**What to Do:** + +Add `--from-review` and `--spec` flags. When `--from-review` is set, skip normal spec resolution, query open beads with `from-review` label (optionally filtered by `spec:`), and run the bead loop directly. + +In `init()`: + +```go +func init() { + run2Cmd.Flags().String("epic", "", "Run specs scoped to the specified epic") + run2Cmd.Flags().Bool("from-review", false, "Run only beads with the from-review label") + run2Cmd.Flags().String("spec", "", "Scope --from-review to a specific spec ID") +} +``` + +In `run2()`, check the flag early: + +```go +fromReview, _ := cmd.Flags().GetBool("from-review") +if fromReview { + specScope, _ := cmd.Flags().GetString("spec") + return runFromReview(cmd.Context(), cfg, specScope, components) +} +``` + +Add `runFromReview` function: + +```go +func runFromReview(ctx context.Context, cfg *config.Config, specScope string, components *loop.Run2LoopComponents) error { + // Build query labels + labels := []string{"from-review"} + if specScope != "" { + labels = append(labels, fmt.Sprintf("spec:%s", specScope)) + } + + // Query open from-review beads + resp, err := taskTrackerAdapter.QueryBeads(ctx, trackertypes.TaskTrackerQueryBeadsRequest{ + Labels: labels, + StatusIn: []string{"open"}, + }) + if err != nil { + return fmt.Errorf("query from-review beads: %w", err) + } + if resp == nil || len(resp.Beads) == 0 { + fmt.Println("No open from-review beads found.") + return nil + } + + beads := make([]*bead.Bead, len(resp.Beads)) + for i, b := range resp.Beads { + beads[i] = &bead.Bead{ID: b.ID, Title: b.Title, Description: b.Description, Priority: b.Priority, Labels: b.Labels} + } + + // Run bead loop directly — no plan, no decompose, no accept, no review + stopCh := make(chan struct{}) + _, err = components.BeadLoop.Run(ctx, beads, stopCh) + return err +} +``` + +Note: the function needs access to `taskTrackerAdapter`. Refactor to pass it in or build it inside the function using the same adapter construction logic from `run2()`. Use the existing pattern from `run2()` to construct the task tracker adapter. + +**Step 1: Write the failing test** + +```go +func TestRun2FromReviewFlag_QueriesFromReviewBeads(t *testing.T) { + // Set --from-review flag + // Verify task tracker queried with label "from-review" + // Verify bead loop runs with the returned beads + // Verify no accept/review/decompose stages called +} + +func TestRun2FromReviewFlag_WithSpec_ScopesLabel(t *testing.T) { + // Set --from-review --spec my-spec + // Verify task tracker queried with labels ["from-review", "spec:my-spec"] +} + +func TestRun2FromReviewFlag_NoBeads_PrintsMessage(t *testing.T) { + // Task tracker returns empty response + // Verify function returns nil (no error) and prints "No open from-review beads found." +} +``` + +**Step 2: Run test to verify it fails** + +```bash +cd cmd/gromit && go test ./... -run TestRun2FromReview -v +``` +Expected: FAIL + +**Step 3: Implement** + +Add flags and `runFromReview` function. + +**Step 4: Run tests** + +```bash +cd cmd/gromit && go test ./... -v +``` +Expected: PASS + +**Step 5: Verify full build** + +```bash +go build ./... +go test ./... -count=1 +``` + +**Step 6: Commit** + +```bash +git add cmd/gromit/run2.go cmd/gromit/run2_from_review_test.go +git commit -m "green: --from-review flag runs only from-review beads without plan/accept/review cycle" +``` + +**Acceptance Criteria:** +- `run2 --from-review` queries beads with label `from-review` and runs bead loop +- `run2 --from-review --spec ` additionally filters by `spec:` label +- When no beads found, prints message and returns nil +- From-review run does NOT invoke plan, decompose, accept, or spec-level review stages +- Existing `run2` behavior unchanged when `--from-review` is not set + +--- + +## Integration Test: Full Post-Bead-Loop Pipeline + +After all tasks are complete, verify end-to-end with an integration test: + +**File:** `internal/v2/loop/spec_loop_integration_test.go` + +```go +func TestIntegration_AcceptPassesReviewFails_RemediatesWithFindings(t *testing.T) { + // Wire spec loop with: + // - accept stage that passes + // - specreview stage that returns one critical finding + // - remediation runner that captures received findings + // Verify: Remediate called with the critical finding from review +} + +func TestIntegration_BothPassWithImprovements_SpecProceedsFromReviewBeadsCreated(t *testing.T) { + // Wire spec loop with: + // - accept stage that passes + // - specreview stage that returns "pass" verdict with one warning finding (scope: spec) + // Verify: Result is success (no remediation) + // Verify: from-review bead created in tracker with labels ["from-review", "spec:"] +} +``` + +```bash +go test ./internal/v2/loop/... -run TestIntegration -v +git add internal/v2/loop/spec_loop_integration_test.go +git commit -m "green: integration tests for full post-bead-loop pipeline" +``` diff --git a/internal/v2/stage/accept/accept.go b/internal/v2/stage/accept/accept.go index d74d8be7c..1e758414d 100644 --- a/internal/v2/stage/accept/accept.go +++ b/internal/v2/stage/accept/accept.go @@ -64,10 +64,26 @@ type GitDiffer interface { DiffFromBase(ctx context.Context, worktree string) (string, error) } +// Finding describes a structured observation about an unmet acceptance criterion. +type Finding struct { + Severity string + Category string + Scope string + Description string + AffectedFiles []string +} + // AcceptArtifacts captures acceptance evaluation results produced by the stage. type AcceptArtifacts struct { Results []presentation.AcceptanceResult GapSummary string + Findings []Finding +} + +type failureDetail struct { + Criterion coverage.Criterion + Description string + GapEntry string } // GetGapSummary returns the gap summary, or empty string if the receiver is nil. @@ -189,58 +205,38 @@ func (s *Stage) Run(ctx context.Context, req *stagepkg.Request) (*stagepkg.Resul provider = req.Provider } - // Small diffs: evaluate all criteria in one invocation (cheap, fast). - // Large diffs: first identify relevant files per criterion, then evaluate - // each criterion with only its relevant portion of the diff. threshold := s.diffThreshold() if threshold > 0 { if len(diff) <= threshold { s.Log("info", "accept: diff is %d bytes (≤%d threshold), using batch evaluation for %d criteria", len(diff), threshold, len(criteria)) - return s.runBatchEvaluation(ctx, provider, specID, criteria, diff, cfg, req, root) + results, failures, evalErr := s.runBatchEvaluation(ctx, provider, specID, criteria, diff, cfg, req, root) + if evalErr != nil { + return nil, evalErr + } + return s.finalizeAcceptResult(ctx, root, cfg, req, provider, specID, criteria, diff, results, failures, nil) } s.Log("info", "accept: diff is %d bytes (>%d threshold), using targeted evaluation for %d criteria", len(diff), threshold, len(criteria)) - results, failures, evalErr := s.runTargetedEvaluation(ctx, provider, specID, criteria, diff, cfg, req) + results, failures, mapping, evalErr := s.runTargetedEvaluation(ctx, provider, specID, criteria, diff, cfg, req) if evalErr != nil { return nil, evalErr } - - artifacts := &AcceptArtifacts{Results: results} - if len(failures) > 0 { - gapSummary := strings.Join(failures, "\n") - artifacts.GapSummary = gapSummary - if err := s.writeGapAnalysis(root, cfg, gapSummary); err != nil { - return nil, fmt.Errorf("write gap analysis: %w", err) - } - return &stagepkg.Result{Decision: stagepkg.DecisionFail, Artifacts: artifacts}, nil - } - return &stagepkg.Result{Decision: stagepkg.DecisionProceed, Artifacts: artifacts}, nil + return s.finalizeAcceptResult(ctx, root, cfg, req, provider, specID, criteria, diff, results, failures, mapping) } - // Per-criterion fallback (threshold disabled or negative). results, failures, evalErr := s.runPerCriterionEvaluation(ctx, provider, specID, criteria, diff, cfg, req) if evalErr != nil { return nil, evalErr } - artifacts := &AcceptArtifacts{Results: results} - if len(failures) > 0 { - gapSummary := strings.Join(failures, "\n") - artifacts.GapSummary = gapSummary - if err := s.writeGapAnalysis(root, cfg, gapSummary); err != nil { - return nil, fmt.Errorf("write gap analysis: %w", err) - } - return &stagepkg.Result{Decision: stagepkg.DecisionFail, Artifacts: artifacts}, nil - } - - return &stagepkg.Result{Decision: stagepkg.DecisionProceed, Artifacts: artifacts}, nil + return s.finalizeAcceptResult(ctx, root, cfg, req, provider, specID, criteria, diff, results, failures, nil) } // runPerCriterionEvaluation evaluates each criterion in a separate LLM invocation. // Used when the diff is small enough that per-criterion calls are practical. -func (s *Stage) runPerCriterionEvaluation(ctx context.Context, provider llmtypes.LLMProvider, specID string, criteria []coverage.Criterion, diff string, cfg *config.Config, req *stagepkg.Request) ([]presentation.AcceptanceResult, []string, error) { +func (s *Stage) runPerCriterionEvaluation(ctx context.Context, provider llmtypes.LLMProvider, specID string, criteria []coverage.Criterion, diff string, cfg *config.Config, req *stagepkg.Request) ([]presentation.AcceptanceResult, []failureDetail, error) { results := make([]presentation.AcceptanceResult, 0, len(criteria)) - failures := make([]string, 0) + failures := make([]failureDetail, 0, len(criteria)) for _, criterion := range criteria { if ctx.Err() != nil { @@ -274,7 +270,13 @@ func (s *Stage) runPerCriterionEvaluation(ctx context.Context, provider llmtypes score := "PASS" if !pass { score = "FAIL" - failures = append(failures, fmt.Sprintf("Criterion %d failed: %s — %s", criterion.Number, trimmed, summaryOrDefault(summary))) + description := fmt.Sprintf("%s — %s", trimmed, summaryOrDefault(summary)) + gapEntry := fmt.Sprintf("Criterion %d failed: %s — %s", criterion.Number, trimmed, summaryOrDefault(summary)) + failures = append(failures, failureDetail{ + Criterion: criterion, + Description: description, + GapEntry: gapEntry, + }) } s.Log("info", "accept: criterion %d %s (%s)", criterion.Number, score, elapsed.Truncate(time.Second)) @@ -293,7 +295,7 @@ func (s *Stage) runPerCriterionEvaluation(ctx context.Context, provider llmtypes // runTargetedEvaluation handles large diffs by first asking the LLM to map // criteria to relevant files (cheap — only diff stat), then evaluating each // criterion with only its relevant diff hunks. -func (s *Stage) runTargetedEvaluation(ctx context.Context, provider llmtypes.LLMProvider, specID string, criteria []coverage.Criterion, diff string, cfg *config.Config, req *stagepkg.Request) ([]presentation.AcceptanceResult, []string, error) { +func (s *Stage) runTargetedEvaluation(ctx context.Context, provider llmtypes.LLMProvider, specID string, criteria []coverage.Criterion, diff string, cfg *config.Config, req *stagepkg.Request) ([]presentation.AcceptanceResult, []failureDetail, map[int][]string, error) { model := s.selectModel(cfg, req) fileDiffs := splitDiffByFile(diff) @@ -308,19 +310,19 @@ func (s *Stage) runTargetedEvaluation(ctx context.Context, provider llmtypes.LLM if err != nil { if isDeadlineExceeded(err) { s.Log("info", "accept: criteria-to-file mapping timed out, falling back to full diff per criterion") - // Fall back to per-criterion with full diff (original behavior). - return s.runPerCriterionEvaluation(ctx, provider, specID, criteria, diff, cfg, req) + results, failures, perErr := s.runPerCriterionEvaluation(ctx, provider, specID, criteria, diff, cfg, req) + return results, failures, nil, perErr } - return nil, nil, fmt.Errorf("map criteria to files: %w", err) + return nil, nil, nil, fmt.Errorf("map criteria to files: %w", err) } // Phase 2: Evaluate each criterion with only its relevant diff. results := make([]presentation.AcceptanceResult, 0, len(criteria)) - failures := make([]string, 0) + failures := make([]failureDetail, 0, len(criteria)) for _, criterion := range criteria { if ctx.Err() != nil { - return nil, nil, fmt.Errorf("accept interrupted: %w", ctx.Err()) + return nil, nil, nil, fmt.Errorf("accept interrupted: %w", ctx.Err()) } trimmed := strings.TrimSpace(criterion.Text) @@ -341,21 +343,27 @@ func (s *Stage) runTargetedEvaluation(ctx context.Context, provider llmtypes.LLM if evalErr != nil { if ctx.Err() != nil { - return nil, nil, fmt.Errorf("accept interrupted during criterion %d: %w", criterion.Number, evalErr) + return nil, nil, nil, fmt.Errorf("accept interrupted during criterion %d: %w", criterion.Number, evalErr) } if isDeadlineExceeded(evalErr) { s.Log("info", "accept: criterion %d timed out after %s, marking FAIL", criterion.Number, elapsed.Truncate(time.Second)) pass = false summary = fmt.Sprintf("evaluation timed out after %s", elapsed.Truncate(time.Second)) } else { - return nil, nil, fmt.Errorf("evaluate criterion %d: %w", criterion.Number, evalErr) + return nil, nil, nil, fmt.Errorf("evaluate criterion %d: %w", criterion.Number, evalErr) } } score := "PASS" if !pass { score = "FAIL" - failures = append(failures, fmt.Sprintf("Criterion %d failed: %s — %s", criterion.Number, trimmed, summaryOrDefault(summary))) + description := fmt.Sprintf("%s — %s", trimmed, summaryOrDefault(summary)) + gapEntry := fmt.Sprintf("Criterion %d failed: %s — %s", criterion.Number, trimmed, summaryOrDefault(summary)) + failures = append(failures, failureDetail{ + Criterion: criterion, + Description: description, + GapEntry: gapEntry, + }) } s.Log("info", "accept: criterion %d %s (%s)", criterion.Number, score, elapsed.Truncate(time.Second)) @@ -366,7 +374,7 @@ func (s *Stage) runTargetedEvaluation(ctx context.Context, provider llmtypes.LLM }) } - return results, failures, nil + return results, failures, fileMapping, nil } // mapCriteriaToFiles asks the LLM to identify which files are relevant to each @@ -487,7 +495,7 @@ func buildTargetedDiff(files []string, fileDiffs map[string]string) string { return b.String() } -func (s *Stage) runBatchEvaluation(ctx context.Context, provider llmtypes.LLMProvider, specID string, criteria []coverage.Criterion, diff string, cfg *config.Config, req *stagepkg.Request, root string) (*stagepkg.Result, error) { +func (s *Stage) runBatchEvaluation(ctx context.Context, provider llmtypes.LLMProvider, specID string, criteria []coverage.Criterion, diff string, cfg *config.Config, req *stagepkg.Request, root string) ([]presentation.AcceptanceResult, []failureDetail, error) { model := s.selectModel(cfg, req) var criteriaList strings.Builder @@ -541,41 +549,84 @@ Do NOT output markdown, commentary, or anything other than the JSON array.`, if err != nil { if isDeadlineExceeded(err) { s.Log("info", "accept: batch evaluation timed out after %s, marking all criteria FAIL", elapsed.Truncate(time.Second)) - return s.allCriteriaFailed(criteria, fmt.Sprintf("batch evaluation timed out after %s", elapsed.Truncate(time.Second)), root, cfg) + reason := fmt.Sprintf("batch evaluation timed out after %s", elapsed.Truncate(time.Second)) + results, failures := s.buildTimeoutFailures(criteria, reason) + return results, failures, nil } - return nil, fmt.Errorf("batch evaluate: %w", err) + return nil, nil, fmt.Errorf("batch evaluate: %w", err) } if resp == nil { - return nil, fmt.Errorf("batch evaluate: provider returned nil response") + return nil, nil, fmt.Errorf("batch evaluate: provider returned nil response") } if !resp.Success { detail := strings.TrimSpace(resp.Output) if detail == "" { detail = "no detail available" } - return nil, fmt.Errorf("batch evaluate: provider reported unsuccessful invocation: %s", detail) + return nil, nil, fmt.Errorf("batch evaluate: provider reported unsuccessful invocation: %s", detail) } lastOutput = resp.Output batchResults, parseErr := parseBatchEvaluation(resp.Output, len(criteria)) if parseErr == nil { s.Log("info", "accept: batch evaluation completed in %s", elapsed.Truncate(time.Second)) - return s.buildBatchResult(criteria, batchResults, root, cfg) + results, failures := s.buildBatchOutcome(criteria, batchResults) + return results, failures, nil } if attempt == maxEvalParseRetries { preview := lastOutput if len(preview) > outputPreviewMaxLen { preview = preview[:outputPreviewMaxLen] + "... (truncated)" } - return nil, fmt.Errorf("parse batch evaluation: %w\nLLM output preview: %s", parseErr, preview) + return nil, nil, fmt.Errorf("parse batch evaluation: %w\nLLM output preview: %s", parseErr, preview) } } - return nil, fmt.Errorf("unreachable: batch evaluation loop exited without result") + return nil, nil, fmt.Errorf("unreachable: batch evaluation loop exited without result") } -func (s *Stage) allCriteriaFailed(criteria []coverage.Criterion, reason string, root string, cfg *config.Config) (*stagepkg.Result, error) { +func (s *Stage) buildBatchOutcome(criteria []coverage.Criterion, batchResults []batchEvalResult) ([]presentation.AcceptanceResult, []failureDetail) { results := make([]presentation.AcceptanceResult, 0, len(criteria)) - failures := make([]string, 0, len(criteria)) + failures := make([]failureDetail, 0, len(criteria)) + + resultMap := make(map[int]batchEvalResult, len(batchResults)) + for _, br := range batchResults { + resultMap[br.Criterion] = br + } + + for _, c := range criteria { + text := strings.TrimSpace(c.Text) + if text == "" { + text = fmt.Sprintf("criterion %d", c.Number) + } + + br, found := resultMap[c.Number] + pass := found && br.Pass + score := "PASS" + if !pass { + score = "FAIL" + description := fmt.Sprintf("%s — %s", text, summaryOrDefault(br.Summary)) + gapEntry := fmt.Sprintf("Criterion %d failed: %s — %s", c.Number, text, summaryOrDefault(br.Summary)) + failures = append(failures, failureDetail{ + Criterion: c, + Description: description, + GapEntry: gapEntry, + }) + } + + s.Log("info", "accept: criterion %d %s", c.Number, score) + + results = append(results, presentation.AcceptanceResult{ + Title: text, + Description: fmt.Sprintf("%s: %s", score, summaryOrDefault(br.Summary)), + }) + } + + return results, failures +} + +func (s *Stage) buildTimeoutFailures(criteria []coverage.Criterion, reason string) ([]presentation.AcceptanceResult, []failureDetail) { + results := make([]presentation.AcceptanceResult, 0, len(criteria)) + failures := make([]failureDetail, 0, len(criteria)) for _, c := range criteria { text := strings.TrimSpace(c.Text) if text == "" { @@ -585,15 +636,89 @@ func (s *Stage) allCriteriaFailed(criteria []coverage.Criterion, reason string, Title: text, Description: fmt.Sprintf("FAIL: %s", reason), }) - failures = append(failures, fmt.Sprintf("Criterion %d failed: %s — %s", c.Number, text, reason)) + failures = append(failures, failureDetail{ + Criterion: c, + Description: fmt.Sprintf("%s — %s", text, reason), + GapEntry: fmt.Sprintf("Criterion %d failed: %s — %s", c.Number, text, reason), + }) + } + return results, failures +} + +func (s *Stage) finalizeAcceptResult(ctx context.Context, root string, cfg *config.Config, req *stagepkg.Request, provider llmtypes.LLMProvider, specID string, criteria []coverage.Criterion, diff string, results []presentation.AcceptanceResult, failures []failureDetail, mapping map[int][]string) (*stagepkg.Result, error) { + artifacts := &AcceptArtifacts{Results: results} + if len(failures) == 0 { + return &stagepkg.Result{Decision: stagepkg.DecisionProceed, Artifacts: artifacts}, nil } - artifacts := &AcceptArtifacts{Results: results, GapSummary: strings.Join(failures, "\n")} - if err := s.writeGapAnalysis(root, cfg, artifacts.GapSummary); err != nil { + + gapSummary := s.buildGapSummary(failures) + artifacts.GapSummary = gapSummary + if err := s.writeGapAnalysis(root, cfg, gapSummary); err != nil { return nil, fmt.Errorf("write gap analysis: %w", err) } + + mappingForFindings := mapping + if mappingForFindings == nil { + mappingForFindings = s.collectCriterionMapping(ctx, provider, specID, criteria, diff, cfg, req) + } + artifacts.Findings = s.buildFindingsFromFailures(failures, mappingForFindings) + return &stagepkg.Result{Decision: stagepkg.DecisionFail, Artifacts: artifacts}, nil } +func (s *Stage) buildGapSummary(failures []failureDetail) string { + entries := make([]string, 0, len(failures)) + for _, f := range failures { + entries = append(entries, f.GapEntry) + } + return strings.Join(entries, "\n") +} + +func (s *Stage) buildFindingsFromFailures(failures []failureDetail, mapping map[int][]string) []Finding { + if len(failures) == 0 { + return nil + } + + findings := make([]Finding, 0, len(failures)) + for _, f := range failures { + affected := mapping[f.Criterion.Number] + finding := Finding{ + Severity: "critical", + Category: "acceptance", + Scope: "spec", + Description: f.Description, + } + if len(affected) > 0 { + finding.AffectedFiles = append([]string(nil), affected...) + } + findings = append(findings, finding) + } + return findings +} + +func (s *Stage) collectCriterionMapping(ctx context.Context, provider llmtypes.LLMProvider, specID string, criteria []coverage.Criterion, diff string, cfg *config.Config, req *stagepkg.Request) map[int][]string { + if provider == nil || len(criteria) == 0 { + return nil + } + fileDiffs := splitDiffByFile(diff) + if len(fileDiffs) == 0 { + return nil + } + + files := make([]string, 0, len(fileDiffs)) + for name := range fileDiffs { + files = append(files, name) + } + + model := s.selectModel(cfg, req) + mapping, err := s.mapCriteriaToFiles(ctx, provider, model, specID, criteria, files, req) + if err != nil { + s.Log("warn", "accept: failed to map criteria to files for findings: %v", err) + return nil + } + return mapping +} + type batchEvalResult struct { Criterion int `json:"criterion"` Pass bool `json:"pass"` @@ -624,55 +749,6 @@ func parseBatchEvaluation(output string, expectedCount int) ([]batchEvalResult, return []batchEvalResult{single}, nil } -func (s *Stage) buildBatchResult(criteria []coverage.Criterion, batchResults []batchEvalResult, root string, cfg *config.Config) (*stagepkg.Result, error) { - // Index batch results by criterion number for lookup. - resultMap := make(map[int]batchEvalResult, len(batchResults)) - for _, br := range batchResults { - resultMap[br.Criterion] = br - } - - results := make([]presentation.AcceptanceResult, 0, len(criteria)) - failures := make([]string, 0) - - for _, c := range criteria { - text := strings.TrimSpace(c.Text) - if text == "" { - text = fmt.Sprintf("criterion %d", c.Number) - } - - br, found := resultMap[c.Number] - pass := found && br.Pass - summary := "no evaluation returned for this criterion" - if found { - summary = strings.TrimSpace(br.Summary) - } - - score := "PASS" - if !pass { - score = "FAIL" - failures = append(failures, fmt.Sprintf("Criterion %d failed: %s — %s", c.Number, text, summaryOrDefault(summary))) - } - - s.Log("info", "accept: criterion %d %s", c.Number, score) - - results = append(results, presentation.AcceptanceResult{ - Title: text, - Description: fmt.Sprintf("%s: %s", score, summaryOrDefault(summary)), - }) - } - - artifacts := &AcceptArtifacts{Results: results} - if len(failures) > 0 { - gapSummary := strings.Join(failures, "\n") - artifacts.GapSummary = gapSummary - if err := s.writeGapAnalysis(root, cfg, gapSummary); err != nil { - return nil, fmt.Errorf("write gap analysis: %w", err) - } - return &stagepkg.Result{Decision: stagepkg.DecisionFail, Artifacts: artifacts}, nil - } - return &stagepkg.Result{Decision: stagepkg.DecisionProceed, Artifacts: artifacts}, nil -} - func buildBatchRepairPrompt(previousOutput string, criteriaCount int) string { return fmt.Sprintf(`Your previous response was not valid JSON. Here is what you wrote: diff --git a/internal/v2/stage/accept/accept_test.go b/internal/v2/stage/accept/accept_test.go index 59efeabef..e7d0ed8e7 100644 --- a/internal/v2/stage/accept/accept_test.go +++ b/internal/v2/stage/accept/accept_test.go @@ -105,6 +105,14 @@ func TestRunWritesGapAnalysisWhenCriterionFails(t *testing.T) { } } +func TestAcceptArtifactsFindingsField(t *testing.T) { + t.Parallel() + var artifacts AcceptArtifacts + if len(artifacts.Findings) != 0 { + t.Fatalf("expected zero findings, got %d", len(artifacts.Findings)) + } +} + func TestRunProceedWhenAllCriteriaPass(t *testing.T) { t.Parallel() @@ -182,6 +190,80 @@ func TestRunProceedWhenAllCriteriaPass(t *testing.T) { } } +func TestAcceptStageProducesFindingsForFailedCriteria(t *testing.T) { + t.Parallel() + + specID := "spec-findings" + tmp := t.TempDir() + specDir := filepath.Join(tmp, ".gromit", "specs") + if err := os.MkdirAll(specDir, 0o755); err != nil { + t.Fatalf("create specs dir: %v", err) + } + specPath := filepath.Join(specDir, specID+".md") + content := "# Findings spec\n\n## Acceptance Criteria\n- ensure mapping works\n" + if err := os.WriteFile(specPath, []byte(content), 0o644); err != nil { + t.Fatalf("write spec: %v", err) + } + + cfg := &config.Config{ + ProjectRoot: tmp, + Paths: config.PathsConfig{ + GromitDir: ".gromit", + Specs: ".gromit/specs", + }, + } + + git := &fakeGitAdapter{ + diff: "diff --git a/foo/bar.go b/foo/bar.go\nindex 0000000..1111111 100644\n--- a/foo/bar.go\n+++ b/foo/bar.go\n@@\n+func foo() {}\n", + } + llmProvider := &fakeLLM{ + responses: []*llm.LLMResponse{ + {Success: true, Output: `{"1":["foo/bar.go"]}`}, + {Success: true, Output: `{"pass": false, "summary": "needs tests"}`}, + }, + } + + stageInstance, err := New(cfg, git, llmProvider, "BASE", "PROJECT", "FRAGMENT") + if err != nil { + t.Fatalf("create stage: %v", err) + } + stageInstance.batchDiffThreshold = 5 // ensure diff exceeds threshold for targeted evaluation + + req := &stagepkg.Request{ + Bead: stagepkg.BeadInfo{ID: specID}, + Worktree: tmp, + } + + res, err := stageInstance.Run(context.Background(), req) + if err != nil { + t.Fatalf("run stage: %v", err) + } + if res.Decision != stagepkg.DecisionFail { + t.Fatalf("decision = %v, want %v", res.Decision, stagepkg.DecisionFail) + } + + artifacts, ok := res.Artifacts.(*AcceptArtifacts) + if !ok { + t.Fatalf("artifacts type = %T, want *AcceptArtifacts", res.Artifacts) + } + if len(artifacts.Findings) != 1 { + t.Fatalf("findings count = %d, want 1", len(artifacts.Findings)) + } + finding := artifacts.Findings[0] + if finding.Severity != "critical" { + t.Fatalf("severity = %q, want critical", finding.Severity) + } + if finding.Category != "acceptance" { + t.Fatalf("category = %q, want acceptance", finding.Category) + } + if finding.Scope != "spec" { + t.Fatalf("scope = %q, want spec", finding.Scope) + } + if len(finding.AffectedFiles) != 1 || finding.AffectedFiles[0] != "foo/bar.go" { + t.Fatalf("affected files = %v, want [foo/bar.go]", finding.AffectedFiles) + } +} + type fakeLLM struct { calls []llm.InvokeRequest responses []*llm.LLMResponse