From 865aae1b73f81a30943d4d5775618dd81caf9904 Mon Sep 17 00:00:00 2001 From: Nitzan Pomerantz <9297302+nitzpo@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:48:12 +0200 Subject: [PATCH 1/2] Fix autocomplete non-determinism causing 0 deals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Autocomplete returns different coordinates for vague queries (e.g. "תל אביב דיזנגוף"), sometimes landing on points with no nearby polygon_ids within 30m radius. - Try top 3 autocomplete results until one has polygons - Fallback radius expansion (30m→200m) if no polygons found - Fix limit validation bug (min 1 for deal queries) Fixes: compare_addresses, get_valuation_comparables, get_deal_statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- nadlan_mcp/govmap/client.py | 61 +++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/nadlan_mcp/govmap/client.py b/nadlan_mcp/govmap/client.py index 284f11b..4030c3b 100644 --- a/nadlan_mcp/govmap/client.py +++ b/nadlan_mcp/govmap/client.py @@ -559,18 +559,53 @@ class GovmapClient: if not autocomplete_result.results: raise ValueError(f"No results found for address: {address}") - # Get the best match (first result) - best_match = autocomplete_result.results[0] - if not best_match.coordinates: - raise ValueError("No coordinates found in autocomplete result") + # Try multiple autocomplete results to find one with nearby polygons + # (autocomplete can return different coordinates for vague queries) + nearby_polygons = [] + point = None + + for result in autocomplete_result.results[:3]: # Try top 3 results + if not result.coordinates: + continue + + test_point = (result.coordinates.longitude, result.coordinates.latitude) + test_polygons = self.get_deals_by_radius(test_point, radius=radius) + + if test_polygons: + point = test_point + nearby_polygons = test_polygons + logger.info( + f"Using autocomplete result: '{result.text}' with {len(test_polygons)} polygons" + ) + break + + # Fallback: if no results had polygons at specified radius, try expanding radius + if not nearby_polygons and radius < 200: + logger.warning(f"No polygons found at {radius}m radius, expanding to 200m") + # Use first result with coordinates for expanded search + for result in autocomplete_result.results[:3]: + if result.coordinates: + test_point = (result.coordinates.longitude, result.coordinates.latitude) + nearby_polygons = self.get_deals_by_radius(test_point, radius=200) + if nearby_polygons: + point = test_point + logger.info( + f"Found {len(nearby_polygons)} polygons at expanded 200m radius" + ) + break + + # Final fallback: use first result even if no polygons (will return empty results) + if not point: + best_match = autocomplete_result.results[0] + if not best_match.coordinates: + raise ValueError("No coordinates found in any autocomplete result") + point = (best_match.coordinates.longitude, best_match.coordinates.latitude) + logger.warning( + f"No polygons found for '{best_match.text}', will return empty results" + ) - # Use coordinates from the model - point = (best_match.coordinates.longitude, best_match.coordinates.latitude) search_address_normalized = address.lower().strip() - logger.info(f"Found coordinates: {point}") - - # Step 2: Get polygon metadata by radius to find polygon IDs - nearby_polygons = self.get_deals_by_radius(point, radius=radius) + logger.info(f"Using coordinates: {point}") # Extract unique polygon IDs from metadata dicts polygon_ids = set() @@ -612,7 +647,7 @@ class GovmapClient: # Get street deals first (higher priority) current_street_deals = self.get_street_deals( polygon_id, - limit=max_deals // 2, # Allocate more to street deals + limit=max(1, max_deals // 2), # Allocate more to street deals (min 1) start_date=start_date_str, end_date=end_date_str, deal_type=deal_type, @@ -624,7 +659,9 @@ class GovmapClient: if len(street_deals) < max_deals // 2: current_neighborhood_deals = self.get_neighborhood_deals( polygon_id, - limit=max_deals // 4, # Allocate less to neighborhood deals + limit=max( + 1, max_deals // 4 + ), # Allocate less to neighborhood deals (min 1) start_date=start_date_str, end_date=end_date_str, deal_type=deal_type, From fd79ea88bf6bc1e7c59176f3b6882496c655fb31 Mon Sep 17 00:00:00 2001 From: Nitzan Pomerantz <9297302+nitzpo@users.noreply.github.com> Date: Sat, 15 Nov 2025 00:08:42 +0200 Subject: [PATCH 2/2] Fix test_parse_deal_dates_basic temporal assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjusted sample_deals fixture to ensure 5 deals across 5 distinct months. Previous dates collapsed into 3 months due to naive 30-day calculations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- tests/govmap/test_market_analysis.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/govmap/test_market_analysis.py b/tests/govmap/test_market_analysis.py index 003ba70..c905fec 100644 --- a/tests/govmap/test_market_analysis.py +++ b/tests/govmap/test_market_analysis.py @@ -32,31 +32,31 @@ class TestParseDealDates: Deal( objectid=1, deal_amount=1000000, - deal_date=get_recent_date(months_ago=4, days_ago=15), + deal_date=get_recent_date(months_ago=4, days_ago=5), asset_area=80, ), Deal( objectid=2, deal_amount=1100000, - deal_date=get_recent_date(months_ago=4, days_ago=10), + deal_date=get_recent_date(months_ago=3, days_ago=5), asset_area=85, ), Deal( objectid=3, deal_amount=1200000, - deal_date=get_recent_date(months_ago=3, days_ago=20), + deal_date=get_recent_date(months_ago=2, days_ago=5), asset_area=90, ), Deal( objectid=4, deal_amount=1300000, - deal_date=get_recent_date(months_ago=2, days_ago=25), + deal_date=get_recent_date(months_ago=1, days_ago=5), asset_area=95, ), Deal( objectid=5, deal_amount=1400000, - deal_date=get_recent_date(months_ago=1, days_ago=18), + deal_date=get_recent_date(months_ago=0, days_ago=5), asset_area=100, ), ]