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