Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@
## 2025-07-15 - Fast Bounding Box Pre-filter
**Learning:** Calculating great circle distance (Haversine) for every issue against a target location is computationally expensive (O(N) with heavy math ops like sin, cos, atan2). In high-traffic aggregations, this can become a bottleneck.
**Action:** Use a fast bounding box pre-filter (`get_bounding_box` with a 5% epsilon) to quickly discard issues that are definitely outside the search radius before running the expensive exact haversine distance calculation.

## 2025-07-16 - N+1 Query in Escalation Loop
**Learning:** During periodic evaluation of overdue grievances (`evaluate_and_escalate_grievances`), checking `grievance.jurisdiction.level` without eager loading triggers a separate DB query for every overdue grievance. This is a classic N+1 bottleneck when scanning a large number of open issues.
**Action:** Always use `.options(joinedload(Model.relationship))` in queries that retrieve lists of items if those items' relationships will be accessed during iteration.
7 changes: 5 additions & 2 deletions backend/escalation_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import datetime
from typing import List, Dict, Any, Optional
from sqlalchemy.orm import Session
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import and_, or_
from backend.models import Grievance, Jurisdiction, EscalationAudit, GrievanceStatus, JurisdictionLevel, EscalationReason, SeverityLevel
from backend.database import SessionLocal
Expand Down Expand Up @@ -150,7 +150,10 @@ def _get_grievances_for_evaluation(self, db: Session) -> List[Grievance]:
now = datetime.datetime.now(datetime.timezone.utc)

# Get grievances that are active and past SLA deadline
return db.query(Grievance).filter(
# PERFORMANCE OPTIMIZATION:
# Added .options(joinedload(Grievance.jurisdiction)) to resolve an N+1 query problem.
# This prevents a separate database query for each jurisdiction during the evaluation loop.
return db.query(Grievance).options(joinedload(Grievance.jurisdiction)).filter(
and_(
Grievance.status.in_([GrievanceStatus.OPEN, GrievanceStatus.IN_PROGRESS, GrievanceStatus.ESCALATED]),
Grievance.sla_deadline < now
Expand Down
Loading