Skip to content

fix(digest): drop archived followups from the due list - #636

Merged
plind-junior merged 1 commit into
vouchdev:testfrom
atoz96:fix/digest-excludes-archived-followups
Jul 30, 2026
Merged

fix(digest): drop archived followups from the due list#636
plind-junior merged 1 commit into
vouchdev:testfrom
atoz96:fix/digest-excludes-archived-followups

Conversation

@atoz96

@atoz96 atoz96 commented Jul 30, 2026

Copy link
Copy Markdown

archiving a followup page does nothing to vouch digest — it keeps appearing in the due list forever.

the asymmetry

the two queries sit adjacent in digest.build. the claim one filters lifecycle status:

for c in store.list_claims():
    if c.status in _RETIRED_CLAIM_STATUSES:
        continue

the page one doesn't:

due_pages = filter_pages(
    store.list_pages(),
    kind="followup",
    before={"due_at": now.date().isoformat()},
)

and it can't have — filter_pages only understands kind, equals, before, after. there is no status predicate anywhere in page_filters.py, so nothing in this path has ever excluded an archived page.

reproducing

two followup pages, same past due date, both followup_status: open, one ACTIVE and one ARCHIVED:

expected: ['fu-live']
actual:   ['fu-archived', 'fu-live']

_CLOSED_FOLLOWUP_STATUSES catches a followup that was marked done, but archiving the page is the other way to retire one, and that path was unguarded.

why it matters here specifically

the digest is the reviewer-facing briefing — vouch digest, kb.digest, and the SessionStart surface. an archived followup showing as overdue is worse than a stale search hit: it's an action item the reviewer is being asked to do something about, and the only way to make it go away was to edit followup_status, not to archive.

same shape as the retracted-claim gaps fixed in #581 and #624, and the archived-page gap in context packs — the lifecycle control is honoured on one read surface and ignored on the next.

the change

archived pages are filtered out before the kind/due-date predicates. i deliberately did not teach filter_pages about status: the digest is the caller that wants live pages only, and page_filters is a pure frontmatter matcher used by vouch pages and the CLI listing, where "show me archived followups" is a legitimate query. pushing status into the shared filter would change those callers too.

tests

test_build_excludes_archived_followups — fails on the previous code with

AssertionError: assert ['fu-archived', 'fu-live'] == ['fu-live']

verification

pytest tests/ -q --ignore=tests/embeddings   green
mypy src                                     Success: no issues found in 117 source files
ruff check src tests                         All checks passed!

the stale-claims loop skips retired claims, but the followup query
immediately below it passed store.list_pages() to filter_pages with no
status predicate — and filter_pages only knows about kind, equals, before
and after. so archiving a followup page did nothing to the digest: it kept
appearing as due, forever, on the surface a reviewer actually reads.

same shape as the retracted-claim gaps fixed in vouchdev#581 and vouchdev#624, and the
archived-page gap in context packs: the lifecycle control is honoured on
one read surface and ignored on the next.

filters ARCHIVED out before the kind/due-date predicates rather than
teaching filter_pages about status — the digest is the caller that wants
live pages only, and page_filters stays a pure metadata matcher.
@github-actions github-actions Bot added tests tests and fixtures size: XS less than 50 changed non-doc lines labels Jul 30, 2026
@plind-junior

Copy link
Copy Markdown
Member

Thanks for addressing the issue. LGTM!

@plind-junior
plind-junior merged commit f893114 into vouchdev:test Jul 30, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: XS less than 50 changed non-doc lines tests tests and fixtures

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants