feat: bd ready filters by external dep satisfaction (bd-zmmy)

GetReadyWork now lazily resolves external dependencies at query time:
- External refs (external:project:capability) checked against target DB
- Issues with unsatisfied external deps are filtered from ready list
- Satisfaction = closed issue with provides:<capability> label in target

Key changes:
- Remove FK constraint on depends_on_id to allow external refs
- Add migration 025 to drop FK and recreate views
- Filter external deps in GetReadyWork, not in blocked_issues_cache
- Add application-level validation for orphaned local deps
- Comprehensive tests for external dep resolution

🤖 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-21 23:41:44 -08:00
parent a9bfce7f6e
commit 1cfb23487b
9 changed files with 633 additions and 64 deletions

View File

@@ -217,6 +217,30 @@ func (s *SQLiteStorage) importJSONLFile(ctx context.Context, jsonlPath, sourceRe
)
}
// Check for orphaned local dependencies (non-external refs) (bd-zmmy)
// The FK constraint on depends_on_id was removed to allow external:* refs,
// so we need to validate local deps manually.
orphanRows, err := conn.QueryContext(ctx, `
SELECT d.issue_id, d.depends_on_id
FROM dependencies d
LEFT JOIN issues i ON d.depends_on_id = i.id
WHERE i.id IS NULL
AND d.depends_on_id NOT LIKE 'external:%'
`)
if err != nil {
return 0, fmt.Errorf("failed to check orphaned dependencies: %w", err)
}
defer orphanRows.Close()
if orphanRows.Next() {
var issueID, dependsOnID string
_ = orphanRows.Scan(&issueID, &dependsOnID)
return 0, fmt.Errorf(
"foreign key violation: issue %s depends on non-existent issue %s",
issueID, dependsOnID,
)
}
if err := tx.Commit(); err != nil {
return 0, fmt.Errorf("failed to commit transaction: %w", err)
}