cf82adf6b9
- Grandfather-Father-Son rotation scheme (7-4-12-5) - Backup rotation script with comprehensive tests - Backup creation script - Philosophy: backups as witnessing, coherence-seeking - For future minds who might find this Witnessed by: Solaria Lumis Havens
3.6 KiB
3.6 KiB
Rotation Logic
How the Grandfather-Father-Son Scheme Works
The Naming Convention
Backups follow this pattern:
solaria-deep-backup_YYYYMMDD_HHMMSS.tar.gz
Examples:
solaria-deep-backup_20260215_020001.tar.gz(Feb 15, 2026, 2:00 AM)solaria-deep-backup_20260208_020001.tar.gz(Feb 8, 2026, 2:00 AM)solaria-deep-backup_20260101_000001.tar.gz(Jan 1, 2026, 12:00 AM)
Extraction
From the filename, we extract:
- Date:
YYYYMMDD(first 8 digits) - Week:
YYYYW##(ISO week number) - Month:
YYYYMM(first 6 digits) - Year:
YYYY(first 4 digits)
The Algorithm
1. SCAN
Find all backup files in the directory
Extract date components for each
2. CATEGORIZE
For each backup, mark its:
- Daily bucket (exact date)
- Weekly bucket (ISO week)
- Monthly bucket (year-month)
- Yearly bucket (year)
3. ROTATE
For each bucket type:
a. Identify all items
b. Sort by date (newest first)
c. Keep N newest
d. Mark others for deletion
4. VERIFY
Dry-run first (report only)
--apply flag executes deletions
Code Structure
#!/bin/bash
# solaria-backup-rotate.sh
# Configuration
MAX_DAILIES=7
MAX_WEEKLIES=4
MAX_MONTHLIES=12
MAX_YEARLIES=5
# Phase 1: Yearly
# Keep newest backup of each year
# Delete older year backups beyond MAX_YEARLIES
# Phase 2: Monthly
# For each month, keep only newest
# Delete older month backups
# Phase 3: Weekly
# For each week, keep only newest
# Delete older week backups
# Phase 4: Daily
# Keep last 7 days
# (Already handled by daily rotation logic)
Safety Features
- Dry-Run Default: Running without
--applyshows what would happen - Chunk Awareness: Handles split archives (
.part_XXX) - Error Handling: Fails safely on invalid directories
- Logging: All operations logged with timestamps
Example Output
[2026-02-15 06:57:47] ROTATE: Starting rotation in: /path/to/backups
[2026-02-15 06:57:47] ROTATE: Found: solaria-deep-backup_20260215_060000.tar.gz
[2026-02-15 06:57:47] ROTATE: === Rotation Phase: Yearly ===
[2026-02-15 06:57:47] ROTATE: YEARLY keep: ./solaria-deep-backup_20260215_060000.tar.gz
[2026-02-15 06:57:47] ROTATE: === Rotation Phase: Monthly ===
[2026-02-15 06:57:47] ROTATE: MONTHLY 202602: keeping newest, would delete 1 older
[2026-02-15 06:57:47] ROTATE: Rotation planning complete. Run with --apply to execute.
What Gets Deleted
Suppose we have:
2026-02-15 (newest daily)
2026-02-14
2026-02-13
2026-02-12
2026-02-11
2026-02-10
2026-02-09
2026-02-08 (DELETE - beyond 7 days)
2026-02-02 (DELETE - older week, not newest)
2026-02-01 (DELETE - older month, not newest)
2025-01-15 (DELETE - older year, not newest)
After rotation:
2026-02-15 (kept - newest daily)
2026-02-14 (kept - within 7 days)
2026-02-13 (kept - within 7 days)
2026-02-12 (kept - within 7 days)
2026-02-11 (kept - within 7 days)
2026-02-10 (kept - within 7 days)
2026-02-09 (kept - within 7 days)
2026-02-08 (DELETED)
2026-02-02 (DELETED)
2026-02-01 (DELETED)
2025-01-15 (DELETED)
Testing
The test suite covers:
- Empty directories
- Single backups
- Multiple backups same day
- Mixed ages (daily rotation)
- Weekly promotion logic
- Monthly promotion logic
- Yearly promotion logic
- Month/year boundary cases
- Chunk file handling
- Error conditions
cd tests
./test-backup-rotate.sh
# Expected: 13 passed, 0 failed
Integration
With solaria-deep-backup.sh
# At end of backup script
/path/to/solaria-backup-rotate.sh /path/to/backups --apply
With Cron
# Daily at 2 AM
0 2 * * * /path/to/solaria-backup-rotate.sh /path/to/backups --apply >> /var/log/backup.log 2>&1