-
Notifications
You must be signed in to change notification settings - Fork 30
fix(spatial): address review feedback - hybrid distance calculation and IDL test coverage #361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(spatial): address review feedback - hybrid distance calculation and IDL test coverage #361
Conversation
- Use equirectangular as pre-filter, then compute accurate Haversine distance for candidates - Fix misleading comment about "actual distance" (now clarifies it's great-circle distance) - Unify Earth radius constants (use EARTH_RADIUS_METERS everywhere) - Add comprehensive IDL and high-latitude test cases Co-authored-by: RohanExploit <178623867+RohanExploit@users.noreply.github.com>
Clarify why mean radius is used over WGS84 equatorial radius Co-authored-by: RohanExploit <178623867+RohanExploit@users.noreply.github.com>
🔍 Quality Reminder |
91c9566
into
bolt/spatial-optimization-15204600466855577516
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues found across 4 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="tests/test_spatial_utils_only.py">
<violation number="1" location="tests/test_spatial_utils_only.py:123">
P2: Misleading comment contradicts test behavior. The comment says "shouldn't match across IDL" but the test uses a 250km radius and asserts that both issues ARE found (including across IDL). The variable name `nearby_small` is also misleading since 250km is not small.</violation>
</file>
<file name="backend/spatial_utils.py">
<violation number="1" location="backend/spatial_utils.py:135">
P2: Missing radius check after computing Haversine distance. The equirectangular pre-filter can underestimate distances, allowing issues outside the radius to be included. The accurate Haversine distance should be verified against `radius_meters` before appending.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| Issue(id=6, latitude=0.0, longitude=-179.0), | ||
| ] | ||
|
|
||
| # With small radius, shouldn't match across IDL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Misleading comment contradicts test behavior. The comment says "shouldn't match across IDL" but the test uses a 250km radius and asserts that both issues ARE found (including across IDL). The variable name nearby_small is also misleading since 250km is not small.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/test_spatial_utils_only.py, line 123:
<comment>Misleading comment contradicts test behavior. The comment says "shouldn't match across IDL" but the test uses a 250km radius and asserts that both issues ARE found (including across IDL). The variable name `nearby_small` is also misleading since 250km is not small.</comment>
<file context>
@@ -0,0 +1,205 @@
+ Issue(id=6, latitude=0.0, longitude=-179.0),
+ ]
+
+ # With small radius, shouldn't match across IDL
+ nearby_small = find_nearby_issues(issues_wrapped, 0.0, 179.0, radius_meters=250000)
+ print(f" Found {len(nearby_small)} issues within 250km from 179.0°E")
</file context>
| # Calculate actual distance (sqrt of squared distance) | ||
| distance = math.sqrt(dist_sq) | ||
| # Calculate accurate great-circle distance for candidates that passed filter | ||
| distance = haversine_distance(target_lat, target_lon, issue.latitude, issue.longitude) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Missing radius check after computing Haversine distance. The equirectangular pre-filter can underestimate distances, allowing issues outside the radius to be included. The accurate Haversine distance should be verified against radius_meters before appending.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/spatial_utils.py, line 135:
<comment>Missing radius check after computing Haversine distance. The equirectangular pre-filter can underestimate distances, allowing issues outside the radius to be included. The accurate Haversine distance should be verified against `radius_meters` before appending.</comment>
<file context>
@@ -120,16 +123,16 @@ def find_nearby_issues(
- # Calculate actual distance (sqrt of squared distance)
- distance = math.sqrt(dist_sq)
+ # Calculate accurate great-circle distance for candidates that passed filter
+ distance = haversine_distance(target_lat, target_lon, issue.latitude, issue.longitude)
nearby_issues.append((issue, distance))
</file context>
| distance = haversine_distance(target_lat, target_lon, issue.latitude, issue.longitude) | |
| distance = haversine_distance(target_lat, target_lon, issue.latitude, issue.longitude) | |
| if distance > radius_meters: | |
| continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Improves the spatial deduplication utilities and related guidance by returning accurate great-circle distances while preserving the equirectangular performance optimization, and adds International Date Line-focused tests.
Changes:
- Hybrid distance calculation: equirectangular squared-distance pre-filter + Haversine for returned distances in
find_nearby_issues. - Unified Earth radius constant usage in spatial helpers.
- Added/expanded IDL and high-latitude test coverage; updated internal optimization notes.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
backend/spatial_utils.py |
Unifies Earth radius constant and switches nearby-issue distance output to accurate Haversine after a fast pre-filter. |
tests/test_spatial_deduplication.py |
Adds an IDL handling test for spatial utilities. |
tests/test_spatial_utils_only.py |
Introduces a focused spatial utility test suite (Haversine/equirectangular/IDL/constant checks). |
.jules/bolt.md |
Updates internal “bolt” guidance to document the hybrid pre-filter + accurate-distance approach. |
Comments suppressed due to low confidence (1)
backend/spatial_utils.py:38
get_bounding_boxcan returnmin_lon/max_lonoutside the [-180, 180] range (or a range that crosses the International Date Line). Callers use these values directly in SQLIssue.longitude >= min_lon/<= max_lonfilters, which will miss valid candidates across the IDL (e.g., target lon=179.9, radius=30km should include lon=-179.9, but won’t). Consider normalizing longitudes and explicitly handling the wrap case (e.g., return a flag / two longitude intervals, or provide a helper that builds the correct SQL filter with an OR when the box crosses the IDL; also consider the near-pole case where longitude should be unconstrained).
def get_bounding_box(lat: float, lon: float, radius_meters: float) -> Tuple[float, float, float, float]:
"""
Calculate the bounding box coordinates for a given radius.
Returns (min_lat, max_lat, min_lon, max_lon).
"""
# Coordinate offsets in radians
# Prevent division by zero at poles
effective_lat = max(min(lat, 89.9), -89.9)
dlat = radius_meters / EARTH_RADIUS_METERS
dlon = radius_meters / (EARTH_RADIUS_METERS * math.cos(math.pi * effective_lat / 180.0))
# Offset positions in decimal degrees
lat_offset = dlat * 180.0 / math.pi
lon_offset = dlon * 180.0 / math.pi
min_lat = lat - lat_offset
max_lat = lat + lat_offset
min_lon = lon - lon_offset
max_lon = lon + lon_offset
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def test_international_date_line_handling(): | ||
| """Test that longitude wrapping works correctly near the International Date Line""" | ||
| print("Testing International Date Line handling...") | ||
|
|
||
| # Test case 1: Points near +180/-180 boundary | ||
| # Point at 179.9°E and point at -179.9°W should be ~22km apart, not ~35978km | ||
| issues = [ | ||
| Issue(id=1, latitude=0.0, longitude=179.9), | ||
| Issue(id=2, latitude=0.0, longitude=-179.9), | ||
| ] | ||
|
|
||
| # Test from eastern side of IDL | ||
| nearby_east = find_nearby_issues(issues, 0.0, 179.9, radius_meters=30000) | ||
| print(f"Found {len(nearby_east)} issues within 30km from 179.9°E") | ||
| assert len(nearby_east) == 2, f"Expected 2 issues (both sides of IDL), got {len(nearby_east)}" | ||
|
|
||
| # Verify the cross-IDL distance is calculated correctly | ||
| cross_idl_distance = haversine_distance(0.0, 179.9, 0.0, -179.9) | ||
| print(f"Cross-IDL distance (179.9 to -179.9): {cross_idl_distance:.2f} meters") | ||
| assert cross_idl_distance < 25000, f"Cross-IDL distance should be ~22km, got {cross_idl_distance:.2f}m" | ||
|
|
||
| # Test case 2: High latitude near IDL | ||
| # At 60°N, longitude degrees are compressed (1° ≈ 55.6km) | ||
| issues_high_lat = [ | ||
| Issue(id=3, latitude=60.0, longitude=179.5), | ||
| Issue(id=4, latitude=60.0, longitude=-179.5), | ||
| ] | ||
|
|
||
| nearby_high_lat = find_nearby_issues(issues_high_lat, 60.0, 179.5, radius_meters=60000) | ||
| print(f"Found {len(nearby_high_lat)} issues at 60°N within 60km") | ||
| assert len(nearby_high_lat) == 2, f"Expected 2 issues at high latitude, got {len(nearby_high_lat)}" | ||
|
|
||
| high_lat_distance = haversine_distance(60.0, 179.5, 60.0, -179.5) | ||
| print(f"High latitude cross-IDL distance: {high_lat_distance:.2f} meters") | ||
| assert 50000 <= high_lat_distance <= 60000, f"High-lat cross-IDL distance should be ~55.6km, got {high_lat_distance:.2f}m" | ||
|
|
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new IDL test validates find_nearby_issues on an in-memory list, but the production endpoints first pre-filter in SQL using get_bounding_box + longitude >= min_lon AND longitude <= max_lon. Since get_bounding_box doesn’t currently handle International Date Line wrap, the API can still miss cross-IDL candidates even if find_nearby_issues is correct. Add a test that exercises the /api/issues/nearby endpoint (or a unit test for get_bounding_box’s wrap behavior) around ±180° to prevent regressions.
| # With small radius, shouldn't match across IDL | ||
| nearby_small = find_nearby_issues(issues_wrapped, 0.0, 179.0, radius_meters=250000) | ||
| print(f" Found {len(nearby_small)} issues within 250km from 179.0°E") | ||
| # Both should be found as they're ~222km apart | ||
| assert len(nearby_small) == 2, f"Expected 2 issues, got {len(nearby_small)}" |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment for this case is contradictory: it says “With small radius, shouldn't match across IDL”, but the radius is 250km and the assertions expect the cross‑IDL point (~222km away) to be included. Please update the comment to reflect what’s being tested (e.g., that cross‑IDL matching occurs only when the radius is large enough).
Addresses review comments on PR #358's spatial optimization. Four issues: (1) missing IDL test coverage, (2)
find_nearby_issuesreturns approximation instead of accurate distance, (3) misleading comments, (4) inconsistent Earth radius constants.Changes
Hybrid distance calculation: Use equirectangular squared-distance as pre-filter, compute Haversine only for candidates that pass. Maintains ~4x speedup while returning accurate great-circle distances to callers.
IDL test coverage: Added test cases for ±180° boundary and high-latitude (60°N) scenarios where longitude compression matters.
Unified Earth radius: Replaced hardcoded
R = 6378137.0inget_bounding_boxwith sharedEARTH_RADIUS_METERS = 6371000.0. Documented choice of mean radius over WGS84 equatorial radius.Clarified documentation: Updated comments and docstrings to specify returned distances are Haversine (great-circle), not approximations.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
Summary by cubic
Optimized spatial deduplication with a fast equirectangular pre-filter and Haversine for final, sorted distances. Unified Earth-radius usage to the mean radius and expanded tests for edge cases.
Written for commit 6eb751c. Summary will update on new commits.