fix matchmaking search cache identity
This commit is contained in:
@@ -17,14 +17,35 @@ logger = logging.getLogger(__name__)
|
||||
# fields a caller may set on an opportunity's state (status + the generated document ids + activity flags)
|
||||
_STATE_FIELDS = ("status", "tailored_resume_id", "tailored_version_id", "cover_letter_id", "seen", "viewed", "saved")
|
||||
|
||||
# the search-defining pref fields — same values → same signature → cursor advances (new jobs);
|
||||
# change any → new signature → cursor resets to page 1.
|
||||
_SIG_FIELDS = ("title", "role", "location", "industry", "experience", "years", "work_mode", "remote")
|
||||
def _effective_title(prefs: dict) -> str:
|
||||
"""Match the board adapter's title precedence for cache identity."""
|
||||
target_titles = prefs.get("targetTitles") or []
|
||||
if target_titles and str(target_titles[0]).strip():
|
||||
return str(target_titles[0]).strip()
|
||||
title = str(prefs.get("title") or "").strip()
|
||||
if title:
|
||||
return title
|
||||
for role in prefs.get("role") or []:
|
||||
if role and role != "Open to any":
|
||||
return str(role)
|
||||
return ""
|
||||
|
||||
|
||||
def search_signature(prefs: dict) -> str:
|
||||
"""Stable short hash of the search-defining prefs (ignores transient flags / user_context)."""
|
||||
payload = {k: prefs.get(k) for k in _SIG_FIELDS}
|
||||
# Canonicalize the fields exactly as the board adapters consume them. The
|
||||
# dashboard contract is camelCase; work_mode remains a legacy fallback.
|
||||
work_mode = prefs.get("workMode") if "workMode" in prefs else prefs.get("work_mode")
|
||||
payload = {
|
||||
"effective_title": _effective_title(prefs),
|
||||
"role": prefs.get("role"),
|
||||
"location": prefs.get("location"),
|
||||
"industry": prefs.get("industry"),
|
||||
"experience": prefs.get("experience"),
|
||||
"years": prefs.get("years"),
|
||||
"workMode": work_mode,
|
||||
"remote": prefs.get("remote"),
|
||||
}
|
||||
blob = json.dumps(payload, sort_keys=True, default=str)
|
||||
return hashlib.sha1(blob.encode()).hexdigest()[:16]
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||
command: sh -c "alembic upgrade head && exec uvicorn app.main:app --host 0.0.0.0 --port 8000"
|
||||
restart: unless-stopped
|
||||
|
||||
postgres:
|
||||
|
||||
@@ -10,6 +10,7 @@ services:
|
||||
environment:
|
||||
# inside the compose network the DB host is `postgres` (overrides the host-dev .env value)
|
||||
DATABASE_URL: postgresql+asyncpg://matchmaking:matchmaking@postgres:5432/matchmaking
|
||||
command: sh -c "alembic upgrade head && exec uvicorn app.main:app --host 0.0.0.0 --port 8000"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Warm-pool gate — the reorder/floor decision that keeps the shelf stocked without over-fetching."""
|
||||
from app.engine.search import pool_decision
|
||||
from app.db.repo import search_signature
|
||||
|
||||
FLOOR, REORDER = 90, 100 # the configured thresholds (POOL_SAFETY_FLOOR / POOL_REORDER_AT)
|
||||
|
||||
@@ -39,3 +40,29 @@ def test_floor_never_above_reorder_invariant():
|
||||
from app.config import get_settings
|
||||
s = get_settings()
|
||||
assert s.POOL_SAFETY_FLOOR <= s.POOL_REORDER_AT
|
||||
|
||||
|
||||
def test_target_title_changes_search_signature():
|
||||
base = {
|
||||
"title": "Product Manager",
|
||||
"role": ["Product"],
|
||||
"targetTitles": ["Backend Engineer"],
|
||||
"location": ["Bangalore · India"],
|
||||
"workMode": ["Hybrid"],
|
||||
}
|
||||
changed = {**base, "targetTitles": ["Data Analyst"]}
|
||||
|
||||
assert search_signature(base) != search_signature(changed)
|
||||
|
||||
|
||||
def test_work_mode_changes_search_signature_using_dashboard_contract():
|
||||
base = {"title": "Data Analyst", "location": ["Bangalore · India"], "workMode": ["Hybrid"]}
|
||||
changed = {**base, "workMode": ["Remote"]}
|
||||
|
||||
assert search_signature(base) != search_signature(changed)
|
||||
|
||||
|
||||
def test_legacy_and_camel_case_work_mode_have_same_signature():
|
||||
common = {"title": "Data Analyst", "location": ["Bangalore · India"]}
|
||||
|
||||
assert search_signature({**common, "workMode": ["Hybrid"]}) == search_signature({**common, "work_mode": ["Hybrid"]})
|
||||
|
||||
Reference in New Issue
Block a user