diff --git a/meshterm/ui/contacts_screen.py b/meshterm/ui/contacts_screen.py index a11b673..1c41ed6 100644 --- a/meshterm/ui/contacts_screen.py +++ b/meshterm/ui/contacts_screen.py @@ -11,7 +11,7 @@ and backing out of that page returns to the list right where it stood. The one-s :func:`~meshterm.ui.widgets.contacts_table`; only the menu gets the live list. Below the contacts sits one maintenance action — **Purge stale contacts** — that sweeps out -the contacts a device has accumulated but no longer hears. It offers an age ladder (a week up +the contacts a device has accumulated but no longer hears. It offers an age ladder (a day up to a year, plus a *never heard* bucket), each rung showing a live count of how many contacts it would remove, so the impact is visible before anything is chosen; the pick is then gated behind a typed ``delete`` confirm. A purge deletes the contacts from the device's table and @@ -55,6 +55,7 @@ _DAY = 86400 #: bucket, so an age rung never quietly deletes a freshly-added contact that hasn't had time #: to advert yet. PURGE_RUNGS: tuple[tuple[str, int], ...] = ( + ("Older than 1 day", _DAY), ("Older than 1 week", 7 * _DAY), ("Older than 1 month", 30 * _DAY), ("Older than 3 months", 90 * _DAY), diff --git a/tests/test_device_config.py b/tests/test_device_config.py index 624687b..733441d 100644 --- a/tests/test_device_config.py +++ b/tests/test_device_config.py @@ -327,11 +327,16 @@ def test_purge_buckets_split_stale_from_never_heard() -> None: now = utcnow() fresh = Contact(name="Fresh", public_key="aa" * 32, last_seen=now - timedelta(hours=1)) + quiet = Contact(name="Quiet", public_key="ee" * 32, last_seen=now - timedelta(days=3)) old = Contact(name="Old", public_key="bb" * 32, last_seen=now - timedelta(days=45)) ancient = Contact(name="Ancient", public_key="cc" * 32, last_seen=now - timedelta(days=400)) unheard = Contact(name="Unheard", public_key="dd" * 32) # no last_seen - contacts = [fresh, old, ancient, unheard] + contacts = [fresh, quiet, old, ancient, unheard] + # A day catches everything heard but not heard *today* — the tightest rung the ladder + # offers (JP, 2026-08-10), so a contact three days quiet is swept where the week rung + # would still have kept it. + assert {c.name for c in stale_past(contacts, _DAY)} == {"Quiet", "Old", "Ancient"} # A week catches the two aged ones but not the fresh — and never the never-heard one. week = {c.name for c in stale_past(contacts, 7 * _DAY)} assert week == {"Old", "Ancient"}