TaskStore.checkForChanges detects deletions by comparing the in-memory
taskCache against the tasks table. But archiveTask also DELETEs the row
from `tasks` (after copying to archive_db), so any TaskStore instance
polling the same DB sees the archived task vanish and emits
`task:deleted`. The activity-log listener records that as a deletion,
producing entries like "Task FN-NNNN deleted" for tasks that are alive
and well in the archive.
Reproduced live: 2048 task:deleted entries in a single ~1ms burst, all
of them present in archive.db. Two TaskStores (CLI/engine and dashboard
server) on the same DB → CLI archives, dashboard polls and false-flags.
Fix: in checkForChanges, batch-query the archive for all missing IDs.
For ids that exist in archived_tasks, emit `task:moved` (to:archived) —
matching what archiveTask emits in-process — so the activity log
records the correct event. For ids not in archive, emit task:deleted as
before (real deletion).
Adds ArchiveDatabase.filterArchived(ids) helper that returns the subset
in archived_tasks via a single SELECT IN query (chunked at 500 to stay
under SQLite's parameter limit).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>