diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b0113b4..fdaef3b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -155,6 +155,12 @@ All notable changes to vouch are documented here. Format follows artifact the caller could not already retrieve, and it touches no write path. ### Fixed +- **`kb.list_pages` / `vouch pages` no longer list archived pages** (#728): + `filter_pages` (shared by MCP, JSONL, and the CLI) had no + `PageStatus.ARCHIVED` gate, so retired pages stayed in the agent-facing + live listing — and MCP/CLI payloads omit `status`, so an archived page + looked identical to a live one. Default is now live-set only + (`include_archived=False`); pass `include_archived=True` to opt back in. - **`extract` no longer fractures file paths/URLs into auto-approved garbage claims** (#702): the sentence segmenter only skipped a `.` as a boundary when it was flanked by digits on both sides (decimals/versions diff --git a/src/vouch/page_filters.py b/src/vouch/page_filters.py index 068059d2..2853b904 100644 --- a/src/vouch/page_filters.py +++ b/src/vouch/page_filters.py @@ -17,7 +17,7 @@ from typing import Any -from .models import Page +from .models import Page, PageStatus def filter_pages( @@ -27,15 +27,21 @@ def filter_pages( equals: dict[str, str] | None = None, before: dict[str, str] | None = None, after: dict[str, str] | None = None, + include_archived: bool = False, ) -> list[Page]: """Return the pages matching every given predicate. kind: exact match on `Page.type`. equals: frontmatter field == value (string-compared). before / after: inclusive bounds — value <= / >= the given bound. + include_archived: when False (default), drop ``PageStatus.ARCHIVED`` + pages so agent-facing listings (`kb.list_pages`, `vouch pages`) match + the live-set convention used by search/wiki/neighbors/digest (#728). """ out: list[Page] = [] for page in pages: + if not include_archived and page.status is PageStatus.ARCHIVED: + continue if kind is not None and page.type != kind: continue meta = page.metadata diff --git a/tests/test_page_filters.py b/tests/test_page_filters.py index 92c42c81..e68b4f74 100644 --- a/tests/test_page_filters.py +++ b/tests/test_page_filters.py @@ -75,6 +75,15 @@ def test_filter_numeric_bounds() -> None: assert [p.id for p in hits] == ["p5", "p30"] +def test_filter_excludes_archived_by_default() -> None: + pages = [ + _page("live"), + Page(id="dead", title="dead", type="concept", status=PageStatus.ARCHIVED), + ] + assert [p.id for p in filter_pages(pages)] == ["live"] + assert [p.id for p in filter_pages(pages, include_archived=True)] == ["live", "dead"] + + def test_parse_kv() -> None: assert parse_kv(("a=1", "b=x=y")) == {"a": "1", "b": "x=y"} with pytest.raises(ValueError):