fix(pin): add 'pinned' field to allowed update fields (gt-zr0a)

The 'bd pin' command was failing with "invalid field for update: pinned"
because the pinned field was missing from allowedUpdateFields.

Fixes:
- Add 'pinned' to allowedUpdateFields in queries.go
- Update importer to include pinned field in updates during import
- Add equalBool comparator for IssueDataChanged to detect pinned changes
- Fix stats query to count pinned=1 instead of status='pinned'
- Fix pinIndicator in list.go to check issue.Pinned instead of status

This unblocks gt mail --pinned functionality.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-20 19:57:16 -08:00
parent 1f3b43853d
commit 5d2daf2e1e
5 changed files with 20 additions and 3 deletions

View File

@@ -554,6 +554,8 @@ func upsertIssues(ctx context.Context, sqliteStore *sqlite.SQLiteStorage, issues
updates["acceptance_criteria"] = incoming.AcceptanceCriteria
updates["notes"] = incoming.Notes
updates["closed_at"] = incoming.ClosedAt
// Pinned field (bd-7h5)
updates["pinned"] = incoming.Pinned
if incoming.Assignee != "" {
updates["assignee"] = incoming.Assignee
@@ -647,6 +649,8 @@ func upsertIssues(ctx context.Context, sqliteStore *sqlite.SQLiteStorage, issues
updates["acceptance_criteria"] = incoming.AcceptanceCriteria
updates["notes"] = incoming.Notes
updates["closed_at"] = incoming.ClosedAt
// Pinned field (bd-7h5)
updates["pinned"] = incoming.Pinned
if incoming.Assignee != "" {
updates["assignee"] = incoming.Assignee

View File

@@ -112,6 +112,15 @@ func (fc *fieldComparator) equalPriority(existing int, newVal interface{}) bool
return ok && int64(existing) == newPriority
}
func (fc *fieldComparator) equalBool(existingVal bool, newVal interface{}) bool {
switch t := newVal.(type) {
case bool:
return existingVal == t
default:
return false
}
}
func (fc *fieldComparator) checkFieldChanged(key string, existing *types.Issue, newVal interface{}) bool {
switch key {
case "title":
@@ -134,6 +143,8 @@ func (fc *fieldComparator) checkFieldChanged(key string, existing *types.Issue,
return !fc.equalStr(existing.Assignee, newVal)
case "external_ref":
return !fc.equalPtrStr(existing.ExternalRef, newVal)
case "pinned":
return !fc.equalBool(existing.Pinned, newVal)
default:
return false
}

View File

@@ -121,7 +121,7 @@ func (s *SQLiteStorage) GetStatistics(ctx context.Context) (*types.Statistics, e
COALESCE(SUM(CASE WHEN status = 'closed' THEN 1 ELSE 0 END), 0) as closed,
COALESCE(SUM(CASE WHEN status = 'deferred' THEN 1 ELSE 0 END), 0) as deferred,
COALESCE(SUM(CASE WHEN status = 'tombstone' THEN 1 ELSE 0 END), 0) as tombstone,
COALESCE(SUM(CASE WHEN status = 'pinned' THEN 1 ELSE 0 END), 0) as pinned
COALESCE(SUM(CASE WHEN pinned = 1 THEN 1 ELSE 0 END), 0) as pinned
FROM issues
`).Scan(&stats.TotalIssues, &stats.OpenIssues, &stats.InProgressIssues, &stats.ClosedIssues, &stats.DeferredIssues, &stats.TombstoneIssues, &stats.PinnedIssues)
if err != nil {

View File

@@ -558,6 +558,8 @@ var allowedUpdateFields = map[string]bool{
// Messaging fields (bd-kwro)
"sender": true,
"ephemeral": true,
// Pinned field (bd-7h5)
"pinned": true,
// NOTE: replies_to, relates_to, duplicate_of, superseded_by removed per Decision 004
// Use AddDependency() to create graph edges instead
}