feat(deletions): add pruning and git history fallback
Implements two P1 tasks for the deletions manifest epic: bd-v2x: Add deletions pruning to bd compact - PruneDeletions function removes records older than retention period - Default retention: 7 days (configurable via metadata.json) - CLI --retention flag for override - Atomic file rewrite prevents corruption - Called automatically during all compact operations bd-pnm: Add git history fallback for pruned deletions - Catches deletions where manifest entry was pruned - Uses git log -S to search for ID in JSONL history - Batches multiple IDs for efficiency (git -G regex) - Self-healing: backfills manifest on hit - Conservative: keeps issue if git check fails (shallow clone) Tests added for both features with edge cases covered. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,9 @@ type Config struct {
|
||||
Database string `json:"database"`
|
||||
JSONLExport string `json:"jsonl_export,omitempty"`
|
||||
LastBdVersion string `json:"last_bd_version,omitempty"`
|
||||
|
||||
// Deletions configuration
|
||||
DeletionsRetentionDays int `json:"deletions_retention_days,omitempty"` // 0 means use default (7 days)
|
||||
}
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
@@ -94,3 +97,14 @@ func (c *Config) JSONLPath(beadsDir string) string {
|
||||
}
|
||||
return filepath.Join(beadsDir, c.JSONLExport)
|
||||
}
|
||||
|
||||
// DefaultDeletionsRetentionDays is the default retention period for deletion records.
|
||||
const DefaultDeletionsRetentionDays = 7
|
||||
|
||||
// GetDeletionsRetentionDays returns the configured retention days, or the default if not set.
|
||||
func (c *Config) GetDeletionsRetentionDays() int {
|
||||
if c.DeletionsRetentionDays <= 0 {
|
||||
return DefaultDeletionsRetentionDays
|
||||
}
|
||||
return c.DeletionsRetentionDays
|
||||
}
|
||||
|
||||
@@ -114,8 +114,46 @@ func TestConfigPath(t *testing.T) {
|
||||
beadsDir := "/home/user/project/.beads"
|
||||
got := ConfigPath(beadsDir)
|
||||
want := filepath.Join(beadsDir, "metadata.json")
|
||||
|
||||
|
||||
if got != want {
|
||||
t.Errorf("ConfigPath() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDeletionsRetentionDays(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg *Config
|
||||
want int
|
||||
}{
|
||||
{
|
||||
name: "zero uses default",
|
||||
cfg: &Config{DeletionsRetentionDays: 0},
|
||||
want: DefaultDeletionsRetentionDays,
|
||||
},
|
||||
{
|
||||
name: "negative uses default",
|
||||
cfg: &Config{DeletionsRetentionDays: -5},
|
||||
want: DefaultDeletionsRetentionDays,
|
||||
},
|
||||
{
|
||||
name: "custom value",
|
||||
cfg: &Config{DeletionsRetentionDays: 14},
|
||||
want: 14,
|
||||
},
|
||||
{
|
||||
name: "minimum value 1",
|
||||
cfg: &Config{DeletionsRetentionDays: 1},
|
||||
want: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.cfg.GetDeletionsRetentionDays()
|
||||
if got != tt.want {
|
||||
t.Errorf("GetDeletionsRetentionDays() = %d, want %d", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user