Add AICL example: 37_crm_platform.aicl
Browse files
data/aicl/examples/37_crm_platform.aicl
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AICL Example: CRM Platform
|
| 2 |
+
# Comprehensive customer relationship management platform with contact management, sales pipeline, marketing automation, analytics, and third-party integration capabilities
|
| 3 |
+
|
| 4 |
+
Goal: Deliver a CRM platform that unifies customer data across all touchpoints, accelerates sales velocity through intelligent pipeline management, automates marketing campaigns with behavioral triggers, and provides actionable analytics for revenue optimization and customer lifetime value maximization
|
| 5 |
+
|
| 6 |
+
Constraint: All customer data must respect consent preferences and honor opt-out requests within 24 hours across all channels
|
| 7 |
+
Constraint: Sales pipeline stage transitions must enforce required data completeness before advancement
|
| 8 |
+
Constraint: Marketing automation must throttle outbound communications per contact to prevent spam fatigue
|
| 9 |
+
Constraint: API integrations must implement circuit breaker patterns to prevent downstream failures from affecting core CRM operations
|
| 10 |
+
Constraint: Reporting queries must not impact transactional system performance during business hours
|
| 11 |
+
|
| 12 |
+
Risk: Data deduplication failure creating fragmented customer profiles across modules
|
| 13 |
+
Recovery: Execute automated merge detection using fuzzy matching on email, phone, and company attributes; flag unresolved duplicates for manual review; preserve activity history from both records during merge
|
| 14 |
+
|
| 15 |
+
Risk: Sales pipeline manipulation via unauthorized stage regression or forecast inflation
|
| 16 |
+
Recovery: Enforce immutable audit log for all pipeline changes; detect anomalous stage movement patterns; alert sales operations on suspicious modifications; enable one-click revert to previous state
|
| 17 |
+
|
| 18 |
+
Risk: Marketing campaign blowback from segment misconfiguration sending to wrong audience
|
| 19 |
+
Recovery: Implement pre-send preview with recipient count validation; require dual approval for campaigns exceeding threshold; enable immediate kill switch to halt in-progress sends; auto-generate apology workflow for affected contacts
|
| 20 |
+
|
| 21 |
+
Risk: Integration API credential exposure or unauthorized third-party data access
|
| 22 |
+
Recovery: Rotate all affected API keys immediately; audit access logs for unauthorized data exfiltration; notify affected customers per breach disclosure requirements; enforce scoped token permissions going forward
|
| 23 |
+
|
| 24 |
+
Risk: Analytics report inaccuracy from stale or incorrectly joined data across modules
|
| 25 |
+
Recovery: Implement data freshness checks with timestamp validation; flag reports using data older than threshold; provide cache invalidation trigger; regenerate reports from source on demand
|
| 26 |
+
|
| 27 |
+
Risk: Lead assignment bias causing uneven distribution and revenue impact
|
| 28 |
+
Recovery: Monitor assignment distribution metrics in real-time; detect deviation from round-robin or territory rules; auto-rebalance queued assignments; alert sales manager on persistent imbalance
|
| 29 |
+
|
| 30 |
+
Layer: ContactManagement
|
| 31 |
+
SubLayer: ContactRecords
|
| 32 |
+
SubLayer: CompanyAccounts
|
| 33 |
+
SubLayer: ActivityTracking
|
| 34 |
+
SubLayer: DataEnrichment
|
| 35 |
+
|
| 36 |
+
Layer: SalesPipeline
|
| 37 |
+
SubLayer: LeadManagement
|
| 38 |
+
SubLayer: OpportunityTracking
|
| 39 |
+
SubLayer: ForecastManagement
|
| 40 |
+
SubLayer: DealRoom
|
| 41 |
+
|
| 42 |
+
Layer: MarketingAutomation
|
| 43 |
+
SubLayer: CampaignBuilder
|
| 44 |
+
SubLayer: SegmentEngine
|
| 45 |
+
SubLayer: EmailOrchestration
|
| 46 |
+
SubLayer: LeadScoring
|
| 47 |
+
|
| 48 |
+
Layer: Analytics
|
| 49 |
+
SubLayer: RevenueAnalytics
|
| 50 |
+
SubLayer: FunnelAnalytics
|
| 51 |
+
SubLayer: CustomerHealth
|
| 52 |
+
SubLayer: PredictiveInsights
|
| 53 |
+
|
| 54 |
+
Layer: Integration
|
| 55 |
+
SubLayer: APIGateway
|
| 56 |
+
SubLayer: ConnectorFramework
|
| 57 |
+
SubLayer: DataSync
|
| 58 |
+
SubLayer: WebhookRouter
|
| 59 |
+
|
| 60 |
+
Validation: Contact records must have at least one validated communication channel (email or phone)
|
| 61 |
+
Validation: Opportunity amounts must be positive and currency must match account billing currency
|
| 62 |
+
Validation: Marketing campaign segments must contain at least one consented contact before activation
|
| 63 |
+
Validation: Sales forecast rollups must reconcile with individual opportunity projections
|
| 64 |
+
Validation: API integration tokens must have explicit scope declarations and expiration policies
|
| 65 |
+
Validation: Lead assignment must verify active sales representative with valid territory coverage
|
| 66 |
+
|
| 67 |
+
Entity Contact
|
| 68 |
+
contactId: string
|
| 69 |
+
firstName: string
|
| 70 |
+
lastName: string
|
| 71 |
+
email: string
|
| 72 |
+
phone: string
|
| 73 |
+
companyId: string
|
| 74 |
+
jobTitle: string
|
| 75 |
+
lifecycleStage: string
|
| 76 |
+
leadScore: float
|
| 77 |
+
lastActivityDate: datetime
|
| 78 |
+
consentStatus: dict
|
| 79 |
+
customFields: dict
|
| 80 |
+
owner: string
|
| 81 |
+
|
| 82 |
+
Entity Opportunity
|
| 83 |
+
opportunityId: string
|
| 84 |
+
dealName: string
|
| 85 |
+
accountId: string
|
| 86 |
+
contactId: string
|
| 87 |
+
amount: float
|
| 88 |
+
currencyCode: string
|
| 89 |
+
stage: string
|
| 90 |
+
probability: float
|
| 91 |
+
closeDate: datetime
|
| 92 |
+
owner: string
|
| 93 |
+
pipeline: string
|
| 94 |
+
products: list
|
| 95 |
+
competitors: list
|
| 96 |
+
activityCount: integer
|
| 97 |
+
|
| 98 |
+
Entity Campaign
|
| 99 |
+
campaignId: string
|
| 100 |
+
campaignName: string
|
| 101 |
+
campaignType: string
|
| 102 |
+
status: string
|
| 103 |
+
startDate: datetime
|
| 104 |
+
endDate: datetime
|
| 105 |
+
targetSegment: string
|
| 106 |
+
budgetAllocated: float
|
| 107 |
+
budgetSpent: float
|
| 108 |
+
channelMix: dict
|
| 109 |
+
goals: dict
|
| 110 |
+
approvalStatus: string
|
| 111 |
+
sendsCompleted: integer
|
| 112 |
+
|
| 113 |
+
Entity SalesForecast
|
| 114 |
+
forecastId: string
|
| 115 |
+
period: string
|
| 116 |
+
owner: string
|
| 117 |
+
pipeline: string
|
| 118 |
+
committedAmount: float
|
| 119 |
+
bestCaseAmount: float
|
| 120 |
+
worstCaseAmount: float
|
| 121 |
+
weightedPipeline: float
|
| 122 |
+
closedWonAmount: float
|
| 123 |
+
forecastAccuracy: float
|
| 124 |
+
lastUpdated: datetime
|
| 125 |
+
adjustmentReason: string
|
| 126 |
+
|
| 127 |
+
Entity IntegrationConnector
|
| 128 |
+
connectorId: string
|
| 129 |
+
connectorName: string
|
| 130 |
+
connectorType: string
|
| 131 |
+
endpoint: string
|
| 132 |
+
authMethod: string
|
| 133 |
+
tokenScope: list
|
| 134 |
+
syncFrequency: string
|
| 135 |
+
lastSyncTime: datetime
|
| 136 |
+
status: string
|
| 137 |
+
errorCount: integer
|
| 138 |
+
rateLimit: integer
|
| 139 |
+
fieldMappings: dict
|
| 140 |
+
|
| 141 |
+
Entity ActivityLog
|
| 142 |
+
activityId: string
|
| 143 |
+
entityType: string
|
| 144 |
+
entityId: string
|
| 145 |
+
activityType: string
|
| 146 |
+
description: string
|
| 147 |
+
performedBy: string
|
| 148 |
+
performedAt: datetime
|
| 149 |
+
channel: string
|
| 150 |
+
outcome: string
|
| 151 |
+
duration: integer
|
| 152 |
+
linkedRecords: list
|
| 153 |
+
|
| 154 |
+
Behavior CreateOpportunity
|
| 155 |
+
Input: accountId: string, contactId: string, dealName: string, amount: float, stage: string, owner: string
|
| 156 |
+
Output: opportunity: Opportunity
|
| 157 |
+
Action: Validate account and contact existence; check territory alignment with owner; calculate initial probability based on stage; validate amount and currency; persist opportunity; trigger pipeline stage automation; emit opportunity created event; assign activity sequence; update forecast projection
|
| 158 |
+
|
| 159 |
+
Behavior ExecuteCampaign
|
| 160 |
+
Input: campaignId: string, approvalToken: string
|
| 161 |
+
Output: executionResult: dict
|
| 162 |
+
Action: Validate campaign approval status; resolve target segment membership; check consent compliance per contact; apply communication throttling rules; schedule send batches; execute multi-channel delivery; track send and engagement events; update campaign metrics in real-time; emit campaign activated event
|
| 163 |
+
|
| 164 |
+
Behavior ScoreLead
|
| 165 |
+
Input: contactId: string, scoringModel: string
|
| 166 |
+
Output: leadScore: float
|
| 167 |
+
Action: Load contact demographic and firmographic data; aggregate behavioral signals across touchpoints; apply scoring model weights; compute composite lead score; determine lifecycle stage transition eligibility; update contact record; emit lead score changed event; trigger assignment or nurture path based on score threshold
|
| 168 |
+
|
| 169 |
+
Behavior GenerateForecast
|
| 170 |
+
Input: period: string, owner: string, pipeline: string
|
| 171 |
+
Output: forecast: SalesForecast
|
| 172 |
+
Action: Aggregate open opportunities by stage; apply stage-based probability weighting; calculate committed best case and worst case scenarios; incorporate historical forecast accuracy adjustments; validate against quota targets; persist forecast; emit forecast generated event; push to analytics dashboard
|
| 173 |
+
|
| 174 |
+
Behavior SyncIntegrationData
|
| 175 |
+
Input: connectorId: string, direction: string, entityTypes: list
|
| 176 |
+
Output: syncResult: dict
|
| 177 |
+
Action: Retrieve connector configuration and field mappings; check rate limit capacity; execute data extraction from source; transform data per mapping rules; validate data integrity; apply conflict resolution strategy; persist synced records; update last sync timestamp; emit sync completed event; log sync statistics
|
| 178 |
+
|
| 179 |
+
Behavior MergeContacts
|
| 180 |
+
Input: primaryContactId: string, duplicateContactId: string, mergeStrategy: dict
|
| 181 |
+
Output: mergedContact: Contact
|
| 182 |
+
Action: Validate both contacts exist; determine field-level winner per merge strategy; consolidate activity history; reassign all related records to primary; archive duplicate record; emit contact merged event; update segmentation memberships; recalculate lead score; notify contact owner of merge
|
| 183 |
+
|
| 184 |
+
Condition:
|
| 185 |
+
When contact.leadScore exceeds hotThreshold AND contact.lifecycleStage is not yet "opportunity"
|
| 186 |
+
Then auto-promote to sales qualified lead; assign to territory owner; create opportunity draft; trigger sales notification sequence; log promotion event in activity timeline
|
| 187 |
+
|
| 188 |
+
Condition:
|
| 189 |
+
When opportunity.closeDate is within 3 days AND opportunity.stage is not "closed_won" or "closed_lost"
|
| 190 |
+
Then escalate to sales manager; add to deal review queue; send reminder to opportunity owner; adjust probability weighting in forecast; flag for pipeline review
|
| 191 |
+
|
| 192 |
+
Condition:
|
| 193 |
+
When campaign.budgetSpent exceeds campaign.budgetAllocated by more than 5 percent
|
| 194 |
+
Then pause active campaign sends; notify marketing operations; generate budget overrun report; require explicit approval to resume; adjust remaining segment volumes
|
| 195 |
+
|
| 196 |
+
Condition:
|
| 197 |
+
When integrationConnector.errorCount exceeds 5 consecutive failures
|
| 198 |
+
Then circuit breaker opens and disables connector; notify integration admin; switch to fallback data source if available; log diagnostic information; enable manual reactivation after health check
|
| 199 |
+
|
| 200 |
+
Condition:
|
| 201 |
+
When salesForecast.forecastAccuracy drops below 60 percent for 2 consecutive periods
|
| 202 |
+
Then flag forecast for review by sales operations; trigger pipeline inspection workflow; suggest probability recalibration; adjust weighting factors; notify forecast owner
|
| 203 |
+
|
| 204 |
+
Event:
|
| 205 |
+
On OpportunityStageChanged
|
| 206 |
+
Action: Update pipeline analytics; recalculate forecast projections; trigger stage-specific automation sequence; update contact lifecycle stage if applicable; notify deal team; log stage transition in activity timeline
|
| 207 |
+
|
| 208 |
+
Event:
|
| 209 |
+
On CampaignEmailEngaged
|
| 210 |
+
Action: Update contact engagement score; record interaction in activity log; trigger follow-up nurture sequence if applicable; update segment membership; feed real-time campaign performance dashboard; increment engagement counter
|
| 211 |
+
|
| 212 |
+
Event:
|
| 213 |
+
On LeadScoreThresholdCrossed
|
| 214 |
+
Action: Evaluate lifecycle stage transition eligibility; trigger assignment routing if sales qualified; add to appropriate nurture track if not; notify assigned sales rep; update pipeline health metrics; log threshold event
|
| 215 |
+
|
| 216 |
+
Event:
|
| 217 |
+
On IntegrationSyncFailed
|
| 218 |
+
Action: Log error with diagnostic context; increment error counter; evaluate circuit breaker threshold; notify integration admin if threshold approached; queue retry with exponential backoff; preserve data consistency with transaction boundary
|
| 219 |
+
|
| 220 |
+
Event:
|
| 221 |
+
On ContactMerged
|
| 222 |
+
Action: Update all segment memberships; recalculate aggregate analytics; refresh search index; archive duplicate record; notify downstream integrations; update activity timeline with merge notation
|
| 223 |
+
|
| 224 |
+
Parallel:
|
| 225 |
+
- Contact data enrichment from third-party providers
|
| 226 |
+
- Lead scoring model batch computation
|
| 227 |
+
- Campaign delivery execution across channels
|
| 228 |
+
- Forecast aggregation and rollup processing
|
| 229 |
+
- Integration data synchronization cycles
|
| 230 |
+
|
| 231 |
+
Optimize: Sales pipeline velocity and forecast accuracy
|
| 232 |
+
Priority: Data integrity and consent compliance over campaign throughput
|
| 233 |
+
Priority: Sales representative productivity over administrative completeness
|
| 234 |
+
Priority: Customer experience personalization over batch efficiency
|
| 235 |
+
Priority: Real-time engagement responsiveness over resource conservation
|
| 236 |
+
|
| 237 |
+
Learn: Lead scoring model accuracy
|
| 238 |
+
Goal: Achieve lead-to-opportunity conversion prediction AUC above 0.82
|
| 239 |
+
Adapt: Scoring model feature weights and thresholds
|
| 240 |
+
Based: Historical conversion outcomes, engagement pattern analysis, and demographic correlation
|
| 241 |
+
|
| 242 |
+
Learn: Optimal campaign send timing
|
| 243 |
+
Goal: Increase email open rates by 25 percent through timing optimization
|
| 244 |
+
Adapt: Per-contact send time scheduling
|
| 245 |
+
Based: Historical engagement timestamps, timezone patterns, and channel preference signals
|
| 246 |
+
|
| 247 |
+
Learn: Forecast prediction precision
|
| 248 |
+
Goal: Reduce forecast deviation from actual results to under 10 percent
|
| 249 |
+
Adapt: Stage probability weightings and historical adjustment factors
|
| 250 |
+
Based: Win/loss patterns, close date accuracy trends, and pipeline velocity metrics
|
| 251 |
+
|
| 252 |
+
Learn: Customer churn prediction
|
| 253 |
+
Goal: Identify at-risk accounts 60 days before renewal with 75 percent recall
|
| 254 |
+
Adapt: Customer health score calculation
|
| 255 |
+
Based: Usage frequency decline, support ticket escalation, engagement drop-off, and competitive signals
|
| 256 |
+
|
| 257 |
+
Security:
|
| 258 |
+
Encrypt: All customer personally identifiable information including email, phone, and address
|
| 259 |
+
Encrypt: Sales opportunity amounts and deal terms at rest and in transit
|
| 260 |
+
Encrypt: Integration API tokens and authentication credentials
|
| 261 |
+
Protect: Campaign execution endpoints with multi-level approval gates
|
| 262 |
+
Protect: Contact merge operations with audit logging and undo capability
|
| 263 |
+
Protect: Forecast modification with change tracking and manager visibility
|
| 264 |
+
Protect: Integration connector configurations from unauthorized modification
|
| 265 |
+
|
| 266 |
+
Native: python
|
| 267 |
+
{
|
| 268 |
+
from datetime import datetime, timedelta
|
| 269 |
+
from typing import Dict, List, Optional
|
| 270 |
+
|
| 271 |
+
class LeadScoringEngine:
|
| 272 |
+
"""ML-driven lead scoring with behavioral and demographic signal fusion."""
|
| 273 |
+
|
| 274 |
+
def __init__(self, model_config: Dict):
|
| 275 |
+
self.weights = model_config.get("weights", {})
|
| 276 |
+
self.thresholds = model_config.get("thresholds", {})
|
| 277 |
+
self.decay_factor = model_config.get("decay_factor", 0.95)
|
| 278 |
+
|
| 279 |
+
def compute_score(self, contact: Dict, activities: List[Dict]) -> float:
|
| 280 |
+
demographic_score = self._demographic_score(contact)
|
| 281 |
+
behavioral_score = self._behavioral_score(activities)
|
| 282 |
+
engagement_recency = self._recency_multiplier(activities)
|
| 283 |
+
|
| 284 |
+
composite = (
|
| 285 |
+
demographic_score * self.weights.get("demographic", 0.3) +
|
| 286 |
+
behavioral_score * self.weights.get("behavioral", 0.5) +
|
| 287 |
+
engagement_recency * self.weights.get("recency", 0.2)
|
| 288 |
+
)
|
| 289 |
+
return round(min(max(composite, 0), 100), 2)
|
| 290 |
+
|
| 291 |
+
def _demographic_score(self, contact: Dict) -> float:
|
| 292 |
+
score = 50.0
|
| 293 |
+
if contact.get("job_title") in ["VP", "Director", "C-Suite"]:
|
| 294 |
+
score += 20
|
| 295 |
+
if contact.get("company_size", 0) > 500:
|
| 296 |
+
score += 15
|
| 297 |
+
if contact.get("industry") in self.weights.get("target_industries", []):
|
| 298 |
+
score += 15
|
| 299 |
+
return min(score, 100)
|
| 300 |
+
|
| 301 |
+
def _behavioral_score(self, activities: List[Dict]) -> float:
|
| 302 |
+
if not activities:
|
| 303 |
+
return 0.0
|
| 304 |
+
score = 0.0
|
| 305 |
+
for act in activities[-20:]:
|
| 306 |
+
weight = self.weights.get(f"activity_{act['type']}", 1.0)
|
| 307 |
+
score += weight * 10
|
| 308 |
+
return min(score, 100)
|
| 309 |
+
|
| 310 |
+
def _recency_multiplier(self, activities: List[Dict]) -> float:
|
| 311 |
+
if not activities:
|
| 312 |
+
return 0.0
|
| 313 |
+
latest = max(a["timestamp"] for a in activities)
|
| 314 |
+
days_since = (datetime.utcnow() - latest).days
|
| 315 |
+
return max(0, 100 * (self.decay_factor ** days_since))
|
| 316 |
+
|
| 317 |
+
|
| 318 |
+
class CircuitBreaker:
|
| 319 |
+
"""Protects CRM integrations from cascading failures."""
|
| 320 |
+
|
| 321 |
+
def __init__(self, failure_threshold: int = 5, recovery_timeout: int = 300):
|
| 322 |
+
self.failure_threshold = failure_threshold
|
| 323 |
+
self.recovery_timeout = recovery_timeout
|
| 324 |
+
self.failure_count = 0
|
| 325 |
+
self.state = "CLOSED"
|
| 326 |
+
self.last_failure_time = None
|
| 327 |
+
|
| 328 |
+
def execute(self, operation, *args, **kwargs):
|
| 329 |
+
if self.state == "OPEN":
|
| 330 |
+
if (datetime.utcnow() - self.last_failure_time).seconds > self.recovery_timeout:
|
| 331 |
+
self.state = "HALF_OPEN"
|
| 332 |
+
else:
|
| 333 |
+
raise CircuitBreakerOpenError("Circuit breaker is open")
|
| 334 |
+
|
| 335 |
+
try:
|
| 336 |
+
result = operation(*args, **kwargs)
|
| 337 |
+
self._on_success()
|
| 338 |
+
return result
|
| 339 |
+
except Exception as e:
|
| 340 |
+
self._on_failure()
|
| 341 |
+
raise
|
| 342 |
+
|
| 343 |
+
def _on_success(self):
|
| 344 |
+
self.failure_count = 0
|
| 345 |
+
self.state = "CLOSED"
|
| 346 |
+
|
| 347 |
+
def _on_failure(self):
|
| 348 |
+
self.failure_count += 1
|
| 349 |
+
self.last_failure_time = datetime.utcnow()
|
| 350 |
+
if self.failure_count >= self.failure_threshold:
|
| 351 |
+
self.state = "OPEN"
|
| 352 |
+
}
|