diff --git a/CHANGELOG.md b/CHANGELOG.md index 65407d84..446c1789 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ All notable changes to vouch are documented here. Format follows ## [Unreleased] +### Fixed +- `_meta.vouch_hot_memory` dropped `actionable` claims: the sidebar's live + set was `working` / `stable` / `contested`, so `kb.confirm` — which + promotes a working claim to `actionable` and bumps `last_confirmed_at` — + removed a claim from the recency sidebar at the moment it became the + freshest thing in the kb. the live set is now the complement of the + retired statuses, matching `vault_sync`. + ## [1.4.0] — 2026-07-17 ### Added diff --git a/src/vouch/hot_memory.py b/src/vouch/hot_memory.py index fea42ea1..8d8014e6 100644 --- a/src/vouch/hot_memory.py +++ b/src/vouch/hot_memory.py @@ -231,8 +231,20 @@ def _preview(text: str) -> str: return flat[: TEXT_PREVIEW_CHARS - 1] + "…" +# the live statuses — the complement of the retired set (superseded / archived +# / redacted). actionable belongs here: kb.confirm promotes a working claim to +# actionable and bumps last_confirmed_at, so leaving it out dropped a claim +# from the sidebar at the moment it became freshest. +_ACTIVE_STATUSES = frozenset({ + ClaimStatus.WORKING, + ClaimStatus.ACTIONABLE, + ClaimStatus.STABLE, + ClaimStatus.CONTESTED, +}) + + def _is_active(status: ClaimStatus) -> bool: - return status in {ClaimStatus.WORKING, ClaimStatus.STABLE, ClaimStatus.CONTESTED} + return status in _ACTIVE_STATUSES def query_bias_for_page(page: Page) -> str: diff --git a/tests/test_hot_memory.py b/tests/test_hot_memory.py index 102444aa..c5b7b9f8 100644 --- a/tests/test_hot_memory.py +++ b/tests/test_hot_memory.py @@ -10,6 +10,7 @@ from vouch import hot_memory as hot_mod from vouch.capabilities import METHODS from vouch.jsonl_server import handle_request +from vouch.lifecycle import confirm from vouch.models import ClaimStatus, Entity, EntityType, Page, PageType from vouch.proposals import approve, propose_claim from vouch.storage import KBStore @@ -50,6 +51,21 @@ def test_recently_approved_claim_appears(store: KBStore) -> None: assert "approved_at" in row +def test_confirmed_claim_stays_in_sidebar(store: KBStore) -> None: + # kb.confirm promotes a working claim to actionable and bumps + # last_confirmed_at. the claim is at its freshest, so dropping it from the + # recency sidebar is backwards. + cid = _approved_claim(store, "the sky is blue today") + assert [r["id"] for r in hot_mod.compute_hot_memory(store, limit=5)] == [cid] + + confirm(store, claim_id=cid, actor="reviewer") + hot_mod.reset_sidebar_cache() + + rows = hot_mod.compute_hot_memory(store, limit=5) + assert [r["id"] for r in rows] == [cid] + assert rows[0]["status"] == ClaimStatus.ACTIONABLE.value + + def test_empty_kb_yields_empty_list(store: KBStore) -> None: assert hot_mod.compute_hot_memory(store, limit=5) == []