ADR-0006 — Financial Constraint Parameter Mapping Strategy¶
Context¶
Financial constraint queries like "Horror movies with revenue under $25 million" require mapping revenue thresholds to TMDB API parameters for effective discovery. The challenge lies in the mismatch between user intent and API capabilities:
- User Intent: Find movies by revenue thresholds (e.g., "under $25M", "over $100M")
- TMDB API Limitation:
/discover/moviedoesn't support direct revenue filtering parameters - API Sorting Options: Only
sort_by=revenue.asc/descavailable for revenue-based ordering - Data Availability: Revenue data requires individual
/movie/{id}calls, not available in discovery results
Decision¶
Implement a dual-phase financial constraint mapping strategy that combines strategic sorting with post-API filtering:
Phase 1: Strategic Parameter Mapping
- Map revenue entities to sort_by parameters instead of direct filtering
- Use operator-aware sorting strategies:
- less_than/less_than_equal → sort_by=popularity.desc (avoids $0 revenue indie films)
- greater_than/greater_than_equal → sort_by=revenue.desc (gets highest earners first)
Phase 2: Post-Discovery Filtering - Fetch individual movie details for revenue data completion - Apply threshold-based filtering on complete financial data - Return results matching the original constraint criteria
Technical Implementation:
def _map_revenue_constraint(self, ent: dict) -> tuple:
operator = ent.get("operator", "less_than")
if operator in ("less_than", "less_than_equal"):
# Strategy: Get popular movies first, then filter by threshold
ent["sort_value"] = "popularity.desc"
ent["threshold"] = int(ent.get("name", 0))
ent["threshold_operator"] = operator
elif operator in ("greater_than", "greater_than_equal"):
# Strategy: Get highest revenue movies first
ent["sort_value"] = "revenue.desc"
ent["threshold"] = int(ent.get("name", 0))
ent["threshold_operator"] = operator
return "sort_by", priority=1
Rationale¶
Why not direct revenue parameter filtering?
- TMDB API doesn't provide revenue filtering parameters in /discover/movie
- Direct filtering would require custom API endpoint development
Why popularity.desc for "under" queries?
- sort_by=revenue.asc returns thousands of $0 revenue independent films first
- Popular movies are more likely to have accurate revenue data
- Provides better user experience with recognizable mainstream titles
Why individual movie detail fetching?
- /discover/movie responses don't include revenue fields
- Required for accurate threshold-based filtering
- Acceptable performance trade-off for financial query accuracy
Consequences¶
Positive¶
- Accurate Financial Filtering: Users get precise revenue-based results matching their thresholds
- Strategic API Usage: Optimizes TMDB API calls by getting relevant movies first
- Extensible Pattern: Framework supports future financial constraints (budget, profit margins)
- Fallback Compatibility: System gracefully handles missing revenue data
Negative¶
- Increased API Calls: Requires individual movie detail fetching (N+1 pattern)
- Response Latency: Additional network calls for revenue data completion
- API Rate Limits: Higher chance of hitting TMDB rate limits for large result sets
Mitigations¶
- Result Limiting: Intelligent estimation of required result counts based on constraint selectivity
- Caching Strategy: Cache movie detail responses for repeated revenue queries
- Progressive Loading: Fetch revenue data in batches with user-visible progress
- Fallback Degradation: Show partial results if API limits are reached
Implementation Files¶
data/param_to_entity_map.json- Added"sort_by": "revenue"mappingcore/model/constraint.py- Revenue constraint builder with operator logiccore/planner/plan_validator.py- Revenue parameter injection with strategic sortingcore/execution/discovery_handler.py- Individual movie detail fetching before filteringcore/execution/financial_filter.py- Threshold-based revenue filtering implementation