Skip to content

Keep explicit signal filters when expanding a search - #82

Open
00200200 wants to merge 2 commits into
huggingface:mainfrom
00200200:fix/preserve-explicit-signal-filters
Open

00200200 wants to merge 2 commits into
huggingface:mainfrom
00200200:fix/preserve-explicit-signal-filters

Conversation

@00200200

Copy link
Copy Markdown

Fixes #75.

expand() built each derived signal leg with replace(query, text="", **override). When the caller had already set --symbol (or --file / --error / --test), that overwrite dropped their constraint. The JSON filters object still echoed the original flag, so the page claimed a scope the query no longer applied.

Appending the derived value is not a fix either: values inside one signal filter are ORed, which would widen the call rather than keep it.

This skips a derived leg of a kind the caller already filtered on. The text leg and the filters-only leg still carry that evidence; cross-kind filters (e.g. --file on a symbol leg) are unchanged.

Tested with pytest tests/integration/test_expansion.py tests/unit tests/integration/test_search.py.

Skip a derived error/test/symbol/file leg when the caller already
filtered on that kind. Replacing the field dropped the constraint
while the response still reported it.
@tarekziade
tarekziade self-requested a review September 19, 2026 14:37
@tarekziade

Copy link
Copy Markdown
Collaborator

Thanks that looks right

One subtlety: rank_spec() gathers structured signals from the surviving legs, so skipping a leg also removes its derived signal from scoring. The term remains in the lexical query, but loses its signal-overlap weight.

Could we retain derived signals for ranking independently of which legs execute?

The regression test should also assert constrained_numbers == {2} It already indexes a valid matching thread, but the current assertions would pass if the constrained search returned nothing.

Skipping the derived leg for a kind the caller already scoped also dropped
that term from rank_spec, so it lost its signal-overlap weight while staying
in the lexical query. rank_spec now folds those terms in independently of
which legs run. The regression test also asserts the constrained call
returns exactly the matching thread, not merely nothing extra.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@00200200

Copy link
Copy Markdown
Author

Thanks, both points were right. Pushed a follow-up:

  • Ranking: rank_spec() now also folds in the derived terms for any kind the caller already scoped, so skipping that leg no longer drops the term's signal-overlap weight. It only widens the scoring question; the filters (and therefore the scope) are unchanged. Kinds the caller left open still arrive through their own leg, so nothing is counted twice. Added test_a_skipped_derived_leg_still_counts_toward_ranking (it fails without the change) plus a no-double-counting case.
  • Regression test: the constrained call now asserts constrained_numbers == {2}, so it can no longer pass by returning nothing.

Full suite passes locally (864 passed) and ruff is clean; the Postgres half of the parity tests is skipped here since I don't have a Postgres URL configured.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expansion overwrites explicit signal filters while the response still reports them as active

2 participants