Skip to content

fix(gastown): dispatch refinery to correct rig in multi-rig towns#693

Merged
jrf0110 merged 4 commits intomainfrom
657-refinery-wrong-rig
Mar 1, 2026
Merged

fix(gastown): dispatch refinery to correct rig in multi-rig towns#693
jrf0110 merged 4 commits intomainfrom
657-refinery-wrong-rig

Conversation

@jrf0110
Copy link
Contributor

@jrf0110 jrf0110 commented Mar 1, 2026

Summary

Fixes 4 compounding bugs that caused the refinery agent to be dispatched into the wrong rig's repository in multi-rig towns, fixes 3 additional issues with MR bead assignment and the review lifecycle, and adds a Related Beads DAG section to the bead drawer UI.

Closes #657

Note: This branch is based on 686-pr544-review-hardening (PR #689) which is pending review. Once #689 merges to main, this PR will be clean against main.

Also adds UI to show relationship between related beads (like a task bead to review bead)

image

The bug chain (before this fix)

  1. Polecat on rig B finishes work -> submitToReviewQueue
  2. MR bead created with rig_id = null and assignee = polecat (Bugs 3, 5)
  3. Alarm fires -> processReviewQueue pops the entry
  4. Rig resolved via rigList[0] -> gets rig A (Bug 2)
  5. getOrCreateAgent('refinery') returns the existing refinery for rig A (Bug 1)
  6. Refinery hooked to the source bead (not the MR bead), overwriting its assignee (Bug 6)
  7. Source bead left in_progress instead of closed (Bug 7)

Fixes

Bug 1: Refinery was a town-wide singleton

  • agents.ts: Removed refinery from singletonRoles (now only witness and mayor)
  • Refinery now uses the same per-rig idle agent reuse logic as polecats, scoped by rig_id

Bug 2: processReviewQueue hardcoded rigList[0]

  • Town.do.ts: Now reads entry.rig_id from the merge_request bead

Bug 3: merge_request beads created with rig_id = null

  • review-queue.ts: submitToReviewQueue now writes input.rig_id to the bead

Bug 4: ReviewQueueInput type lacked rig_id

  • types.ts: Added rig_id: string to both ReviewQueueInput and ReviewQueueEntry

Bug 5: MR bead assignee set to polecat instead of left for refinery

  • review-queue.ts: MR bead assignee_agent_bead_id now null on creation (refinery claims it via hookBead). Source agent stored in metadata.source_agent_id.

Bug 6: Refinery hooked to source bead, not MR bead

  • Town.do.ts: processReviewQueue now hooks the refinery to entry.id (MR bead), not entry.bead_id (source bead). This preserves the source bead's polecat assignee.
  • review-queue.ts: Refinery agentDone path updated — completeReviewFromMRBead reads the source bead from the MR's metadata instead of the old completeReviewForSourceBead lookup.

Bug 7: Source bead not closed after polecat submits to review

  • review-queue.ts: agentDone (polecat path) now calls closeBead on the source bead after submitting to the review queue, matching upstream gt done behavior.

Feature: Related Beads DAG in bead drawer

  • BeadPanel.tsx: New "Related Beads" section shows the bead's DAG neighborhood:
    • Child beads — beads whose parent_bead_id matches the current bead
    • Source Work — for MR beads, the original issue/work bead from metadata.source_bead_id
    • Review — for non-MR beads, any merge_request beads that track this bead
  • Each entry is clickable, pushing a new bead drawer onto the navigation stack
  • Computed client-side from existing listBeads data — no new API endpoints
  • Also adds a bead_dependencies 'tracks' row when creating MR beads to formally link the DAG

Files changed

File Change
cloudflare-gastown/src/types.ts Added rig_id to ReviewQueueInput and ReviewQueueEntry
cloudflare-gastown/src/dos/town/agents.ts Refinery per-rig, generalized idle agent lookup
cloudflare-gastown/src/dos/town/review-queue.ts MR bead lifecycle fixes, bead_dependencies tracking
cloudflare-gastown/src/dos/Town.do.ts Hook refinery to MR bead, resolve rig from bead
cloudflare-gastown/src/handlers/rig-review-queue.handler.ts Pass params.rigId to submitToReviewQueue
src/components/gastown/drawer-panels/BeadPanel.tsx Related Beads DAG section
cloudflare-gastown/test/integration/rig-do.test.ts Add rig_id to test data
cloudflare-gastown/test/integration/rig-alarm.test.ts Add rig_id to test data

@kilo-code-bot
Copy link
Contributor

kilo-code-bot bot commented Mar 1, 2026

Code Review Summary

Status: No New Issues Found | Recommendation: Address existing comments, then merge

Overview

This PR fixes the refinery rig assignment bug in multi-rig towns. The core changes are well-structured:

  1. Refinery is no longer a town-wide singletongetOrCreateAgent now treats refinery as a per-rig agent (like polecat), ensuring it's dispatched into the correct repository.
  2. MR bead stores rig_id and source_agent_idsubmitToReviewQueue now persists the rig and originating agent in the bead, so processReviewQueue resolves the correct rig instead of blindly picking rigList[0].
  3. Refinery hooks to the MR bead (not the source bead) — preserves the polecat's assignee on the source bead.
  4. Source bead closed by polecat's agentDone — the refinery no longer double-closes it.
  5. No-op guard in updateBeadStatus — prevents redundant status_changed events when a bead is already in the target status.
  6. DAG link via bead_dependencies — MR bead → source bead relationship is now queryable.
  7. Frontend BeadPanel shows related beads — uses the flat bead list to compute DAG neighborhood (children, source work, reviews).

All 6 existing inline comments from the previous review round remain relevant. No additional issues were found in this review pass.

Other Observations (not in diff)
File Line Observation
cloudflare-gastown/src/dos/town/review-queue.ts 234-235 completeReviewWithResult still calls closeBead on the source bead for merged status. With this PR the source bead is already closed by the polecat's agentDone path. This is now safe due to the no-op guard in updateBeadStatus, but the call is effectively dead code on the happy path. Consider removing it or adding a comment explaining it's a safety net.
Files Reviewed (8 files)
  • cloudflare-gastown/src/dos/Town.do.ts — rig resolution from entry, hook to MR bead
  • cloudflare-gastown/src/dos/town/agents.ts — refinery no longer singleton, parameterized role query
  • cloudflare-gastown/src/dos/town/beads.ts — no-op guard in updateBeadStatus
  • cloudflare-gastown/src/dos/town/review-queue.tsrig_id/source_agent_id in metadata, source bead closed by polecat, completeReviewFromMRBead rewrite
  • cloudflare-gastown/src/handlers/rig-review-queue.handler.ts — inject rig_id from route params
  • cloudflare-gastown/src/types.tsrig_id added to ReviewQueueEntry and ReviewQueueInput
  • cloudflare-gastown/test/integration/rig-alarm.test.ts — test updated with rig_id
  • cloudflare-gastown/test/integration/rig-do.test.ts — tests updated with rig_id
  • src/components/gastown/drawer-panels/BeadPanel.tsx — related beads DAG UI

jrf0110 added 3 commits March 1, 2026 08:09
Four compounding bugs caused the refinery agent to be dispatched into
the wrong rig's repository in multi-rig towns:

1. Refinery was a town-wide singleton — getOrCreateAgent reused the same
   refinery across rigs. Now refinery is per-rig like polecats, with idle
   agent reuse scoped by rig_id.

2. processReviewQueue hardcoded rigList[0] to resolve the rig. Now reads
   rig_id from the merge_request bead itself.

3. merge_request beads were created with rig_id = null. Now
   submitToReviewQueue populates rig_id from the input.

4. ReviewQueueInput/ReviewQueueEntry types lacked rig_id. Added to both.
Three issues with how merge_request beads and the refinery interact:

1. processReviewQueue hooked the refinery to the SOURCE bead instead of
   the MR bead. This overwrote the source bead's assignee (losing track
   of which polecat worked on it). Now hooks the MR bead directly.

2. MR bead was created with assignee_agent_bead_id set to the polecat.
   Now left null — the refinery claims it via hookBead, matching upstream
   gastown behavior. Source agent stored in metadata.source_agent_id.

3. agentDone (polecat path) did not close the source bead after submitting
   to the review queue. Now calls closeBead so the source bead is closed
   with its original polecat assignee preserved, matching upstream gt done.

Also updated the refinery's agentDone path: since the refinery now hooks
the MR bead directly, completeReviewFromMRBead reads the source_bead_id
from the MR's metadata instead of searching by source_bead_id.
Add a Related Beads section to BeadPanel that shows the bead's DAG
neighborhood — child beads, source work (for MR beads), and review
beads (for source work beads). Each entry is clickable, pushing a new
bead drawer onto the stack.

The DAG is computed client-side from the existing listBeads data — no
new API endpoints needed. The metadata.source_bead_id and
metadata.source_agent_id fields (added in the MR lifecycle fix) provide
the MR-to-source link.

Also adds a bead_dependencies 'tracks' row when creating MR beads in
submitToReviewQueue, formally linking the MR to its source bead in the
dependency table for future query use.
@jrf0110 jrf0110 force-pushed the 657-refinery-wrong-rig branch from 43773a0 to b7ade5c Compare March 1, 2026 14:10
- Log warning when agent.rig_id is null in agentDone
- Fix misleading docstring on completeReviewFromMRBead (no longer closes
  source bead — polecat's agentDone handles that)
- Add null guard for getBead in completeReviewFromMRBead
- Remove unused ArrowUpRight import in BeadPanel.tsx
- Add no-op early return in updateBeadStatus when status unchanged,
  preventing redundant status_changed events from double-close
@jrf0110 jrf0110 merged commit d9b2231 into main Mar 1, 2026
12 checks passed
@jrf0110 jrf0110 deleted the 657-refinery-wrong-rig branch March 1, 2026 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Refinery agent dispatched to wrong rig in multi-rig towns

2 participants