refactor(search): consolidate the keyword-mode query-path gate (ADR-030)#1021
Conversation
Behavior-preserving cleanup of the query-type gate merged in #1020 — no wire contract, status, or 422 change (existing unit + pact tests pass unchanged). - management.py: merge resolve_search_algorithm into select_search_algorithm (it was the sole caller, via the implicit-default branch). One function now expresses the whole contract: absent → graceful default; explicit supported → pass through; explicit unsupported → raise UnsupportedSearchType (422). - visualization.py: extract _build_search_algorithm() and use it in both unified_search and vector_search, removing the byte-identical select + try/except + if-semantic-else-bm25hybrid block from each endpoint. - viz_routes.py: the OAuth-session PCA-viz search selected the pure-dense SemanticSearchAlgorithm from a raw query param with no mode check, so in keyword mode it built a dense algorithm that fails against the sparse-only collection. Reject semantic when dense is disabled (bm25_hybrid stays valid in both modes). New unit test asserts the dense algo is never constructed. - Contract: parametrize the keyword-mode 422 pact over both /api/v1/search and /api/v1/vector-viz/search (they now share one gate). ADR-030 updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @cbcoutinho's task in 2m 10s —— View job Review: refactor(search): consolidate the keyword-mode query-path gate (ADR-030)
This is a clean, well-scoped refactor — I traced the logic carefully and the "behavior-preserving" claim holds up.
One observation, not a blocker: this endpoint returns 400 for the rejected-semantic case, while the same conceptual rejection on Tests — the new Docs — ADR-030 update accurately reflects the single-function contract, no stale references to No bugs, security issues, or missing test coverage found. Note: I was unable to execute |
|
|
Thanks — round 1 is a clean pass (no bugs/security/coverage findings). On your one observation: 400 (viz route) vs 422 (API endpoints) for rejected No code change this round. Treating as merge-ready pending the integration matrix going green. |



Summary
Follow-up to #1020: a behavior-preserving cleanup of the ADR-030 keyword-mode query-path gate. No wire contract,
/api/v1/status, or 422 change — the existing unit and Pact tests pass unchanged, which is the proof this is a pure refactor.Changes
api/management.py— mergeresolve_search_algorithmintoselect_search_algorithm(it was the sole caller, via the implicit-default branch). One function now expresses the whole contract: absent → graceful default; explicit supported → pass through; explicit unsupported → raiseUnsupportedSearchType(→ 422).api/visualization.py— extract_build_search_algorithm()used by bothunified_searchandvector_search, removing the byte-identicalselect + try/except + if-semantic-else-bm25hybridblock duplicated in each endpoint.auth/viz_routes.py— the OAuth-session PCA-viz search selected the pure-denseSemanticSearchAlgorithmfrom a raw query param with no mode check, so in keyword mode it built a dense algorithm that fails against the sparse-only collection. Now rejectssemanticwhen dense is disabled (bm25_hybridstays valid in both modes). New unit test asserts the dense algorithm is never constructed./api/v1/searchand/api/v1/vector-viz/search(they now share one gate). ADR-030 updated.Note on status codes (intentional)
The rejected-
semanticcase returns 400 on the session-auth/app/vector-viz/search(matching that file's local{"success": false, "error": …}+ 400 convention used throughoutviz_routes.py) but 422unsupported_search_typeon the astrolabe-consumed/api/v1/search+/api/v1/vector-viz/search(the Pact-covered contract). The split is deliberate: only the two API endpoints share_build_search_algorithmand are part of astrolabe's consumer contract; the browser viz route keeps its own error shape.Out of scope (intentionally kept)
Load-bearing
dense_enabledbranches inbm25_hybrid.py(sparse-only vs fusion) andserver/semantic.py(method_label/score_threshold); all ingest-side conditionals. The strict 422 backstop is deliberately retained (dropping it would revert to the silentsemantic→bm25coercion that motivated #1020).Test plan
pytest tests/unit/test_management_status_endpoint.py tests/unit/test_search_endpoint_algorithm_gate.py tests/unit/test_viz_routes_search_algorithm_gate.py(+ search suite) — 159 passedpytest -m contract tests/contract/test_mcp_status_search_types_consumer.py— 4 interactions (status hybrid/keyword + 422 on both endpoints)ruff+tyclean (pre-commit)This PR was generated with the help of AI, and reviewed by a Human