feat(slot): Add merge-slot gate for serialized conflict resolution

Adds a new slot bead type and merge-slot commands for serializing
conflict resolution in the merge queue. This prevents "monkey knife
fights" where multiple polecats race to resolve conflicts.

- Add TypeSlot to bead types
- Add Holder field to Issue struct
- Add bd merge-slot create/check/acquire/release commands
- Add Holder field to UpdateArgs in RPC protocol

(gt-4u49x)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
furiosa
2026-01-02 18:03:27 -08:00
committed by Steve Yegge
parent b8f9dabcb5
commit 0c7dcee3ac
4 changed files with 552 additions and 1 deletions

View File

@@ -164,6 +164,8 @@ type UpdateArgs struct {
// Gate fields
AwaitID *string `json:"await_id,omitempty"` // Condition identifier for gates (run ID, PR number, etc.)
Waiters []string `json:"waiters,omitempty"` // Mail addresses to notify when gate clears
// Slot fields
Holder *string `json:"holder,omitempty"` // Who currently holds the slot (for type=slot beads)
}
// CloseArgs represents arguments for the close operation

View File

@@ -142,6 +142,10 @@ func updatesFromArgs(a UpdateArgs) map[string]interface{} {
if len(a.Waiters) > 0 {
u["waiters"] = a.Waiters
}
// Slot fields
if a.Holder != nil {
u["holder"] = *a.Holder
}
return u
}

View File

@@ -91,6 +91,9 @@ type Issue struct {
Timeout time.Duration `json:"timeout,omitempty"` // Max wait time before escalation
Waiters []string `json:"waiters,omitempty"` // Mail addresses to notify when gate clears
// ===== Slot Fields (exclusive access primitives) =====
Holder string `json:"holder,omitempty"` // Who currently holds the slot (empty = available)
// ===== Source Tracing Fields (formula cooking origin) =====
SourceFormula string `json:"source_formula,omitempty"` // Formula name where step was defined
SourceLocation string `json:"source_location,omitempty"` // Path: "steps[0]", "advice[0].after"
@@ -163,6 +166,9 @@ func (i *Issue) ComputeContentHash() string {
w.str(waiter)
}
// Slot fields for exclusive access
w.str(i.Holder)
// Agent identity fields
w.str(i.HookBead)
w.str(i.RoleBead)
@@ -413,12 +419,13 @@ const (
TypeRole IssueType = "role" // Agent role definition
TypeConvoy IssueType = "convoy" // Cross-project tracking with reactive completion
TypeEvent IssueType = "event" // Operational state change record
TypeSlot IssueType = "slot" // Exclusive access slot (merge-slot gate)
)
// IsValid checks if the issue type value is valid
func (t IssueType) IsValid() bool {
switch t {
case TypeBug, TypeFeature, TypeTask, TypeEpic, TypeChore, TypeMessage, TypeMergeRequest, TypeMolecule, TypeGate, TypeAgent, TypeRole, TypeConvoy, TypeEvent:
case TypeBug, TypeFeature, TypeTask, TypeEpic, TypeChore, TypeMessage, TypeMergeRequest, TypeMolecule, TypeGate, TypeAgent, TypeRole, TypeConvoy, TypeEvent, TypeSlot:
return true
}
return false