issues/completed/7-005-select-most-recent-archive-per-type.md
Issue 7-005: Select Most Recent Archive Per Type
Priority: High
Phase: 7 (Stabilization and Polish)
Status: Completed
Created: 2026-01-30
Completed: 2026-01-30
Current Behavior
The scripts/zip-extractor.lua finds all ZIP archives in input/, categorizes them by type (fediverse, messages, notes), and extracts all of them. When multiple archives of the same type exist:
- All are extracted sequentially
- The
extraction_pathsdictionary overwrites previous entries:summary.extraction_paths[archive.type] = extraction_path - The last archive processed (by filesystem order) is used, not the most recent by date
- No warning is shown about which archives were skipped
Example: If input/ contains:
similar-different.zip(messages, older)new-messages-export.zip(messages, newer)
The extractor might use similar-different.zip simply because it was found first, ignoring the newer export.
Intended Behavior
- Group archives by type: Collect all archives into buckets (fediverse, messages, notes)
- Sort by modification time: Within each bucket, sort by file mtime (newest first)
- Select most recent: Only extract the newest archive from each type
- Warn about skipped archives: Print a yellow warning (full yellow text, not just icon) showing the full path of each older, unused archive
Example output:
🔍 Scanning for ZIP archives in: ./input
📦 Found messages archive: new-messages-export (2026-01-28)
📦 Found messages archive: similar-different (2025-12-14)
📦 Found fediverse archive: most-recent-29 (2026-01-15)
📊 Archive selection:
messages: new-messages-export (selected)
⚠️ Skipped older: ./input/similar-different.zip (2025-12-14)
fediverse: most-recent-29 (selected)
Suggested Implementation Steps
Step 1: Add modification time detection
-- {{{ local function get_file_mtime
local function get_file_mtime(file_path)
local stat_cmd = string.format("stat -c %%Y '%s' 2>/dev/null", file_path)
local handle = io.popen(stat_cmd)
local result = handle:read("*a")
handle:close()
if result and result ~= "" then
return tonumber(result:gsub("%s+", ""))
end
return 0
end
-- }}}
Step 2: Store mtime in archive info
-- In detect_archives():
table.insert(archives, {
path = file,
type = archive_type,
basename = basename,
mtime = get_file_mtime(file), -- Add this
mtime_date = os.date("%Y-%m-%d", get_file_mtime(file)) -- Human-readable
})
Step 3: Create selection function
-- {{{ local function select_archives_by_type
-- Groups archives by type, sorts by mtime (newest first), returns selected + skipped
local function select_archives_by_type(archives)
local by_type = {}
-- Group by type
for _, archive in ipairs(archives) do
if not by_type[archive.type] then
by_type[archive.type] = {}
end
table.insert(by_type[archive.type], archive)
end
local selected = {}
local skipped = {}
-- Sort each group by mtime (descending) and pick newest
for archive_type, group in pairs(by_type) do
table.sort(group, function(a, b) return a.mtime > b.mtime end)
-- First (newest) is selected
table.insert(selected, group[1])
-- Rest are skipped
for i = 2, #group do
table.insert(skipped, group[i])
end
end
return selected, skipped
end
-- }}}
Step 4: Update main flow
-- After detect_archives():
local all_archives = detect_archives(DIR .. "/input")
local selected, skipped = select_archives_by_type(all_archives)
-- Warn about skipped archives (full yellow text)
if #skipped > 0 then
for _, archive in ipairs(skipped) do
print(COLOR_YELLOW .. "⚠️ Skipped older: " .. relative_path(archive.path) ..
" (" .. archive.mtime_date .. ")" .. COLOR_RESET)
end
end
-- Only extract selected archives
local summary = create_extraction_summary(selected, TEMP_DIR)
Success Criteria
- [x] Archives grouped by type before selection
- [x] Most recent archive (by mtime) selected per type
- [x] Older archives in same type category show yellow warning
- [x] Warning includes full path and date
- [x] Only selected archives are extracted
- [x] Extraction summary reflects actual selection
Related Files
scripts/zip-extractor.lua:47-61-get_file_mtime()functionscripts/zip-extractor.lua:98-137-detect_archives()function with mtimescripts/zip-extractor.lua:139-170-select_archives_by_type()functionscripts/zip-extractor.lua:278-303- Main execution with selection logicissues/7-progress.md- Phase 7 progress tracking
Notes
- The yellow warning text (not just icon) helps distinguish "attention required" from "info"
- This follows the semantic color scheme from 7-003: yellow = attention
- Consider adding a
--force-allflag to extract all archives if ever needed
Implementation Notes (2026-01-30)
Lua gsub gotcha: The string.gsub() function returns two values (string, count). When passed directly to tonumber(), the count became the "base" argument. Fixed by wrapping in parentheses: (result:gsub(...)).
Example output with multiple archives of same type:
🔍 Scanning for ZIP archives in: ./input
📦 Found messages archive: new-export (2026-01-28)
📦 Found messages archive: similar-different (2025-12-13)
📦 Found fediverse archive: most-recent-29 (2025-12-10)
📊 Archive selection:
Total found: 3, Selected: 2, Skipped: 1
⚠️ Skipped older: ./input/similar-different.zip (2025-12-13)