fix(daemon): measure attention window from failure

Closes the gap #239 describes: §5.7's 30-day window was filtered on
grabbed_at, so a torrent stalling past the window before hard-failing
at import never surfaced in the needs-a-decision queue. grabs gains
failed_at (migration 0030, backfilled from grabbed_at for existing
failed rows), the import tick stamps it on hard fail, and every window
query in the daemon notifier and the attention endpoint reads it.
§5.7 now states the anchor explicitly. §6.2's pack backoff stays on
grabbed_at deliberately; noted on the issue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Miguel Palhas
2026-08-25 11:05:59 +01:00
parent 0a0c6359a4
commit 528aadf59c
15 changed files with 147 additions and 77 deletions
@@ -0,0 +1,8 @@
-- #239: §5.7's 30-day attention window runs from the failure, but only
-- grabbed_at existed, so a torrent that stalled past the window and then
-- hard-failed at import was born outside it. failed_at records the moment
-- the grab entered 'failed'. Existing failed rows get grabbed_at as the
-- best available approximation.
ALTER TABLE grabs ADD COLUMN failed_at TEXT;
UPDATE grabs SET failed_at = grabbed_at WHERE state = 'failed';
+4 -2
View File
@@ -18,11 +18,13 @@ use sqlx::{migrate::MigrateError, SqlitePool};
pub static MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!("./migrations");
/// §5.7: how long a failed grab keeps counting toward the needs-a-decision
/// queue, as a SQLite time modifier.
/// queue, as a SQLite time modifier. Measured from `failed_at` — the moment
/// the grab hard-failed, not the moment it was grabbed — so a torrent that
/// stalls past the window and then fails still counts (#239).
///
/// Nothing ever clears a `grabs` row, so without a bound the queue only grows
/// and the one season that wants attention sits behind the ones that do not.
/// Callers pair it with the `grabbed_at` format:
/// Callers pair it with the `failed_at` format:
/// `strftime('%Y-%m-%dT%H:%M:%fZ', 'now', ATTENTION_WINDOW)`.
pub const ATTENTION_WINDOW: &str = "-30 days";