Files
boc/iom/decision_support/decision_engine.py
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

430 lines
16 KiB
Python

"""
Decision Support Engine
Transforms observations → decisions → actions → outcomes
Not selling data. Selling better decisions.
"""
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
class DecisionType(str, Enum):
"""Types of decisions supported"""
INVESTMENT = "investment" # Where to invest
MAINTENANCE = "maintenance" # What to maintain first
RISK_MITIGATION = "risk_mitigation" # How to reduce risk
ESTABLISHMENT = "establishment" # Where to establish business
RESOURCE_ALLOCATION = "resource_allocation" # How to allocate budget
SAFETY_IMPROVEMENT = "safety_improvement" # How to improve safety
class Stakeholder(str, Enum):
"""Target stakeholders"""
MUNICIPALITY = "municipality"
PROPERTY_OWNER = "property_owner"
INFRASTRUCTURE_OWNER = "infrastructure_owner"
INSURANCE = "insurance"
BANK = "bank"
RETAIL = "retail"
LOGISTICS = "logistics"
CITIZEN = "citizen"
@dataclass
class DecisionRecommendation:
"""A decision recommendation"""
decision_type: DecisionType
stakeholder: Stakeholder
recommendation: str
expected_impact: float
confidence: float
cost_estimate_usd: Optional[float]
timeline_months: Optional[int]
supporting_data: List[Dict]
risks: List[str]
def to_dict(self) -> Dict:
return {
"decision_type": self.decision_type.value,
"stakeholder": self.stakeholder.value,
"recommendation": self.recommendation,
"expected_impact": round(self.expected_impact, 2),
"confidence": round(self.confidence, 2),
"cost_estimate_usd": self.cost_estimate_usd,
"timeline_months": self.timeline_months,
"supporting_data": self.supporting_data,
"risks": self.risks
}
class DecisionEngine:
"""Generates decision recommendations from reality signals"""
def __init__(self):
self.decision_models = self._load_decision_models()
self.visual_geo_enabled = True # NEW
def _load_decision_models(self) -> Dict:
"""Load decision models for each stakeholder"""
return {
Stakeholder.MUNICIPALITY: {
"priorities": ["safety", "maintenance_backlog", "citizen_satisfaction", "budget_efficiency"],
"decision_types": [DecisionType.MAINTENANCE, DecisionType.SAFETY_IMPROVEMENT, DecisionType.RESOURCE_ALLOCATION],
"budget_range": [100000, 10000000]
},
Stakeholder.PROPERTY_OWNER: {
"priorities": ["property_value", "tenant_satisfaction", "maintenance_cost", "market_position"],
"decision_types": [DecisionType.INVESTMENT, DecisionType.MAINTENANCE, DecisionType.ESTABLISHMENT],
"budget_range": [50000, 5000000]
},
Stakeholder.INFRASTRUCTURE_OWNER: {
"priorities": ["asset_condition", "failure_risk", "compliance", "lifecycle_cost"],
"decision_types": [DecisionType.MAINTENANCE, DecisionType.RISK_MITIGATION, DecisionType.INVESTMENT],
"budget_range": [500000, 50000000]
},
Stakeholder.INSURANCE: {
"priorities": ["risk_assessment", "claim_prevention", "portfolio_optimization"],
"decision_types": [DecisionType.RISK_MITIGATION, DecisionType.RESOURCE_ALLOCATION],
"budget_range": [0, 0] # Risk-based pricing
},
Stakeholder.RETAIL: {
"priorities": ["foot_traffic", "demographics", "competition", "accessibility"],
"decision_types": [DecisionType.ESTABLISHMENT, DecisionType.INVESTMENT],
"budget_range": [100000, 2000000]
}
}
def recommend(
self,
stakeholder: Stakeholder,
location_signals: Dict[str, float],
constraints: Optional[Dict] = None,
visual_evidence: Optional[Dict] = None # NEW
) -> List[DecisionRecommendation]:
"""
Generate decision recommendations for a stakeholder
Args:
stakeholder: Who is making the decision
location_signals: Reality signals for the location
constraints: Budget, timeline, etc.
Returns:
Prioritized recommendations
"""
model = self.decision_models.get(stakeholder, {})
recommendations = []
for decision_type in model.get("decision_types", []):
rec = self._generate_recommendation(
stakeholder, decision_type, location_signals, constraints, visual_evidence
)
if rec:
recommendations.append(rec)
# Sort by expected impact
recommendations.sort(key=lambda x: x.expected_impact, reverse=True)
return recommendations
def _generate_recommendation(
self,
stakeholder: Stakeholder,
decision_type: DecisionType,
signals: Dict[str, float],
constraints: Optional[Dict],
visual_evidence: Optional[Dict] = None
) -> Optional[DecisionRecommendation]:
"""Generate a specific recommendation"""
if decision_type == DecisionType.MAINTENANCE:
return self._maintenance_recommendation(stakeholder, signals, constraints, visual_evidence)
elif decision_type == DecisionType.SAFETY_IMPROVEMENT:
return self._safety_recommendation(stakeholder, signals, constraints, visual_evidence)
elif decision_type == DecisionType.INVESTMENT:
return self._investment_recommendation(stakeholder, signals, constraints, visual_evidence)
elif decision_type == DecisionType.ESTABLISHMENT:
return self._establishment_recommendation(stakeholder, signals, constraints, visual_evidence)
elif decision_type == DecisionType.RISK_MITIGATION:
return self._risk_recommendation(stakeholder, signals, constraints, visual_evidence)
return None
def _maintenance_recommendation(
self,
stakeholder: Stakeholder,
signals: Dict[str, float],
constraints: Optional[Dict],
visual_evidence: Optional[Dict] = None
) -> DecisionRecommendation:
"""Generate maintenance recommendation"""
condition = signals.get("maintenance_quality", 50)
backlog = signals.get("maintenance_backlog", 0)
if condition < 40:
urgency = "critical"
expected_impact = 80
elif condition < 60:
urgency = "high"
expected_impact = 60
else:
urgency = "medium"
expected_impact = 40
return DecisionRecommendation(
decision_type=DecisionType.MAINTENANCE,
stakeholder=stakeholder,
recommendation=f"Prioritize {urgency} maintenance. Current quality: {condition}/100.",
expected_impact=expected_impact,
confidence=0.75,
cost_estimate_usd=constraints.get("budget_usd", 100000) if constraints else 100000,
timeline_months=6,
supporting_data=[
{"signal": "maintenance_quality", "value": condition},
{"signal": "maintenance_backlog", "value": backlog}
],
risks=["Budget overrun", "Disruption during work"]
)
def _safety_recommendation(
self,
stakeholder: Stakeholder,
signals: Dict[str, float],
constraints: Optional[Dict],
visual_evidence: Optional[Dict] = None
) -> DecisionRecommendation:
"""Generate safety improvement recommendation"""
safety = signals.get("safety_index", 50)
lighting = signals.get("lighting", 50)
interventions = []
if lighting < 50:
interventions.append("improve lighting")
if safety < 50:
interventions.append("increase surveillance")
return DecisionRecommendation(
decision_type=DecisionType.SAFETY_IMPROVEMENT,
stakeholder=stakeholder,
recommendation=f"Improve safety: {', '.join(interventions)}. Current safety: {safety}/100.",
expected_impact=(100 - safety) * 0.8,
confidence=0.7,
cost_estimate_usd=120000,
timeline_months=4,
supporting_data=[
{"signal": "safety_index", "value": safety},
{"signal": "lighting", "value": lighting}
],
risks=["Limited effectiveness if not combined with other measures"]
)
def _investment_recommendation(
self,
stakeholder: Stakeholder,
signals: Dict[str, float],
constraints: Optional[Dict],
visual_evidence: Optional[Dict] = None
) -> DecisionRecommendation:
"""Generate investment recommendation"""
property_value = signals.get("property_value", 50)
growth_potential = signals.get("growth_potential", 50)
return DecisionRecommendation(
decision_type=DecisionType.INVESTMENT,
stakeholder=stakeholder,
recommendation=f"Investment opportunity. Current value: {property_value}/100. Growth potential: {growth_potential}/100.",
expected_impact=growth_potential * 0.9,
confidence=0.65,
cost_estimate_usd=constraints.get("budget_usd", 500000) if constraints else 500000,
timeline_months=12,
supporting_data=[
{"signal": "property_value", "value": property_value},
{"signal": "growth_potential", "value": growth_potential}
],
risks=["Market downturn", "Construction delays"]
)
def _establishment_recommendation(
self,
stakeholder: Stakeholder,
signals: Dict[str, float],
constraints: Optional[Dict],
visual_evidence: Optional[Dict] = None
) -> DecisionRecommendation:
"""Generate establishment recommendation"""
foot_traffic = signals.get("pedestrian_flow", 50)
competition = signals.get("retail_density", 50)
demographics = signals.get("family_friendly", 50)
# Calculate opportunity score
opportunity = (foot_traffic * 0.4 + demographics * 0.3 + (100 - competition) * 0.3)
return DecisionRecommendation(
decision_type=DecisionType.ESTABLISHMENT,
stakeholder=stakeholder,
recommendation=f"Establishment opportunity score: {opportunity:.0f}/100. Foot traffic: {foot_traffic}, Competition: {competition}.",
expected_impact=opportunity * 0.85,
confidence=0.6,
cost_estimate_usd=300000,
timeline_months=8,
supporting_data=[
{"signal": "pedestrian_flow", "value": foot_traffic},
{"signal": "retail_density", "value": competition},
{"signal": "family_friendly", "value": demographics}
],
risks=["Competition increase", "Changing demographics"]
)
def _risk_recommendation(
self,
stakeholder: Stakeholder,
signals: Dict[str, float],
constraints: Optional[Dict],
visual_evidence: Optional[Dict] = None
) -> DecisionRecommendation:
"""Generate risk mitigation recommendation"""
risk_score = signals.get("infrastructure_reliability", 50)
failure_probability = 100 - risk_score
return DecisionRecommendation(
decision_type=DecisionType.RISK_MITIGATION,
stakeholder=stakeholder,
recommendation=f"Risk mitigation needed. Failure probability: {failure_probability:.0f}%. Current reliability: {risk_score}/100.",
expected_impact=failure_probability * 0.9,
confidence=0.8,
cost_estimate_usd=200000,
timeline_months=6,
supporting_data=[
{"signal": "infrastructure_reliability", "value": risk_score},
{"signal": "failure_probability", "value": failure_probability}
],
risks=["Unexpected failures", "Cost escalation"]
)
def prioritize_investments(
self,
stakeholder: Stakeholder,
locations: List[Dict],
budget_usd: float
) -> Dict:
"""
Prioritize investments across multiple locations
Returns:
Prioritized list with ROI estimates
"""
opportunities = []
for location in locations:
signals = location.get("signals", {})
# Calculate investment attractiveness
attractiveness = (
signals.get("property_value", 50) * 0.3 +
signals.get("growth_potential", 50) * 0.3 +
signals.get("safety_index", 50) * 0.2 +
signals.get("connectivity", 50) * 0.2
)
# Estimate ROI
estimated_roi = attractiveness * 0.5 # Simplified
opportunities.append({
"location_id": location.get("id"),
"location_name": location.get("name"),
"attractiveness": round(attractiveness, 1),
"estimated_roi": round(estimated_roi, 1),
"recommended_investment": min(budget_usd * 0.2, 1000000),
"priority": "high" if attractiveness > 75 else "medium" if attractiveness > 50 else "low"
})
# Sort by attractiveness
opportunities.sort(key=lambda x: x["attractiveness"], reverse=True)
# Allocate budget
allocated = 0
for opp in opportunities:
if allocated + opp["recommended_investment"] <= budget_usd:
opp["allocated"] = opp["recommended_investment"]
allocated += opp["allocated"]
else:
remaining = budget_usd - allocated
if remaining > 0:
opp["allocated"] = remaining
allocated += remaining
else:
opp["allocated"] = 0
return {
"stakeholder": stakeholder.value,
"total_budget": budget_usd,
"allocated": allocated,
"opportunities": opportunities
}
# Example usage
def example_decisions():
"""Example: Generate decision recommendations"""
engine = DecisionEngine()
# Signals for a location
signals = {
"safety_index": 45,
"lighting": 35,
"maintenance_quality": 40,
"property_value": 60,
"growth_potential": 70,
"pedestrian_flow": 80,
"retail_density": 65,
"family_friendly": 55,
"infrastructure_reliability": 50
}
# Municipality recommendations
print("=== Municipality Decisions ===")
recs = engine.recommend(Stakeholder.MUNICIPALITY, signals, {"budget_usd": 500000})
for rec in recs:
print(f"\n{rec.decision_type.value.upper()}")
print(f" Recommendation: {rec.recommendation}")
print(f" Expected impact: {rec.expected_impact}")
print(f" Cost: ${rec.cost_estimate_usd:,}")
print(f" Timeline: {rec.timeline_months} months")
# Property owner recommendations
print("\n=== Property Owner Decisions ===")
recs = engine.recommend(Stakeholder.PROPERTY_OWNER, signals, {"budget_usd": 1000000})
for rec in recs:
print(f"\n{rec.decision_type.value.upper()}")
print(f" Recommendation: {rec.recommendation}")
print(f" Expected impact: {rec.expected_impact}")
# Prioritize investments
print("\n=== Investment Prioritization ===")
locations = [
{"id": "LOC-001", "name": "Downtown", "signals": {"property_value": 80, "growth_potential": 75, "safety_index": 70}},
{"id": "LOC-002", "name": "Suburb A", "signals": {"property_value": 60, "growth_potential": 85, "safety_index": 80}},
{"id": "LOC-003", "name": "Industrial", "signals": {"property_value": 40, "growth_potential": 50, "safety_index": 45}}
]
result = engine.prioritize_investments(Stakeholder.PROPERTY_OWNER, locations, 2000000)
print(f"Budget: ${result['total_budget']:,}")
print(f"Allocated: ${result['allocated']:,}")
print("\nPriorities:")
for opp in result["opportunities"]:
print(f" {opp['location_name']}: {opp['priority']} (ROI: {opp['estimated_roi']}, Allocated: ${opp.get('allocated', 0):,})")
return engine
if __name__ == '__main__':
example_decisions()