Merge polecat/Ace: protect pinned from cleanup/compact
This commit is contained in:
@@ -126,6 +126,22 @@ SEE ALSO:
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Filter out pinned issues - they are protected from cleanup (bd-b2k)
|
||||
pinnedCount := 0
|
||||
filteredIssues := make([]*types.Issue, 0, len(closedIssues))
|
||||
for _, issue := range closedIssues {
|
||||
if issue.Pinned {
|
||||
pinnedCount++
|
||||
continue
|
||||
}
|
||||
filteredIssues = append(filteredIssues, issue)
|
||||
}
|
||||
closedIssues = filteredIssues
|
||||
|
||||
if pinnedCount > 0 && !jsonOutput {
|
||||
fmt.Printf("Skipping %d pinned issue(s) (protected from cleanup)\n", pinnedCount)
|
||||
}
|
||||
|
||||
if len(closedIssues) == 0 {
|
||||
if jsonOutput {
|
||||
result := map[string]interface{}{
|
||||
|
||||
@@ -47,7 +47,7 @@ func (s *SQLiteStorage) GetTier1Candidates(ctx context.Context) ([]*CompactionCa
|
||||
-- Find all issues that depend on (are blocked by) other issues
|
||||
dependent_tree AS (
|
||||
-- Base case: direct dependents
|
||||
SELECT
|
||||
SELECT
|
||||
d.depends_on_id as issue_id,
|
||||
i.id as dependent_id,
|
||||
i.status as dependent_status,
|
||||
@@ -55,11 +55,11 @@ func (s *SQLiteStorage) GetTier1Candidates(ctx context.Context) ([]*CompactionCa
|
||||
FROM dependencies d
|
||||
JOIN issues i ON d.issue_id = i.id
|
||||
WHERE d.type = 'blocks'
|
||||
|
||||
|
||||
UNION ALL
|
||||
|
||||
|
||||
-- Recursive case: parent-child relationships
|
||||
SELECT
|
||||
SELECT
|
||||
dt.issue_id,
|
||||
i.id as dependent_id,
|
||||
i.status as dependent_status,
|
||||
@@ -70,20 +70,21 @@ func (s *SQLiteStorage) GetTier1Candidates(ctx context.Context) ([]*CompactionCa
|
||||
WHERE d.type = 'parent-child'
|
||||
AND dt.depth < ?
|
||||
)
|
||||
SELECT
|
||||
SELECT
|
||||
i.id,
|
||||
i.closed_at,
|
||||
COALESCE(i.original_size, LENGTH(i.description) + LENGTH(i.design) + LENGTH(i.notes) + LENGTH(i.acceptance_criteria)) as original_size,
|
||||
0 as estimated_size,
|
||||
COUNT(DISTINCT dt.dependent_id) as dependent_count
|
||||
FROM issues i
|
||||
LEFT JOIN dependent_tree dt ON i.id = dt.issue_id
|
||||
LEFT JOIN dependent_tree dt ON i.id = dt.issue_id
|
||||
AND dt.dependent_status IN ('open', 'in_progress', 'blocked')
|
||||
AND dt.depth <= ?
|
||||
WHERE i.status = 'closed'
|
||||
AND i.closed_at IS NOT NULL
|
||||
AND i.closed_at <= datetime('now', '-' || CAST(? AS INTEGER) || ' days')
|
||||
AND COALESCE(i.compaction_level, 0) = 0
|
||||
AND COALESCE(i.pinned, 0) = 0 -- Exclude pinned issues (bd-b2k)
|
||||
AND dt.dependent_id IS NULL -- No open dependents
|
||||
GROUP BY i.id
|
||||
ORDER BY i.closed_at ASC
|
||||
@@ -142,7 +143,7 @@ func (s *SQLiteStorage) GetTier2Candidates(ctx context.Context) ([]*CompactionCa
|
||||
FROM events
|
||||
GROUP BY issue_id
|
||||
)
|
||||
SELECT
|
||||
SELECT
|
||||
i.id,
|
||||
i.closed_at,
|
||||
i.original_size,
|
||||
@@ -154,6 +155,7 @@ func (s *SQLiteStorage) GetTier2Candidates(ctx context.Context) ([]*CompactionCa
|
||||
AND i.closed_at IS NOT NULL
|
||||
AND i.closed_at <= datetime('now', '-' || CAST(? AS INTEGER) || ' days')
|
||||
AND i.compaction_level = 1
|
||||
AND COALESCE(i.pinned, 0) = 0 -- Exclude pinned issues (bd-b2k)
|
||||
AND COALESCE(ec.event_count, 0) >= CAST(? AS INTEGER)
|
||||
AND NOT EXISTS (
|
||||
-- Check for open dependents
|
||||
@@ -196,13 +198,14 @@ func (s *SQLiteStorage) CheckEligibility(ctx context.Context, issueID string, ti
|
||||
var status string
|
||||
var closedAt sql.NullTime
|
||||
var compactionLevel int
|
||||
|
||||
var pinned int
|
||||
|
||||
err := s.db.QueryRowContext(ctx, `
|
||||
SELECT status, closed_at, COALESCE(compaction_level, 0)
|
||||
SELECT status, closed_at, COALESCE(compaction_level, 0), COALESCE(pinned, 0)
|
||||
FROM issues
|
||||
WHERE id = ?
|
||||
`, issueID).Scan(&status, &closedAt, &compactionLevel)
|
||||
|
||||
`, issueID).Scan(&status, &closedAt, &compactionLevel, &pinned)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
return false, "issue not found", nil
|
||||
}
|
||||
@@ -214,11 +217,16 @@ func (s *SQLiteStorage) CheckEligibility(ctx context.Context, issueID string, ti
|
||||
if status != "closed" {
|
||||
return false, "issue is not closed", nil
|
||||
}
|
||||
|
||||
|
||||
if !closedAt.Valid {
|
||||
return false, "issue has no closed_at timestamp", nil
|
||||
}
|
||||
|
||||
// Pinned issues are protected from compaction (bd-b2k)
|
||||
if pinned != 0 {
|
||||
return false, "issue is pinned (protected from compaction)", nil
|
||||
}
|
||||
|
||||
switch tier {
|
||||
case 1:
|
||||
if compactionLevel != 0 {
|
||||
|
||||
@@ -36,6 +36,11 @@ func insertIssue(ctx context.Context, conn *sql.Conn, issue *types.Issue) error
|
||||
pinned = 1
|
||||
}
|
||||
|
||||
pinned := 0
|
||||
if issue.Pinned {
|
||||
pinned = 1
|
||||
}
|
||||
|
||||
_, err := conn.ExecContext(ctx, `
|
||||
INSERT OR IGNORE INTO issues (
|
||||
id, content_hash, title, description, design, acceptance_criteria, notes,
|
||||
@@ -95,6 +100,11 @@ func insertIssues(ctx context.Context, conn *sql.Conn, issues []*types.Issue) er
|
||||
pinned = 1
|
||||
}
|
||||
|
||||
pinned := 0
|
||||
if issue.Pinned {
|
||||
pinned = 1
|
||||
}
|
||||
|
||||
_, err = stmt.ExecContext(ctx,
|
||||
issue.ID, issue.ContentHash, issue.Title, issue.Description, issue.Design,
|
||||
issue.AcceptanceCriteria, issue.Notes, issue.Status,
|
||||
|
||||
Reference in New Issue
Block a user