From 7fe824781aeaa6ea15589da25d9507482e189ce8 Mon Sep 17 00:00:00 2001 From: Nicolas Suzor Date: Mon, 12 Jan 2026 19:20:32 +1000 Subject: [PATCH] fix: use route prefix when creating issues in rigs (#1028) * fix(create): Use prefix from routes.jsonl when creating issues with --rig When using `bd create --rig `, the prefix from routes.jsonl was being discarded. This caused issues to be created with the target database's default prefix instead of the route's prefix. This is particularly problematic when using the redirect mechanism to share a single database across multiple rigs - the redirect correctly routes to the shared database, but the prefix was not being applied. The fix: 1. Capture the prefix from routing.ResolveBeadsDirForRig() 2. Temporarily override the target database's issue_prefix config 3. Restore the original prefix after issue creation Example scenario that now works: - routes.jsonl: {"prefix": "aops-", "path": "src/academicOps"} - src/academicOps/.beads/redirect points to ~/writing/.beads - `bd create --rig aops "Test"` now creates aops-xxx instead of ns-xxx Co-Authored-By: Claude * fix(create): pass prefix via struct field instead of mutating config The previous approach temporarily mutated the database's issue_prefix config during cross-rig issue creation, then restored it afterward. This was fragile in multi-user scenarios where concurrent operations could see the wrong prefix. New approach: - Add PrefixOverride field to types.Issue - CreateIssue checks PrefixOverride first, uses it if set - createInRig sets issue.PrefixOverride instead of mutating config This passes state as a parameter rather than mutating shared state, making it safe for concurrent multi-user access. Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude --- cmd/bd/create.go | 13 +++++++++++-- internal/storage/sqlite/queries.go | 10 +++++++--- internal/types/types.go | 5 +++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/cmd/bd/create.go b/cmd/bd/create.go index f7bb8cd0..41228b6b 100644 --- a/cmd/bd/create.go +++ b/cmd/bd/create.go @@ -738,8 +738,8 @@ func createInRig(cmd *cobra.Command, rigName, title, description, issueType stri FatalError("cannot use --rig: %v", err) } - // Resolve the target rig's beads directory - targetBeadsDir, _, err := routing.ResolveBeadsDirForRig(rigName, townBeadsDir) + // Resolve the target rig's beads directory and prefix + targetBeadsDir, targetPrefix, err := routing.ResolveBeadsDirForRig(rigName, townBeadsDir) if err != nil { FatalError("%v", err) } @@ -756,6 +756,13 @@ func createInRig(cmd *cobra.Command, rigName, title, description, issueType stri } }() + // Prepare prefix override from routes.jsonl for cross-rig creation + // Strip trailing hyphen - database stores prefix without it (e.g., "aops" not "aops-") + var prefixOverride string + if targetPrefix != "" { + prefixOverride = strings.TrimSuffix(targetPrefix, "-") + } + var externalRefPtr *string if externalRef != "" { externalRefPtr = &externalRef @@ -824,6 +831,8 @@ func createInRig(cmd *cobra.Command, rigName, title, description, issueType stri // Time scheduling fields (bd-xwvo fix) DueAt: dueAt, DeferUntil: deferUntil, + // Cross-rig routing: use route prefix instead of database config + PrefixOverride: prefixOverride, } if err := targetStore.CreateIssue(ctx, issue, actor); err != nil { diff --git a/internal/storage/sqlite/queries.go b/internal/storage/sqlite/queries.go index ba913dff..0dda0082 100644 --- a/internal/storage/sqlite/queries.go +++ b/internal/storage/sqlite/queries.go @@ -167,10 +167,14 @@ func (s *SQLiteStorage) CreateIssue(ctx context.Context, issue *types.Issue, act return fmt.Errorf("failed to get config: %w", err) } - // Use IDPrefix override if set, combined with config prefix - // e.g., configPrefix="bd" + IDPrefix="wisp" → "bd-wisp" + // Determine prefix for ID generation and validation: + // 1. PrefixOverride completely replaces config prefix (for cross-rig creation) + // 2. IDPrefix appends to config prefix (e.g., "bd" + "wisp" → "bd-wisp") + // 3. Otherwise use config prefix as-is prefix := configPrefix - if issue.IDPrefix != "" { + if issue.PrefixOverride != "" { + prefix = issue.PrefixOverride + } else if issue.IDPrefix != "" { prefix = configPrefix + "-" + issue.IDPrefix } diff --git a/internal/types/types.go b/internal/types/types.go index cb1ffd33..8e8b8e9c 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -56,8 +56,9 @@ type Issue struct { OriginalSize int `json:"original_size,omitempty"` // ===== Internal Routing (not exported to JSONL) ===== - SourceRepo string `json:"-"` // Which repo owns this issue (multi-repo support) - IDPrefix string `json:"-"` // Override prefix for ID generation + SourceRepo string `json:"-"` // Which repo owns this issue (multi-repo support) + IDPrefix string `json:"-"` // Override prefix for ID generation (appends to config prefix) + PrefixOverride string `json:"-"` // Completely replace config prefix (for cross-rig creation) // ===== Relational Data (populated for export/import) ===== Labels []string `json:"labels,omitempty"`