feat(gate): add bd gate discover for gh:run await_id auto-discovery (bd-z6kw)

Implements automatic discovery of GitHub workflow run IDs for gates
awaiting CI/CD completion. This enables the Refinery patrol to
auto-populate await_id for gh:run gates that were created without one.

Changes:
- Add `bd gate discover` command that:
  - Finds open gh:run gates without await_id
  - Queries recent GitHub workflow runs via gh CLI
  - Matches runs to gates using heuristics (branch, commit, time)
  - Updates gates with discovered run IDs

- Add `--await-id` flag to `bd update` for manual setting
- Add AwaitID to UpdateArgs in RPC protocol
- Add await_id to allowedUpdateFields in storage layer

Matching heuristics (scored, highest match wins):
- Commit SHA match: +100 points
- Branch match: +50 points
- Time proximity (<5min: +30, <10min: +20, <30min: +10)
- In-progress/queued status: +5 points

Usage:
  bd gate discover           # Auto-discover for all matching gates
  bd gate discover --dry-run # Preview without updating
  bd gate discover --branch main --limit 10

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
onyx
2026-01-02 16:12:48 -08:00
committed by Steve Yegge
parent 2f96795f85
commit a89f47cdf2
5 changed files with 359 additions and 0 deletions

View File

@@ -134,6 +134,11 @@ create, update, show, or close operation).`,
}
updates["issue_type"] = issueType
}
// Gate fields (bd-z6kw)
if cmd.Flags().Changed("await-id") {
awaitID, _ := cmd.Flags().GetString("await-id")
updates["await_id"] = awaitID
}
// Time-based scheduling flags (GH#820)
if cmd.Flags().Changed("due") {
dueStr, _ := cmd.Flags().GetString("due")
@@ -264,6 +269,10 @@ create, update, show, or close operation).`,
if parent, ok := updates["parent"].(string); ok {
updateArgs.Parent = &parent
}
// Gate fields (bd-z6kw)
if awaitID, ok := updates["await_id"].(string); ok {
updateArgs.AwaitID = &awaitID
}
// Time-based scheduling (GH#820)
if dueAt, ok := updates["due_at"].(time.Time); ok {
s := dueAt.Format(time.RFC3339)
@@ -591,5 +600,7 @@ func init() {
// --defer="" Clear defer (show in bd ready immediately)
updateCmd.Flags().String("due", "", "Due date/time (empty to clear). Formats: +6h, +1d, +2w, tomorrow, next monday, 2025-01-15")
updateCmd.Flags().String("defer", "", "Defer until date (empty to clear). Issue hidden from bd ready until then")
// Gate fields (bd-z6kw)
updateCmd.Flags().String("await-id", "", "Set gate await_id (e.g., GitHub run ID for gh:run gates)")
rootCmd.AddCommand(updateCmd)
}