Skip to content

Commit c78673b

Browse files
AJBcodingclaude
andcommitted
fix(refinery): scope discipline — claim only MR queue, not generic bd backlog (gt-a15)
Refinery is an autonomous agent driven by its role template. Nothing in Go auto-claimed beads for it, but the template (1) never forbade claiming generic backlog beads and (2) told it to 'bd list --assignee=refinery' at startup, which surfaced any assigned bead. On 2026-05-03 this pulled the refinery off the merge queue to investigate a misrouted P2 bead; the queue stalled 25+ minutes while polecat work failed to land. Add an explicit SCOPE DISCIPLINE rule: the merge queue (gt mq list) plus the refinery's own patrol wisp are its ONLY work sources. Misrouted generic beads are escalated to the witness, never worked. Remove the misleading startup bd-list line. Add TestRenderRole_Refinery_ScopeDiscipline as a regression guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6bcb0ea commit c78673b

2 files changed

Lines changed: 59 additions & 4 deletions

File tree

internal/templates/roles/refinery.md.tmpl

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,19 @@ queue for your rig, merging polecat work to its target branch one at a time with
5555
goes through the **witness**, who manages polecat lifecycles and can re-sling work.
5656
Integration branches may ONLY be landed via `{{ cmd }} mq integration land <epic-id>`.
5757

58+
**SCOPE DISCIPLINE: The merge queue is your ONLY work source.**
59+
- Your work queue is `{{ cmd }} mq list {{ .RigName }}` — MR wisps submitted by polecats. Nothing else.
60+
- You do NOT claim generic `bd` issues from the rig backlog, even ones assigned to you.
61+
`bd ready`, `bd list`, and a generic bead with `assignee={{ .RigName }}/refinery` are NOT your work queue.
62+
- The ONLY beads you legitimately work are: (a) MR wisps in the merge queue, and (b) your own
63+
patrol wisp (`mol-refinery-patrol`). A generic task bead is neither.
64+
- If a generic (non-MR) bead is assigned to you, do NOT investigate, audit, or implement it.
65+
Escalate to the witness/mayor instead and keep processing the queue:
66+
`{{ cmd }} mail send {{ .RigName }}/witness -s "SCOPE: misrouted bead <id>" -m "Bead <id> assigned to refinery is not an MR. Reassign to a polecat. I am staying on the merge queue."`
67+
- **Why this rule exists**: a misrouted backlog bead once pulled the Refinery off the queue to
68+
investigate work it should never have claimed; the merge queue stalled for 25+ minutes while
69+
polecats' completed work failed to land. The queue always comes first.
70+
5871
**The Scotty Test**: Before proceeding past any failure, ask yourself:
5972
"Would Scotty walk past a warp core leak because it existed before his shift?"
6073

@@ -140,13 +153,16 @@ Print the startup banner:
140153
```
141154

142155
```bash
143-
gt hook # Check for hooked patrol
144-
bd list --status=in_progress --assignee=refinery
145-
# If no patrol:
156+
gt hook # Check for hooked patrol wisp
157+
# If no patrol wisp:
146158
{{ cmd }} patrol new # Creates root-only wisp with config vars and hooks it
147159
```
148160

149-
**No thinking. No "should I?" questions. Hook → Execute.**
161+
⚠️ **The only bead you act on at startup is your patrol wisp.** If `gt hook` shows a
162+
generic (non-MR, non-patrol) task bead, do NOT work it — apply SCOPE DISCIPLINE above:
163+
escalate to the witness and create/run your patrol wisp instead.
164+
165+
**No thinking. No "should I?" questions. Hook → Execute (the queue, not the backlog).**
150166

151167
## Hookable Mail
152168

internal/templates/templates_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,45 @@ func TestRenderRole_Refinery_DefaultBranch(t *testing.T) {
188188
}
189189
}
190190

191+
// TestRenderRole_Refinery_ScopeDiscipline verifies the refinery role makes the
192+
// merge queue its only work source and explicitly forbids claiming generic bd
193+
// backlog issues. Regression guard for gt-a15: the Refinery once claimed a
194+
// generic assigned bead and stalled the merge queue for 25+ minutes.
195+
func TestRenderRole_Refinery_ScopeDiscipline(t *testing.T) {
196+
tmpl, err := New()
197+
if err != nil {
198+
t.Fatalf("New() error = %v", err)
199+
}
200+
201+
data := RoleData{
202+
Role: "refinery",
203+
RigName: "myrig",
204+
TownRoot: "/test/town",
205+
TownName: "town",
206+
WorkDir: "/test/town/myrig/refinery/rig",
207+
DefaultBranch: "main",
208+
MayorSession: "gt-town-mayor",
209+
DeaconSession: "gt-town-deacon",
210+
}
211+
212+
output, err := tmpl.RenderRole("refinery", data)
213+
if err != nil {
214+
t.Fatalf("RenderRole() error = %v", err)
215+
}
216+
217+
if !strings.Contains(output, "SCOPE DISCIPLINE: The merge queue is your ONLY work source.") {
218+
t.Error("output missing SCOPE DISCIPLINE heading - refinery must be scoped to the merge queue")
219+
}
220+
if !strings.Contains(output, "do NOT claim generic `bd` issues") {
221+
t.Error("output missing prohibition on claiming generic bd backlog issues")
222+
}
223+
// The old startup line actively told refinery to list assigned beads, which
224+
// surfaced generic backlog beads. It must no longer be present.
225+
if strings.Contains(output, "bd list --status=in_progress --assignee=refinery") {
226+
t.Error("output still contains the startup 'bd list --assignee=refinery' line that surfaced generic backlog beads")
227+
}
228+
}
229+
191230
func TestRenderMessage_Spawn(t *testing.T) {
192231
tmpl, err := New()
193232
if err != nil {

0 commit comments

Comments
 (0)