Skip to content

fix(explain): withhold status-filtered candidates summaries - #651

Merged
plind-junior merged 2 commits into
vouchdev:testfrom
galuis116:fix/explain-ranking-status-filter-leak
Jul 30, 2026
Merged

fix(explain): withhold status-filtered candidates summaries#651
plind-junior merged 2 commits into
vouchdev:testfrom
galuis116:fix/explain-ranking-status-filter-leak

Conversation

@galuis116

Copy link
Copy Markdown
Contributor

What changed

explain_ranking() now sources candidate summary values from live (the
post-status-filter candidate set) instead of scoped (post-scope-filter,
pre-status-filter), so a retracted/superseded/redacted claim or archived
page that's correctly reported gate: "status-filtered" no longer carries
its full live text in the response.

Why

#640 fixed this exact leak class for the scope_filter stage — a
viewer-invisible candidate keeps its gate attribution but not its text,
matching what kb.search/kb.context already withhold for that viewer.
That fix's chosen source, scoped, is itself computed before
_filter_live_hits runs (the stage that drops retracted/superseded/
redacted claims and archived pages), so the same withholding was never
extended to the status_filter stage. A status-filtered candidate's
summary was still looked up from the pre-status-filter dict regardless of
which stage actually dropped it — confirmed with a repro: a SUPERSEDED
claim containing a secret string came back verbatim in the JSON response
even though its gate correctly said status-filtered.

Fixes #650

What might break

Nothing for users with an existing .vouch/ directory — no on-disk shape,
kb.* method, or object model change. Behaviorally: summary is now ""
for any candidate whose gate is status-filtered (it was previously the
live claim/page text); every other gate value's summary is unaffected,
since live and scoped only differ by which artifacts were removed for
being retracted/superseded/redacted/archived.

VEP

Not applicable — no object model, kb.* method, on-disk layout, bundle
format, or audit-log shape change. A one-line fix to which candidate set a
read-only introspection surface sources its summaries from.

Tests

  • Local make check-equivalent: ruff clean (src + tests); mypy
    clean on explain_ranking.py; all 33 tests/test_explain_ranking.py
    cases pass (31 pre-existing + 2 new)
  • New / changed behaviour has a test —
    test_status_filtered_claim_does_not_carry_its_summary,
    test_status_filtered_page_does_not_carry_its_summary (mirroring
    fix(explain): scope-filtered candidates leak their summary to the viewer #640's test_scope_filtered_candidate_does_not_carry_its_summary)
  • CHANGELOG.md updated under ## [Unreleased]

a retracted/superseded/redacted claim or archived page correctly
reported gate: "status-filtered", but explain_ranking sourced
summaries from `scoped` (post scope-filter, pre status-filter), so
its full live text still came back regardless of which stage actually
dropped it.

vouchdev#640 fixed the equivalent leak for the scope_filter stage, moving
summaries off the raw fused set. that fix's chosen source, `scoped`,
is itself still upstream of `_filter_live_hits`, so the same
withholding was never extended to status_filter.

source summaries from `live` instead — the set that survived both the
scope and status gates, matching what kb.search/kb.context expose.
new tests mirror vouchdev#640's scope-filtered regression test for a
superseded claim and an archived page, asserting an empty summary and
that the secret text is absent from the dumped response.

Fixes vouchdev#650
@github-actions github-actions Bot added docs documentation, specs, examples, and repo guidance tests tests and fixtures size: XS less than 50 changed non-doc lines labels Jul 30, 2026
@plind-junior
plind-junior enabled auto-merge July 30, 2026 16:40
@plind-junior
plind-junior merged commit 65b9681 into vouchdev:test Jul 30, 2026
16 checks passed
@github-actions github-actions Bot added the ci: passing ci is green label Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

diff coverage: n/a — this PR changes no python under src/vouch/, so there is nothing for the gate to measure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci: passing ci is green docs documentation, specs, examples, and repo guidance 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