petter2025 commited on
Commit
9537d6e
·
verified ·
1 Parent(s): 0b9fac2

Update infrastructure/healing_intent.py

Browse files
Files changed (1) hide show
  1. infrastructure/healing_intent.py +174 -861
infrastructure/healing_intent.py CHANGED
@@ -1,33 +1,5 @@
1
- # agentic_reliability_framework/infrastructure/healing_intent.py
2
  """
3
  Healing Intent - OSS creates, Enterprise executes
4
- Enhanced with probabilistic confidence, risk scoring, cost projection,
5
- and full audit trail integration.
6
-
7
- This is the core contract between OSS advisory and Enterprise execution.
8
- All intents are immutable and self-validating, ensuring consistency
9
- across the OSS/Enterprise boundary.
10
-
11
- The design follows ARF governing principles:
12
- - OSS = advisory intelligence only
13
- - Enterprise = governed execution
14
- - Immutable contracts between layers
15
- - Full provenance and explainability
16
- - Probabilistic uncertainty quantification
17
-
18
- Copyright 2025 Juan Petter
19
-
20
- Licensed under the Apache License, Version 2.0 (the "License");
21
- you may not use this file except in compliance with the License.
22
- You may obtain a copy of the License at
23
-
24
- http://www.apache.org/licenses/LICENSE-2.0
25
-
26
- Unless required by applicable law or agreed to in writing, software
27
- distributed under the License is distributed on an "AS IS" BASIS,
28
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29
- See the License for the specific language governing permissions and
30
- limitations under the License.
31
  """
32
 
33
  from dataclasses import dataclass, field, asdict
@@ -40,9 +12,8 @@ import uuid
40
  from enum import Enum
41
  import numpy as np
42
 
43
- # Import from local infrastructure modules
44
  from .intents import InfrastructureIntent
45
- from ..constants import (
46
  OSS_EDITION,
47
  OSS_LICENSE,
48
  ENTERPRISE_UPGRADE_URL,
@@ -57,36 +28,21 @@ from ..constants import (
57
  OSSBoundaryError,
58
  )
59
 
60
-
61
- class HealingIntentError(Exception):
62
- """Base exception for HealingIntent errors"""
63
- pass
64
-
65
-
66
- class SerializationError(HealingIntentError):
67
- """Error during serialization/deserialization"""
68
- pass
69
-
70
-
71
- class ValidationError(HealingIntentError):
72
- """Error during intent validation"""
73
- pass
74
-
75
 
76
  class IntentSource(str, Enum):
77
- """Source of the healing intent - matches old ARF patterns"""
78
  OSS_ANALYSIS = "oss_analysis"
79
  HUMAN_OVERRIDE = "human_override"
80
- AUTOMATED_LEARNING = "automated_learning" # Enterprise only
81
- SCHEDULED_ACTION = "scheduled_action" # Enterprise only
82
- RAG_SIMILARITY = "rag_similarity" # From RAG graph similarity
83
- INFRASTRUCTURE_ANALYSIS = "infrastructure_analysis" # From infra module
84
- POLICY_VIOLATION = "policy_violation" # From policy engine
85
- COST_OPTIMIZATION = "cost_optimization" # From cost analysis
86
-
87
 
88
  class IntentStatus(str, Enum):
89
- """Status of the healing intent - enhanced with partial states"""
90
  CREATED = "created"
91
  PENDING_EXECUTION = "pending_execution"
92
  EXECUTING = "executing"
@@ -102,27 +58,13 @@ class IntentStatus(str, Enum):
102
  APPROVED = "approved"
103
  APPROVED_WITH_OVERRIDES = "approved_with_overrides"
104
 
105
-
106
  class RecommendedAction(str, Enum):
107
- """
108
- Advisory recommendation from the OSS engine.
109
- Matches the infrastructure module's RecommendedAction.
110
- """
111
  APPROVE = "approve"
112
  DENY = "deny"
113
  ESCALATE = "escalate"
114
- DEFER = "defer" # Wait for more information
115
-
116
 
117
  class ConfidenceDistribution:
118
- """
119
- Probabilistic confidence representation.
120
-
121
- Instead of a single confidence score, this represents a distribution
122
- of possible confidence values, allowing for uncertainty quantification.
123
- Matches patterns from the risk_engine.py module.
124
- """
125
-
126
  def __init__(self, mean: float, std: float = 0.05, samples: Optional[List[float]] = None):
127
  self.mean = max(0.0, min(mean, 1.0))
128
  self.std = max(0.0, min(std, 0.5))
@@ -130,26 +72,21 @@ class ConfidenceDistribution:
130
 
131
  @property
132
  def p5(self) -> float:
133
- """5th percentile (pessimistic)"""
134
  return float(np.percentile(self._samples, 5))
135
 
136
  @property
137
  def p50(self) -> float:
138
- """50th percentile (median)"""
139
  return float(np.percentile(self._samples, 50))
140
 
141
  @property
142
  def p95(self) -> float:
143
- """95th percentile (optimistic)"""
144
  return float(np.percentile(self._samples, 95))
145
 
146
  @property
147
  def confidence_interval(self) -> Tuple[float, float]:
148
- """95% confidence interval"""
149
  return (self.p5, self.p95)
150
 
151
  def to_dict(self) -> Dict[str, float]:
152
- """Serialize to dictionary"""
153
  return {
154
  "mean": self.mean,
155
  "std": self.std,
@@ -160,180 +97,97 @@ class ConfidenceDistribution:
160
 
161
  @classmethod
162
  def from_dict(cls, data: Dict[str, float]) -> "ConfidenceDistribution":
163
- """Deserialize from dictionary"""
164
- return cls(
165
- mean=data["mean"],
166
- std=data.get("std", 0.05),
167
- samples=None # Will regenerate on access
168
- )
169
 
170
  def __repr__(self) -> str:
171
  return f"ConfidenceDistribution(mean={self.mean:.3f}, 95% CI=[{self.p5:.3f}, {self.p95:.3f}])"
172
 
173
-
174
  @dataclass(frozen=True, slots=True)
175
  class HealingIntent:
176
- """
177
- OSS-generated healing recommendation for Enterprise execution
178
-
179
- Enhanced with:
180
- - Probabilistic confidence distributions
181
- - Risk score and cost projection integration
182
- - Decision tree tracking for explainability
183
- - Human override audit trail
184
- - Partial execution support
185
- - Integration with infrastructure governance module
186
- - Full backward compatibility with old ARF patterns
187
-
188
- This is the clean boundary between OSS intelligence and Enterprise execution:
189
- - OSS creates HealingIntent through analysis (advisory only)
190
- - Enterprise executes HealingIntent through execution gateway
191
- - Immutable (frozen) to ensure consistency across OSS→Enterprise handoff
192
- """
193
-
194
- # === CORE ACTION FIELDS (Sent to Enterprise) ===
195
- action: str # Tool name, e.g., "restart_container", "provision_vm"
196
- component: str # Target component or resource
197
- parameters: Dict[str, Any] = field(default_factory=dict) # Action parameters
198
- justification: str = "" # OSS reasoning chain
199
-
200
- # === CONFIDENCE & METADATA ===
201
- confidence: float = 0.85 # OSS confidence score (0.0 to 1.0)
202
- confidence_distribution: Optional[Dict[str, float]] = None # Probabilistic confidence
203
- incident_id: str = "" # Source incident identifier
204
- detected_at: float = field(default_factory=time.time) # When OSS detected
205
-
206
- # === RISK AND COST INTEGRATION ===
207
- risk_score: Optional[float] = None # From risk engine (0-1)
208
- risk_factors: Optional[Dict[str, float]] = None # Breakdown by factor
209
- cost_projection: Optional[float] = None # Estimated cost impact
210
- cost_confidence_interval: Optional[Tuple[float, float]] = None # 95% CI
211
- recommended_action: Optional[RecommendedAction] = None # From risk engine
212
-
213
- # === DECISION TRACKING ===
214
- decision_tree: Optional[List[Dict[str, Any]]] = None # How decision was reached
215
- alternative_actions: Optional[List[Dict[str, Any]]] = None # Alternatives considered
216
- risk_profile: Optional[str] = None # Risk tolerance used (conservative/moderate/aggressive)
217
-
218
- # === OSS ANALYSIS CONTEXT (Stays in OSS) ===
219
  reasoning_chain: Optional[List[Dict[str, Any]]] = None
220
  similar_incidents: Optional[List[Dict[str, Any]]] = None
221
  rag_similarity_score: Optional[float] = None
222
  source: IntentSource = IntentSource.OSS_ANALYSIS
223
-
224
- # === IMMUTABLE IDENTIFIERS ===
225
  intent_id: str = field(default_factory=lambda: f"intent_{uuid.uuid4().hex[:16]}")
226
  created_at: float = field(default_factory=time.time)
227
-
228
- # === EXECUTION METADATA (Set by Enterprise) ===
229
  status: IntentStatus = IntentStatus.CREATED
230
  execution_id: Optional[str] = None
231
  executed_at: Optional[float] = None
232
  execution_result: Optional[Dict[str, Any]] = None
233
  enterprise_metadata: Dict[str, Any] = field(default_factory=dict)
234
-
235
- # === HUMAN INTERACTION TRACKING ===
236
- human_overrides: List[Dict[str, Any]] = field(default_factory=list) # Audit trail
237
- approvals: List[Dict[str, Any]] = field(default_factory=list) # Who approved what
238
- comments: List[Dict[str, Any]] = field(default_factory=list) # Human comments
239
-
240
- # === OSS EDITION METADATA ===
241
  oss_edition: str = OSS_EDITION
242
  oss_license: str = OSS_LICENSE
243
- requires_enterprise: bool = True # Always True for OSS-generated intents
244
- execution_allowed: bool = EXECUTION_ALLOWED # From OSS constants
245
-
246
- # === INFRASTRUCTURE INTEGRATION ===
247
- infrastructure_intent_id: Optional[str] = None # Link to infrastructure intent if any
248
- policy_violations: List[str] = field(default_factory=list) # From policy engine
249
- infrastructure_intent: Optional[Dict[str, Any]] = None # Original infrastructure intent
250
 
251
- # Class constants for validation
252
  MIN_CONFIDENCE: ClassVar[float] = 0.0
253
  MAX_CONFIDENCE: ClassVar[float] = 1.0
254
  MAX_JUSTIFICATION_LENGTH: ClassVar[int] = 5000
255
  MAX_PARAMETERS_SIZE: ClassVar[int] = 100
256
  MAX_SIMILAR_INCIDENTS: ClassVar[int] = MAX_SIMILARITY_CACHE
257
- VERSION: ClassVar[str] = "2.0.0" # Major bump for probabilistic features
258
 
259
  def __post_init__(self) -> None:
260
- """Validate HealingIntent after initialization with OSS boundaries"""
261
  self._validate_oss_boundaries()
262
  self._validate_risk_integration()
263
 
264
  def _validate_oss_boundaries(self) -> None:
265
- """Validate all fields against OSS limits"""
266
  errors: List[str] = []
267
-
268
- # Validate confidence range
269
  if not (self.MIN_CONFIDENCE <= self.confidence <= self.MAX_CONFIDENCE):
270
- errors.append(
271
- f"Confidence must be between {self.MIN_CONFIDENCE} and "
272
- f"{self.MAX_CONFIDENCE}, got {self.confidence}"
273
- )
274
-
275
- # Validate justification length
276
  if len(self.justification) > self.MAX_JUSTIFICATION_LENGTH:
277
- errors.append(
278
- f"Justification exceeds max length {self.MAX_JUSTIFICATION_LENGTH}"
279
- )
280
-
281
- # Validate action and component
282
  if not self.action or not self.action.strip():
283
  errors.append("Action cannot be empty")
284
-
285
  if not self.component or not self.component.strip():
286
  errors.append("Component cannot be empty")
287
-
288
- # Validate parameters size
289
  if len(self.parameters) > self.MAX_PARAMETERS_SIZE:
290
- errors.append(
291
- f"Too many parameters: {len(self.parameters)} > {self.MAX_PARAMETERS_SIZE}"
292
- )
293
-
294
- # Validate parameters are JSON serializable
295
  try:
296
  json.dumps(self.parameters)
297
  except (TypeError, ValueError) as e:
298
  errors.append(f"Parameters must be JSON serializable: {e}")
299
-
300
- # Validate similar incidents
301
- if self.similar_incidents:
302
- if len(self.similar_incidents) > self.MAX_SIMILAR_INCIDENTS:
303
- errors.append(
304
- f"Too many similar incidents: {len(self.similar_incidents)} > "
305
- f"{self.MAX_SIMILAR_INCIDENTS}"
306
- )
307
-
308
- # Validate OSS edition restrictions
309
  if self.oss_edition == OSS_EDITION:
310
  if self.execution_allowed:
311
  errors.append("Execution not allowed in OSS edition")
312
-
313
  if self.status == IntentStatus.EXECUTING:
314
  errors.append("EXECUTING status not allowed in OSS edition")
315
-
316
  if self.executed_at is not None:
317
  errors.append("executed_at should not be set in OSS edition")
318
-
319
  if self.execution_id is not None:
320
  errors.append("execution_id should not be set in OSS edition")
321
-
322
  if errors:
323
- raise ValidationError(
324
- f"HealingIntent validation failed:\n" +
325
- "\n".join(f" • {error}" for error in errors)
326
- )
327
 
328
  def _validate_risk_integration(self) -> None:
329
- """Validate that risk and cost fields are consistent"""
330
- if self.risk_score is not None:
331
- if not (0.0 <= self.risk_score <= 1.0):
332
- raise ValidationError(f"Risk score must be between 0 and 1, got {self.risk_score}")
333
-
334
  if self.cost_projection is not None and self.cost_projection < 0:
335
  raise ValidationError(f"Cost projection cannot be negative, got {self.cost_projection}")
336
-
337
  if self.cost_confidence_interval is not None:
338
  low, high = self.cost_confidence_interval
339
  if low > high:
@@ -341,12 +195,6 @@ class HealingIntent:
341
 
342
  @property
343
  def deterministic_id(self) -> str:
344
- """
345
- Deterministic ID for idempotency based on action + component + parameters
346
-
347
- This ensures the same action on the same component with the same parameters
348
- generates the same intent ID, preventing duplicate executions.
349
- """
350
  data = {
351
  "action": self.action,
352
  "component": self.component,
@@ -355,66 +203,41 @@ class HealingIntent:
355
  "detected_at": int(self.detected_at),
356
  "oss_edition": self.oss_edition,
357
  }
358
-
359
- # Sort keys for deterministic JSON
360
  json_str = json.dumps(data, sort_keys=True, default=str)
361
-
362
- # Create hash-based ID
363
  hash_digest = hashlib.sha256(json_str.encode()).hexdigest()
364
  return f"intent_{hash_digest[:16]}"
365
 
366
  @property
367
  def age_seconds(self) -> float:
368
- """Get age of intent in seconds"""
369
  return time.time() - self.created_at
370
 
371
  @property
372
  def is_executable(self) -> bool:
373
- """Check if intent is ready for execution"""
374
- # In OSS edition, nothing is executable
375
  if self.oss_edition == OSS_EDITION:
376
  return False
377
-
378
- return self.status in [
379
- IntentStatus.CREATED,
380
- IntentStatus.PENDING_EXECUTION,
381
- IntentStatus.APPROVED
382
- ]
383
 
384
  @property
385
  def is_oss_advisory(self) -> bool:
386
- """Check if this is an OSS advisory-only intent"""
387
  return self.oss_edition == OSS_EDITION and not self.execution_allowed
388
 
389
  @property
390
  def requires_enterprise_upgrade(self) -> bool:
391
- """Check if intent requires Enterprise upgrade"""
392
  return self.requires_enterprise and self.oss_edition == OSS_EDITION
393
 
394
  @property
395
  def confidence_interval(self) -> Optional[Tuple[float, float]]:
396
- """Get confidence interval if distribution is available"""
397
  if self.confidence_distribution:
398
- return (self.confidence_distribution.get("p5", self.confidence),
399
- self.confidence_distribution.get("p95", self.confidence))
400
  return None
401
 
402
  def to_enterprise_request(self) -> Dict[str, Any]:
403
- """
404
- Convert to Enterprise API request format
405
-
406
- Returns only the data needed for Enterprise execution.
407
- OSS analysis context stays in OSS.
408
- """
409
  return {
410
- # Core execution fields
411
  "intent_id": self.deterministic_id,
412
  "action": self.action,
413
  "component": self.component,
414
  "parameters": self.parameters,
415
  "justification": self.justification,
416
-
417
- # OSS metadata for Enterprise context
418
  "confidence": self.confidence,
419
  "confidence_interval": self.confidence_interval,
420
  "risk_score": self.risk_score,
@@ -424,15 +247,11 @@ class HealingIntent:
424
  "created_at": self.created_at,
425
  "source": self.source.value,
426
  "recommended_action": self.recommended_action.value if self.recommended_action else None,
427
-
428
- # OSS edition information
429
  "oss_edition": self.oss_edition,
430
  "oss_license": self.oss_license,
431
  "requires_enterprise": self.requires_enterprise,
432
  "execution_allowed": self.execution_allowed,
433
  "version": self.VERSION,
434
-
435
- # Minimal OSS context (for debugging only)
436
  "oss_metadata": {
437
  "similar_incidents_count": len(self.similar_incidents) if self.similar_incidents else 0,
438
  "rag_similarity_score": self.rag_similarity_score,
@@ -445,8 +264,6 @@ class HealingIntent:
445
  "learning_applied": False,
446
  "learning_reason": "OSS advisory mode does not persist or learn from outcomes",
447
  },
448
-
449
- # Upgrade information
450
  "upgrade_url": ENTERPRISE_UPGRADE_URL,
451
  "enterprise_features": [
452
  "autonomous_execution",
@@ -465,7 +282,6 @@ class HealingIntent:
465
  }
466
 
467
  def _get_confidence_basis(self) -> str:
468
- """Determine confidence basis based on available data"""
469
  if self.recommended_action == RecommendedAction.DENY and self.policy_violations:
470
  return "policy_violation"
471
  if self.rag_similarity_score and self.rag_similarity_score > SIMILARITY_THRESHOLD:
@@ -475,27 +291,13 @@ class HealingIntent:
475
  return "policy_only"
476
 
477
  def to_dict(self, include_oss_context: bool = False) -> Dict[str, Any]:
478
- """
479
- Convert to dictionary for serialization
480
-
481
- Args:
482
- include_oss_context: Whether to include OSS analysis context
483
- (should be False when sending to Enterprise)
484
-
485
- Returns:
486
- Dictionary representation of the intent
487
- """
488
  data = asdict(self)
489
-
490
- # Convert enums to strings
491
  if "source" in data and isinstance(data["source"], IntentSource):
492
  data["source"] = self.source.value
493
  if "status" in data and isinstance(data["status"], IntentStatus):
494
  data["status"] = self.status.value
495
  if "recommended_action" in data and isinstance(data["recommended_action"], RecommendedAction):
496
  data["recommended_action"] = self.recommended_action.value if self.recommended_action else None
497
-
498
- # Remove OSS context if not needed
499
  if not include_oss_context:
500
  data.pop("reasoning_chain", None)
501
  data.pop("similar_incidents", None)
@@ -503,8 +305,6 @@ class HealingIntent:
503
  data.pop("decision_tree", None)
504
  data.pop("alternative_actions", None)
505
  data.pop("infrastructure_intent", None)
506
-
507
- # Add computed properties
508
  data["deterministic_id"] = self.deterministic_id
509
  data["age_seconds"] = self.age_seconds
510
  data["is_executable"] = self.is_executable
@@ -512,464 +312,182 @@ class HealingIntent:
512
  data["requires_enterprise_upgrade"] = self.requires_enterprise_upgrade
513
  data["version"] = self.VERSION
514
  data["confidence_interval"] = self.confidence_interval
515
-
516
  return data
517
 
518
- def with_execution_result(
519
- self,
520
- execution_id: str,
521
- executed_at: float,
522
- result: Dict[str, Any],
523
- status: IntentStatus = IntentStatus.COMPLETED,
524
- metadata: Optional[Dict[str, Any]] = None
525
- ) -> "HealingIntent":
526
- """
527
- Create a new HealingIntent with execution results (used by Enterprise)
528
-
529
- This is how Enterprise updates the intent after execution.
530
- Returns a new immutable intent with execution results.
531
- """
532
- # Create a new dataclass with updated fields
533
  return HealingIntent(
534
- # Core fields (copied)
535
- action=self.action,
536
- component=self.component,
537
- parameters=self.parameters,
538
- justification=self.justification,
539
- confidence=self.confidence,
540
- confidence_distribution=self.confidence_distribution,
541
- incident_id=self.incident_id,
542
- detected_at=self.detected_at,
543
-
544
- # Risk and cost fields (copied)
545
- risk_score=self.risk_score,
546
- risk_factors=self.risk_factors,
547
- cost_projection=self.cost_projection,
548
- cost_confidence_interval=self.cost_confidence_interval,
549
- recommended_action=self.recommended_action,
550
-
551
- # Decision tracking (copied)
552
- decision_tree=self.decision_tree,
553
- alternative_actions=self.alternative_actions,
554
- risk_profile=self.risk_profile,
555
-
556
- # OSS context (copied)
557
- reasoning_chain=self.reasoning_chain,
558
- similar_incidents=self.similar_incidents,
559
- rag_similarity_score=self.rag_similarity_score,
560
- source=self.source,
561
-
562
- # Identifiers (copied)
563
- intent_id=self.intent_id,
564
- created_at=self.created_at,
565
-
566
- # OSS metadata (copied)
567
- oss_edition=self.oss_edition,
568
- oss_license=self.oss_license,
569
- requires_enterprise=self.requires_enterprise,
570
- execution_allowed=self.execution_allowed,
571
-
572
- # Infrastructure integration (copied)
573
- infrastructure_intent_id=self.infrastructure_intent_id,
574
- policy_violations=self.policy_violations,
575
- infrastructure_intent=self.infrastructure_intent,
576
-
577
- # Updated execution fields
578
- status=status,
579
- execution_id=execution_id,
580
- executed_at=executed_at,
581
- execution_result=result,
582
  enterprise_metadata={**(self.enterprise_metadata or {}), **(metadata or {})},
583
-
584
- # Human interaction (copied)
585
- human_overrides=self.human_overrides,
586
- approvals=self.approvals,
587
- comments=self.comments
588
  )
589
 
590
- def with_human_approval(
591
- self,
592
- approver: str,
593
- approval_time: float,
594
- comments: Optional[str] = None,
595
- overrides: Optional[Dict[str, Any]] = None
596
- ) -> "HealingIntent":
597
- """
598
- Record human approval with optional overrides.
599
-
600
- Returns a new intent with approval recorded and status updated.
601
- """
602
- approval_record = {
603
- "approver": approver,
604
- "timestamp": approval_time,
605
- "comments": comments,
606
- "overrides": overrides
607
- }
608
-
609
  new_overrides = list(self.human_overrides)
610
  if overrides:
611
- new_overrides.append({
612
- "overrider": approver,
613
- "timestamp": approval_time,
614
- "overrides": overrides,
615
- "reason": comments
616
- })
617
-
618
- new_approvals = list(self.approvals)
619
- new_approvals.append(approval_record)
620
-
621
  new_comments = list(self.comments)
622
  if comments:
623
- new_comments.append({
624
- "author": approver,
625
- "timestamp": approval_time,
626
- "comment": comments
627
- })
628
-
629
  return HealingIntent(
630
- # Copy all fields
631
- action=self.action,
632
- component=self.component,
633
- parameters=self.parameters,
634
- justification=self.justification,
635
- confidence=self.confidence,
636
- confidence_distribution=self.confidence_distribution,
637
- incident_id=self.incident_id,
638
- detected_at=self.detected_at,
639
- risk_score=self.risk_score,
640
- risk_factors=self.risk_factors,
641
- cost_projection=self.cost_projection,
642
- cost_confidence_interval=self.cost_confidence_interval,
643
- recommended_action=self.recommended_action,
644
- decision_tree=self.decision_tree,
645
- alternative_actions=self.alternative_actions,
646
- risk_profile=self.risk_profile,
647
- reasoning_chain=self.reasoning_chain,
648
- similar_incidents=self.similar_incidents,
649
- rag_similarity_score=self.rag_similarity_score,
650
- source=self.source,
651
- intent_id=self.intent_id,
652
- created_at=self.created_at,
653
- status=IntentStatus.APPROVED_WITH_OVERRIDES if overrides else IntentStatus.APPROVED,
654
- execution_id=self.execution_id,
655
- executed_at=self.executed_at,
656
- execution_result=self.execution_result,
657
- enterprise_metadata=self.enterprise_metadata,
658
- human_overrides=new_overrides,
659
- approvals=new_approvals,
660
- comments=new_comments,
661
- oss_edition=self.oss_edition,
662
- oss_license=self.oss_license,
663
- requires_enterprise=self.requires_enterprise,
664
- execution_allowed=self.execution_allowed,
665
- infrastructure_intent_id=self.infrastructure_intent_id,
666
- policy_violations=self.policy_violations,
667
  infrastructure_intent=self.infrastructure_intent
668
  )
669
 
670
  def mark_as_sent_to_enterprise(self) -> "HealingIntent":
671
- """
672
- Mark intent as sent to Enterprise (used by OSS)
673
-
674
- Returns a new intent with status updated to PENDING_EXECUTION
675
- """
676
  return HealingIntent(
677
- # Copy all fields
678
- action=self.action,
679
- component=self.component,
680
- parameters=self.parameters,
681
- justification=self.justification,
682
- confidence=self.confidence,
683
- confidence_distribution=self.confidence_distribution,
684
- incident_id=self.incident_id,
685
- detected_at=self.detected_at,
686
- risk_score=self.risk_score,
687
- risk_factors=self.risk_factors,
688
- cost_projection=self.cost_projection,
689
- cost_confidence_interval=self.cost_confidence_interval,
690
- recommended_action=self.recommended_action,
691
- decision_tree=self.decision_tree,
692
- alternative_actions=self.alternative_actions,
693
- risk_profile=self.risk_profile,
694
- reasoning_chain=self.reasoning_chain,
695
- similar_incidents=self.similar_incidents,
696
- rag_similarity_score=self.rag_similarity_score,
697
- source=self.source,
698
- intent_id=self.intent_id,
699
- created_at=self.created_at,
700
- status=IntentStatus.PENDING_EXECUTION,
701
- execution_id=self.execution_id,
702
- executed_at=self.executed_at,
703
- execution_result=self.execution_result,
704
- enterprise_metadata=self.enterprise_metadata,
705
- human_overrides=self.human_overrides,
706
- approvals=self.approvals,
707
- comments=self.comments,
708
- oss_edition=self.oss_edition,
709
- oss_license=self.oss_license,
710
- requires_enterprise=self.requires_enterprise,
711
- execution_allowed=self.execution_allowed,
712
- infrastructure_intent_id=self.infrastructure_intent_id,
713
- policy_violations=self.policy_violations,
714
- infrastructure_intent=self.infrastructure_intent
715
  )
716
 
717
  def mark_as_oss_advisory(self) -> "HealingIntent":
718
- """
719
- Mark intent as OSS advisory only
720
-
721
- Used when OSS creates an intent that can only be advisory
722
- """
723
  return HealingIntent(
724
- # Copy all fields
725
- action=self.action,
726
- component=self.component,
727
- parameters=self.parameters,
728
- justification=self.justification,
729
- confidence=self.confidence,
730
- confidence_distribution=self.confidence_distribution,
731
- incident_id=self.incident_id,
732
- detected_at=self.detected_at,
733
- risk_score=self.risk_score,
734
- risk_factors=self.risk_factors,
735
- cost_projection=self.cost_projection,
736
- cost_confidence_interval=self.cost_confidence_interval,
737
- recommended_action=self.recommended_action,
738
- decision_tree=self.decision_tree,
739
- alternative_actions=self.alternative_actions,
740
- risk_profile=self.risk_profile,
741
- reasoning_chain=self.reasoning_chain,
742
- similar_incidents=self.similar_incidents,
743
- rag_similarity_score=self.rag_similarity_score,
744
- source=self.source,
745
- intent_id=self.intent_id,
746
- created_at=self.created_at,
747
- status=IntentStatus.OSS_ADVISORY_ONLY,
748
- execution_id=self.execution_id,
749
- executed_at=self.executed_at,
750
- execution_result=self.execution_result,
751
- enterprise_metadata=self.enterprise_metadata,
752
- human_overrides=self.human_overrides,
753
- approvals=self.approvals,
754
- comments=self.comments,
755
- oss_edition=self.oss_edition,
756
- oss_license=self.oss_license,
757
- requires_enterprise=self.requires_enterprise,
758
- execution_allowed=False, # Force no execution in OSS
759
- infrastructure_intent_id=self.infrastructure_intent_id,
760
- policy_violations=self.policy_violations,
761
- infrastructure_intent=self.infrastructure_intent
762
  )
763
 
764
  @classmethod
765
- def from_infrastructure_intent(
766
- cls,
767
- infrastructure_intent: Any, # InfrastructureIntent type
768
- action: str,
769
- component: str,
770
- parameters: Dict[str, Any],
771
- justification: str,
772
- confidence: float = 0.85,
773
- risk_score: Optional[float] = None,
774
- risk_factors: Optional[Dict[str, float]] = None,
775
- cost_projection: Optional[float] = None,
776
- policy_violations: Optional[List[str]] = None,
777
- recommended_action: Optional[RecommendedAction] = None,
778
- source: IntentSource = IntentSource.INFRASTRUCTURE_ANALYSIS
779
- ) -> "HealingIntent":
780
- """
781
- Create HealingIntent from infrastructure module analysis.
782
-
783
- This bridges the infrastructure governance module with the healing system.
784
- """
785
- # Extract intent_id if available
786
  infrastructure_intent_id = getattr(infrastructure_intent, 'intent_id', None)
787
-
788
- # Convert infrastructure intent to dict for storage
789
  if hasattr(infrastructure_intent, 'model_dump'):
790
  intent_dict = infrastructure_intent.model_dump()
791
  elif hasattr(infrastructure_intent, 'to_dict'):
792
  intent_dict = infrastructure_intent.to_dict()
793
  else:
794
  intent_dict = {"type": str(type(infrastructure_intent))}
795
-
796
  return cls(
797
- action=action,
798
- component=component,
799
- parameters=parameters,
800
- justification=justification,
801
- confidence=confidence,
802
- risk_score=risk_score,
803
- risk_factors=risk_factors,
804
- cost_projection=cost_projection,
805
- policy_violations=policy_violations or [],
806
- recommended_action=recommended_action,
807
- source=source,
808
- infrastructure_intent_id=infrastructure_intent_id,
809
- infrastructure_intent=intent_dict,
810
- oss_edition=OSS_EDITION,
811
- requires_enterprise=True,
812
- execution_allowed=False
813
  )
814
 
815
  @classmethod
816
- def from_analysis(
817
- cls,
818
- action: str,
819
- component: str,
820
- parameters: Dict[str, Any],
821
- justification: str,
822
- confidence: float,
823
- confidence_std: float = 0.05,
824
- similar_incidents: Optional[List[Dict[str, Any]]] = None,
825
- reasoning_chain: Optional[List[Dict[str, Any]]] = None,
826
- incident_id: str = "",
827
- source: IntentSource = IntentSource.OSS_ANALYSIS,
828
- rag_similarity_score: Optional[float] = None,
829
- risk_score: Optional[float] = None,
830
- cost_projection: Optional[float] = None,
831
- ) -> "HealingIntent":
832
- """
833
- Factory method for creating HealingIntent from OSS analysis
834
-
835
- This is the primary way OSS creates intents.
836
- Enhanced with probabilistic confidence and risk integration.
837
- """
838
- # Apply OSS limits to similar incidents
839
  if similar_incidents and len(similar_incidents) > cls.MAX_SIMILAR_INCIDENTS:
840
  similar_incidents = similar_incidents[:cls.MAX_SIMILAR_INCIDENTS]
841
-
842
- # Create confidence distribution
843
  conf_dist = ConfidenceDistribution(confidence, confidence_std)
844
-
845
- # Calculate enhanced confidence based on similar incidents
846
  enhanced_confidence = confidence
847
  if similar_incidents:
848
- similarity_scores = [
849
- inc.get("similarity", 0.0)
850
- for inc in similar_incidents
851
- if "similarity" in inc
852
- ]
853
  if similarity_scores:
854
  avg_similarity = sum(similarity_scores) / len(similarity_scores)
855
- # Cap the boost to prevent overconfidence
856
  confidence_boost = min(0.2, avg_similarity * 0.3)
857
  enhanced_confidence = min(confidence * (1.0 + confidence_boost), cls.MAX_CONFIDENCE)
858
-
859
- # Use provided RAG score or calculate from similar incidents
860
  final_rag_score = rag_similarity_score
861
  if final_rag_score is None and similar_incidents and len(similar_incidents) > 0:
862
- # Take average of top 3 similarities
863
- top_similarities = [
864
- inc.get("similarity", 0.0)
865
- for inc in similar_incidents[:3]
866
- if "similarity" in inc
867
- ]
868
  if top_similarities:
869
  final_rag_score = sum(top_similarities) / len(top_similarities)
870
-
871
  return cls(
872
- action=action,
873
- component=component,
874
- parameters=parameters,
875
- justification=justification,
876
- confidence=enhanced_confidence,
877
- confidence_distribution=conf_dist.to_dict(),
878
- incident_id=incident_id,
879
- similar_incidents=similar_incidents,
880
- reasoning_chain=reasoning_chain,
881
- rag_similarity_score=final_rag_score,
882
- source=source,
883
- risk_score=risk_score,
884
- cost_projection=cost_projection,
885
- oss_edition=OSS_EDITION,
886
- requires_enterprise=True,
887
- execution_allowed=False,
888
  )
889
 
890
  @classmethod
891
- def from_rag_recommendation(
892
- cls,
893
- action: str,
894
- component: str,
895
- parameters: Dict[str, Any],
896
- rag_similarity_score: float,
897
- similar_incidents: List[Dict[str, Any]],
898
- justification_template: str = "Based on {count} similar historical incidents with {success_rate:.0%} success rate",
899
- success_rate: Optional[float] = None,
900
- risk_score: Optional[float] = None,
901
- cost_projection: Optional[float] = None,
902
- ) -> "HealingIntent":
903
- """
904
- Create HealingIntent from RAG graph recommendation
905
-
906
- Specialized factory for RAG-based recommendations
907
- """
908
  if not similar_incidents:
909
  raise ValidationError("RAG recommendation requires similar incidents")
910
-
911
- # Calculate success rate if not provided
912
  if success_rate is None:
913
  if len(similar_incidents) == 0:
914
  success_rate = 0.0
915
  else:
916
  successful = sum(1 for inc in similar_incidents if inc.get("success", False))
917
  success_rate = successful / len(similar_incidents)
918
-
919
- # Generate justification
920
- justification = justification_template.format(
921
- count=len(similar_incidents),
922
- success_rate=success_rate or 0.0,
923
- action=action,
924
- component=component,
925
- )
926
-
927
- # Calculate confidence based on RAG similarity
928
- base_confidence = rag_similarity_score * 0.8 # Scale similarity to confidence
929
  if success_rate:
930
  base_confidence = base_confidence * (0.7 + success_rate * 0.3)
931
-
932
- return cls.from_analysis(
933
- action=action,
934
- component=component,
935
- parameters=parameters,
936
- justification=justification,
937
- confidence=min(base_confidence, 0.95), # Cap at 95%
938
- similar_incidents=similar_incidents,
939
- incident_id=similar_incidents[0].get("incident_id", "") if similar_incidents else "",
940
- source=IntentSource.RAG_SIMILARITY,
941
- rag_similarity_score=rag_similarity_score,
942
- risk_score=risk_score,
943
- cost_projection=cost_projection,
944
- )
945
 
946
  @classmethod
947
  def from_dict(cls, data: Dict[str, Any]) -> "HealingIntent":
948
- """
949
- Create from dictionary (deserialize)
950
-
951
- Handles versioning and field conversion
952
- """
953
- # Handle versioning
954
  version = data.get("version", "1.0.0")
955
-
956
- # Create a copy to avoid mutating input
957
  clean_data = data.copy()
958
-
959
- # Convert string enums back to Enum instances
960
  if "source" in clean_data and isinstance(clean_data["source"], str):
961
  clean_data["source"] = IntentSource(clean_data["source"])
962
-
963
  if "status" in clean_data and isinstance(clean_data["status"], str):
964
  clean_data["status"] = IntentStatus(clean_data["status"])
965
-
966
  if "recommended_action" in clean_data and isinstance(clean_data["recommended_action"], str):
967
  try:
968
  clean_data["recommended_action"] = RecommendedAction(clean_data["recommended_action"])
969
  except ValueError:
970
  clean_data["recommended_action"] = None
971
-
972
- # Remove computed fields that shouldn't be in constructor
973
  clean_data.pop("deterministic_id", None)
974
  clean_data.pop("age_seconds", None)
975
  clean_data.pop("is_executable", None)
@@ -977,55 +495,30 @@ class HealingIntent:
977
  clean_data.pop("requires_enterprise_upgrade", None)
978
  clean_data.pop("version", None)
979
  clean_data.pop("confidence_interval", None)
980
-
981
  return cls(**clean_data)
982
 
983
  def _normalize_parameters(self, params: Dict[str, Any]) -> Dict[str, Any]:
984
- """
985
- Normalize parameters for deterministic hashing
986
-
987
- Ensures that parameter order and minor format differences
988
- don't affect the deterministic ID.
989
- """
990
  normalized: Dict[str, Any] = {}
991
-
992
  for key, value in sorted(params.items()):
993
  normalized[key] = self._normalize_value(value)
994
-
995
  return normalized
996
 
997
  def _normalize_value(self, value: Any) -> Any:
998
- """Normalize a single value for hashing"""
999
  if isinstance(value, (int, float, str, bool, type(None))):
1000
  return value
1001
  elif isinstance(value, (list, tuple, set)):
1002
- # Convert all iterables to sorted tuples
1003
- normalized_items = tuple(
1004
- sorted(
1005
- self._normalize_value(v) for v in value
1006
- )
1007
- )
1008
- return normalized_items
1009
  elif isinstance(value, dict):
1010
- # Recursively normalize dicts
1011
  return self._normalize_parameters(value)
1012
  elif hasattr(value, '__dict__'):
1013
- # Handle objects with __dict__
1014
  return self._normalize_parameters(value.__dict__)
1015
  else:
1016
- # Convert to string representation for other types
1017
  try:
1018
  return str(value)
1019
  except Exception:
1020
- # Fallback for objects that can't be stringified
1021
  return f"<unserializable:{type(value).__name__}>"
1022
 
1023
  def get_oss_context(self) -> Dict[str, Any]:
1024
- """
1025
- Get OSS analysis context (stays in OSS)
1026
-
1027
- This data never leaves the OSS environment for privacy and IP protection.
1028
- """
1029
  return {
1030
  "reasoning_chain": self.reasoning_chain,
1031
  "similar_incidents": self.similar_incidents,
@@ -1041,11 +534,6 @@ class HealingIntent:
1041
  }
1042
 
1043
  def get_execution_summary(self) -> Dict[str, Any]:
1044
- """
1045
- Get execution summary (public information)
1046
-
1047
- Safe to share externally
1048
- """
1049
  summary = {
1050
  "intent_id": self.deterministic_id,
1051
  "action": self.action,
@@ -1064,80 +552,40 @@ class HealingIntent:
1064
  "policy_violations_count": len(self.policy_violations) if self.policy_violations else 0,
1065
  "confidence_basis": self._get_confidence_basis(),
1066
  }
1067
-
1068
  if self.executed_at:
1069
  summary["executed_at"] = datetime.fromtimestamp(self.executed_at).isoformat()
1070
  summary["execution_duration_seconds"] = self.executed_at - self.created_at
1071
-
1072
  if self.execution_result:
1073
  summary["execution_success"] = self.execution_result.get("success", False)
1074
  summary["execution_message"] = self.execution_result.get("message", "")
1075
-
1076
  if self.rag_similarity_score:
1077
  summary["rag_similarity_score"] = self.rag_similarity_score
1078
-
1079
  if self.similar_incidents:
1080
  summary["similar_incidents_count"] = len(self.similar_incidents)
1081
-
1082
  if self.approvals:
1083
  summary["approvals_count"] = len(self.approvals)
1084
  summary["approved_by"] = [a.get("approver") for a in self.approvals if a.get("approver")]
1085
-
1086
  if self.human_overrides:
1087
  summary["overrides_count"] = len(self.human_overrides)
1088
-
1089
  return summary
1090
 
1091
  def is_immutable(self) -> bool:
1092
- """Check if the intent is truly immutable (frozen dataclass property)"""
1093
  try:
1094
- # Try to modify a field - should raise FrozenInstanceError
1095
  object.__setattr__(self, '_test_immutable', True)
1096
  return False
1097
  except Exception:
1098
  return True
1099
 
1100
  def __repr__(self) -> str:
1101
- return (
1102
- f"HealingIntent("
1103
- f"id={self.deterministic_id[:8]}..., "
1104
- f"action={self.action}, "
1105
- f"component={self.component}, "
1106
- f"confidence={self.confidence:.2f}, "
1107
- f"risk={self.risk_score:.2f if self.risk_score else 'N/A'}, "
1108
- f"status={self.status.value}"
1109
- f")"
1110
- )
1111
-
1112
 
1113
  class HealingIntentSerializer:
1114
- """
1115
- Versioned serialization for HealingIntent
1116
-
1117
- Enhanced with:
1118
- - Probabilistic confidence distribution support
1119
- - Risk and cost field serialization
1120
- - Backward compatibility with v1.x
1121
- - OSS/Enterprise edition detection
1122
- """
1123
-
1124
  SCHEMA_VERSION: ClassVar[str] = "2.0.0"
1125
 
1126
  @classmethod
1127
  def serialize(cls, intent: HealingIntent, version: str = "2.0.0") -> Dict[str, Any]:
1128
- """
1129
- Serialize HealingIntent with versioning
1130
-
1131
- Args:
1132
- intent: HealingIntent to serialize
1133
- version: Schema version to use
1134
-
1135
- Returns:
1136
- Versioned serialization dictionary
1137
-
1138
- Raises:
1139
- SerializationError: If serialization fails
1140
- """
1141
  try:
1142
  if version == "2.0.0":
1143
  return {
@@ -1156,11 +604,8 @@ class HealingIntentSerializer:
1156
  "has_cost_projection": intent.cost_projection is not None,
1157
  }
1158
  }
1159
- elif version == "1.1.0" or version == "1.0.0":
1160
- # Backward compatibility with v1.x
1161
  data = intent.to_dict(include_oss_context=True)
1162
-
1163
- # Remove v2.0.0 fields for compatibility
1164
  data.pop("confidence_distribution", None)
1165
  data.pop("risk_score", None)
1166
  data.pop("risk_factors", None)
@@ -1176,8 +621,6 @@ class HealingIntentSerializer:
1176
  data.pop("infrastructure_intent_id", None)
1177
  data.pop("policy_violations", None)
1178
  data.pop("infrastructure_intent", None)
1179
-
1180
- # Ensure status is compatible
1181
  if data.get("status") in [
1182
  IntentStatus.EXECUTING_PARTIAL.value,
1183
  IntentStatus.COMPLETED_PARTIAL.value,
@@ -1187,7 +630,6 @@ class HealingIntentSerializer:
1187
  IntentStatus.APPROVED_WITH_OVERRIDES.value
1188
  ]:
1189
  data["status"] = IntentStatus.PENDING_EXECUTION.value
1190
-
1191
  return {
1192
  "version": version,
1193
  "schema_version": "1.1.0" if version == "1.1.0" else "1.0.0",
@@ -1201,32 +643,16 @@ class HealingIntentSerializer:
1201
  }
1202
  else:
1203
  raise SerializationError(f"Unsupported version: {version}")
1204
-
1205
  except Exception as e:
1206
  raise SerializationError(f"Failed to serialize HealingIntent: {e}") from e
1207
 
1208
  @classmethod
1209
  def deserialize(cls, data: Dict[str, Any]) -> HealingIntent:
1210
- """
1211
- Deserialize HealingIntent with version detection
1212
-
1213
- Args:
1214
- data: Serialized data
1215
-
1216
- Returns:
1217
- Deserialized HealingIntent
1218
-
1219
- Raises:
1220
- SerializationError: If deserialization fails
1221
- """
1222
  try:
1223
  version = data.get("version", "1.0.0")
1224
- intent_data = data.get("data", data) # Handle both wrapped and unwrapped
1225
-
1226
  if version in ["2.0.0", "1.1.0", "1.0.0"]:
1227
- # Handle version differences
1228
  if version.startswith("1."):
1229
- # Add default values for v2 fields
1230
  intent_data.setdefault("confidence_distribution", None)
1231
  intent_data.setdefault("risk_score", None)
1232
  intent_data.setdefault("risk_factors", None)
@@ -1242,11 +668,9 @@ class HealingIntentSerializer:
1242
  intent_data.setdefault("infrastructure_intent_id", None)
1243
  intent_data.setdefault("policy_violations", [])
1244
  intent_data.setdefault("infrastructure_intent", None)
1245
-
1246
  return HealingIntent.from_dict(intent_data)
1247
  else:
1248
  raise SerializationError(f"Unsupported version: {version}")
1249
-
1250
  except KeyError as e:
1251
  raise SerializationError(f"Missing required field in serialized data: {e}") from e
1252
  except Exception as e:
@@ -1254,19 +678,14 @@ class HealingIntentSerializer:
1254
 
1255
  @classmethod
1256
  def to_json(cls, intent: HealingIntent, pretty: bool = False) -> str:
1257
- """Convert HealingIntent to JSON string"""
1258
  try:
1259
  serialized = cls.serialize(intent)
1260
- if pretty:
1261
- return json.dumps(serialized, indent=2, default=str)
1262
- else:
1263
- return json.dumps(serialized, default=str)
1264
  except Exception as e:
1265
  raise SerializationError(f"Failed to convert to JSON: {e}") from e
1266
 
1267
  @classmethod
1268
  def from_json(cls, json_str: str) -> HealingIntent:
1269
- """Create HealingIntent from JSON string"""
1270
  try:
1271
  data = json.loads(json_str)
1272
  return cls.deserialize(data)
@@ -1277,11 +696,6 @@ class HealingIntentSerializer:
1277
 
1278
  @classmethod
1279
  def to_enterprise_json(cls, intent: HealingIntent) -> str:
1280
- """
1281
- Convert to Enterprise-ready JSON (excludes OSS context)
1282
-
1283
- This is what should be sent to the Enterprise API
1284
- """
1285
  try:
1286
  enterprise_request = intent.to_enterprise_request()
1287
  return json.dumps(enterprise_request, default=str)
@@ -1290,73 +704,30 @@ class HealingIntentSerializer:
1290
 
1291
  @classmethod
1292
  def validate_for_oss(cls, intent: HealingIntent) -> bool:
1293
- """
1294
- Validate that HealingIntent complies with OSS boundaries
1295
-
1296
- Returns:
1297
- True if intent is valid for OSS edition
1298
- """
1299
  try:
1300
- # Check OSS edition
1301
  if intent.oss_edition != OSS_EDITION:
1302
  return False
1303
-
1304
- # Check execution restrictions
1305
  if intent.execution_allowed:
1306
  return False
1307
-
1308
- # Check similar incidents limit
1309
  if intent.similar_incidents and len(intent.similar_incidents) > HealingIntent.MAX_SIMILAR_INCIDENTS:
1310
  return False
1311
-
1312
- # Check that frozen dataclass property is preserved
1313
  if not intent.is_immutable():
1314
  return False
1315
-
1316
- # Check that no execution fields are set
1317
  if intent.executed_at is not None or intent.execution_id is not None:
1318
  return False
1319
-
1320
  return True
1321
-
1322
  except Exception:
1323
  return False
1324
 
1325
-
1326
- # Factory functions for common use cases
1327
- def create_infrastructure_healing_intent(
1328
- infrastructure_result: Any, # HealingIntent from infrastructure module
1329
- action_mapping: Optional[Dict[str, str]] = None
1330
- ) -> HealingIntent:
1331
- """
1332
- Create a healing intent from infrastructure module analysis result.
1333
-
1334
- This bridges the infrastructure governance module with the main healing system.
1335
-
1336
- Args:
1337
- infrastructure_result: The HealingIntent from infrastructure.evaluate()
1338
- action_mapping: Optional mapping from infrastructure actions to healing actions
1339
-
1340
- Returns:
1341
- HealingIntent ready for the healing system
1342
- """
1343
- # Default action mapping
1344
  if action_mapping is None:
1345
- action_mapping = {
1346
- "approve": "execute",
1347
- "deny": "block",
1348
- "escalate": "escalate",
1349
- "defer": "defer"
1350
- }
1351
-
1352
- # Extract fields from infrastructure result
1353
  recommended_action = getattr(infrastructure_result, 'recommended_action', None)
1354
  if recommended_action and hasattr(recommended_action, 'value'):
1355
  action = action_mapping.get(recommended_action.value, "review")
1356
  else:
1357
  action = "review"
1358
-
1359
- # Build parameters
1360
  parameters = {
1361
  "infrastructure_intent_id": getattr(infrastructure_result, 'intent_id', None),
1362
  "risk_score": getattr(infrastructure_result, 'risk_score', None),
@@ -1364,16 +735,10 @@ def create_infrastructure_healing_intent(
1364
  "policy_violations": getattr(infrastructure_result, 'policy_violations', []),
1365
  "evaluation_details": getattr(infrastructure_result, 'evaluation_details', {})
1366
  }
1367
-
1368
- # Build justification
1369
- justification_parts = [
1370
- getattr(infrastructure_result, 'justification', "Infrastructure analysis completed"),
1371
- ]
1372
-
1373
  policy_violations = getattr(infrastructure_result, 'policy_violations', [])
1374
  if policy_violations:
1375
  justification_parts.append(f"Policy violations: {'; '.join(policy_violations)}")
1376
-
1377
  return HealingIntent.from_infrastructure_intent(
1378
  infrastructure_intent=getattr(infrastructure_result, 'infrastructure_intent', None),
1379
  action=action,
@@ -1387,21 +752,12 @@ def create_infrastructure_healing_intent(
1387
  source=IntentSource.INFRASTRUCTURE_ANALYSIS
1388
  ).mark_as_oss_advisory()
1389
 
1390
-
1391
- def create_rollback_intent(
1392
- component: str,
1393
- revision: str = "previous",
1394
- justification: str = "",
1395
- incident_id: str = "",
1396
- similar_incidents: Optional[List[Dict[str, Any]]] = None,
1397
- rag_similarity_score: Optional[float] = None,
1398
- risk_score: Optional[float] = None,
1399
- cost_projection: Optional[float] = None,
1400
- ) -> HealingIntent:
1401
- """Create a rollback healing intent with OSS limits"""
1402
  if not justification:
1403
  justification = f"Rollback {component} to {revision} revision"
1404
-
1405
  return HealingIntent.from_analysis(
1406
  action="rollback",
1407
  component=component,
@@ -1415,25 +771,15 @@ def create_rollback_intent(
1415
  cost_projection=cost_projection,
1416
  ).mark_as_oss_advisory()
1417
 
1418
-
1419
- def create_restart_intent(
1420
- component: str,
1421
- container_id: Optional[str] = None,
1422
- justification: str = "",
1423
- incident_id: str = "",
1424
- similar_incidents: Optional[List[Dict[str, Any]]] = None,
1425
- rag_similarity_score: Optional[float] = None,
1426
- risk_score: Optional[float] = None,
1427
- cost_projection: Optional[float] = None,
1428
- ) -> HealingIntent:
1429
- """Create a container restart healing intent with OSS limits"""
1430
  parameters = {}
1431
  if container_id:
1432
  parameters["container_id"] = container_id
1433
-
1434
  if not justification:
1435
  justification = f"Restart container for {component}"
1436
-
1437
  return HealingIntent.from_analysis(
1438
  action="restart_container",
1439
  component=component,
@@ -1447,21 +793,12 @@ def create_restart_intent(
1447
  cost_projection=cost_projection,
1448
  ).mark_as_oss_advisory()
1449
 
1450
-
1451
- def create_scale_out_intent(
1452
- component: str,
1453
- scale_factor: int = 2,
1454
- justification: str = "",
1455
- incident_id: str = "",
1456
- similar_incidents: Optional[List[Dict[str, Any]]] = None,
1457
- rag_similarity_score: Optional[float] = None,
1458
- risk_score: Optional[float] = None,
1459
- cost_projection: Optional[float] = None,
1460
- ) -> HealingIntent:
1461
- """Create a scale-out healing intent with OSS limits"""
1462
  if not justification:
1463
  justification = f"Scale out {component} by factor {scale_factor}"
1464
-
1465
  return HealingIntent.from_analysis(
1466
  action="scale_out",
1467
  component=component,
@@ -1475,22 +812,9 @@ def create_scale_out_intent(
1475
  cost_projection=cost_projection,
1476
  ).mark_as_oss_advisory()
1477
 
1478
-
1479
- def create_oss_advisory_intent(
1480
- action: str,
1481
- component: str,
1482
- parameters: Dict[str, Any],
1483
- justification: str,
1484
- confidence: float = 0.85,
1485
- incident_id: str = "",
1486
- risk_score: Optional[float] = None,
1487
- cost_projection: Optional[float] = None,
1488
- ) -> HealingIntent:
1489
- """
1490
- Create a generic OSS advisory-only intent
1491
-
1492
- Used when OSS wants to recommend an action without execution capability
1493
- """
1494
  return HealingIntent(
1495
  action=action,
1496
  component=component,
@@ -1506,27 +830,16 @@ def create_oss_advisory_intent(
1506
  status=IntentStatus.OSS_ADVISORY_ONLY,
1507
  )
1508
 
1509
-
1510
- # Export
1511
  __all__ = [
1512
- # Main class
1513
  "HealingIntent",
1514
-
1515
- # Supporting classes
1516
  "ConfidenceDistribution",
1517
  "HealingIntentSerializer",
1518
-
1519
- # Enums
1520
  "IntentSource",
1521
  "IntentStatus",
1522
  "RecommendedAction",
1523
-
1524
- # Exceptions
1525
  "HealingIntentError",
1526
  "SerializationError",
1527
  "ValidationError",
1528
-
1529
- # Factory functions
1530
  "create_infrastructure_healing_intent",
1531
  "create_rollback_intent",
1532
  "create_restart_intent",
 
 
1
  """
2
  Healing Intent - OSS creates, Enterprise executes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  """
4
 
5
  from dataclasses import dataclass, field, asdict
 
12
  from enum import Enum
13
  import numpy as np
14
 
 
15
  from .intents import InfrastructureIntent
16
+ from .constants import (
17
  OSS_EDITION,
18
  OSS_LICENSE,
19
  ENTERPRISE_UPGRADE_URL,
 
28
  OSSBoundaryError,
29
  )
30
 
31
+ class HealingIntentError(Exception): pass
32
+ class SerializationError(HealingIntentError): pass
33
+ class ValidationError(HealingIntentError): pass
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  class IntentSource(str, Enum):
 
36
  OSS_ANALYSIS = "oss_analysis"
37
  HUMAN_OVERRIDE = "human_override"
38
+ AUTOMATED_LEARNING = "automated_learning"
39
+ SCHEDULED_ACTION = "scheduled_action"
40
+ RAG_SIMILARITY = "rag_similarity"
41
+ INFRASTRUCTURE_ANALYSIS = "infrastructure_analysis"
42
+ POLICY_VIOLATION = "policy_violation"
43
+ COST_OPTIMIZATION = "cost_optimization"
 
44
 
45
  class IntentStatus(str, Enum):
 
46
  CREATED = "created"
47
  PENDING_EXECUTION = "pending_execution"
48
  EXECUTING = "executing"
 
58
  APPROVED = "approved"
59
  APPROVED_WITH_OVERRIDES = "approved_with_overrides"
60
 
 
61
  class RecommendedAction(str, Enum):
 
 
 
 
62
  APPROVE = "approve"
63
  DENY = "deny"
64
  ESCALATE = "escalate"
65
+ DEFER = "defer"
 
66
 
67
  class ConfidenceDistribution:
 
 
 
 
 
 
 
 
68
  def __init__(self, mean: float, std: float = 0.05, samples: Optional[List[float]] = None):
69
  self.mean = max(0.0, min(mean, 1.0))
70
  self.std = max(0.0, min(std, 0.5))
 
72
 
73
  @property
74
  def p5(self) -> float:
 
75
  return float(np.percentile(self._samples, 5))
76
 
77
  @property
78
  def p50(self) -> float:
 
79
  return float(np.percentile(self._samples, 50))
80
 
81
  @property
82
  def p95(self) -> float:
 
83
  return float(np.percentile(self._samples, 95))
84
 
85
  @property
86
  def confidence_interval(self) -> Tuple[float, float]:
 
87
  return (self.p5, self.p95)
88
 
89
  def to_dict(self) -> Dict[str, float]:
 
90
  return {
91
  "mean": self.mean,
92
  "std": self.std,
 
97
 
98
  @classmethod
99
  def from_dict(cls, data: Dict[str, float]) -> "ConfidenceDistribution":
100
+ return cls(mean=data["mean"], std=data.get("std", 0.05), samples=None)
 
 
 
 
 
101
 
102
  def __repr__(self) -> str:
103
  return f"ConfidenceDistribution(mean={self.mean:.3f}, 95% CI=[{self.p5:.3f}, {self.p95:.3f}])"
104
 
 
105
  @dataclass(frozen=True, slots=True)
106
  class HealingIntent:
107
+ action: str
108
+ component: str
109
+ parameters: Dict[str, Any] = field(default_factory=dict)
110
+ justification: str = ""
111
+ confidence: float = 0.85
112
+ confidence_distribution: Optional[Dict[str, float]] = None
113
+ incident_id: str = ""
114
+ detected_at: float = field(default_factory=time.time)
115
+ risk_score: Optional[float] = None
116
+ risk_factors: Optional[Dict[str, float]] = None
117
+ cost_projection: Optional[float] = None
118
+ cost_confidence_interval: Optional[Tuple[float, float]] = None
119
+ recommended_action: Optional[RecommendedAction] = None
120
+ decision_tree: Optional[List[Dict[str, Any]]] = None
121
+ alternative_actions: Optional[List[Dict[str, Any]]] = None
122
+ risk_profile: Optional[str] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  reasoning_chain: Optional[List[Dict[str, Any]]] = None
124
  similar_incidents: Optional[List[Dict[str, Any]]] = None
125
  rag_similarity_score: Optional[float] = None
126
  source: IntentSource = IntentSource.OSS_ANALYSIS
 
 
127
  intent_id: str = field(default_factory=lambda: f"intent_{uuid.uuid4().hex[:16]}")
128
  created_at: float = field(default_factory=time.time)
 
 
129
  status: IntentStatus = IntentStatus.CREATED
130
  execution_id: Optional[str] = None
131
  executed_at: Optional[float] = None
132
  execution_result: Optional[Dict[str, Any]] = None
133
  enterprise_metadata: Dict[str, Any] = field(default_factory=dict)
134
+ human_overrides: List[Dict[str, Any]] = field(default_factory=list)
135
+ approvals: List[Dict[str, Any]] = field(default_factory=list)
136
+ comments: List[Dict[str, Any]] = field(default_factory=list)
 
 
 
 
137
  oss_edition: str = OSS_EDITION
138
  oss_license: str = OSS_LICENSE
139
+ requires_enterprise: bool = True
140
+ execution_allowed: bool = EXECUTION_ALLOWED
141
+ infrastructure_intent_id: Optional[str] = None
142
+ policy_violations: List[str] = field(default_factory=list)
143
+ infrastructure_intent: Optional[Dict[str, Any]] = None
 
 
144
 
 
145
  MIN_CONFIDENCE: ClassVar[float] = 0.0
146
  MAX_CONFIDENCE: ClassVar[float] = 1.0
147
  MAX_JUSTIFICATION_LENGTH: ClassVar[int] = 5000
148
  MAX_PARAMETERS_SIZE: ClassVar[int] = 100
149
  MAX_SIMILAR_INCIDENTS: ClassVar[int] = MAX_SIMILARITY_CACHE
150
+ VERSION: ClassVar[str] = "2.0.0"
151
 
152
  def __post_init__(self) -> None:
 
153
  self._validate_oss_boundaries()
154
  self._validate_risk_integration()
155
 
156
  def _validate_oss_boundaries(self) -> None:
 
157
  errors: List[str] = []
 
 
158
  if not (self.MIN_CONFIDENCE <= self.confidence <= self.MAX_CONFIDENCE):
159
+ errors.append(f"Confidence must be between {self.MIN_CONFIDENCE} and {self.MAX_CONFIDENCE}, got {self.confidence}")
 
 
 
 
 
160
  if len(self.justification) > self.MAX_JUSTIFICATION_LENGTH:
161
+ errors.append(f"Justification exceeds max length {self.MAX_JUSTIFICATION_LENGTH}")
 
 
 
 
162
  if not self.action or not self.action.strip():
163
  errors.append("Action cannot be empty")
 
164
  if not self.component or not self.component.strip():
165
  errors.append("Component cannot be empty")
 
 
166
  if len(self.parameters) > self.MAX_PARAMETERS_SIZE:
167
+ errors.append(f"Too many parameters: {len(self.parameters)} > {self.MAX_PARAMETERS_SIZE}")
 
 
 
 
168
  try:
169
  json.dumps(self.parameters)
170
  except (TypeError, ValueError) as e:
171
  errors.append(f"Parameters must be JSON serializable: {e}")
172
+ if self.similar_incidents and len(self.similar_incidents) > self.MAX_SIMILAR_INCIDENTS:
173
+ errors.append(f"Too many similar incidents: {len(self.similar_incidents)} > {self.MAX_SIMILAR_INCIDENTS}")
 
 
 
 
 
 
 
 
174
  if self.oss_edition == OSS_EDITION:
175
  if self.execution_allowed:
176
  errors.append("Execution not allowed in OSS edition")
 
177
  if self.status == IntentStatus.EXECUTING:
178
  errors.append("EXECUTING status not allowed in OSS edition")
 
179
  if self.executed_at is not None:
180
  errors.append("executed_at should not be set in OSS edition")
 
181
  if self.execution_id is not None:
182
  errors.append("execution_id should not be set in OSS edition")
 
183
  if errors:
184
+ raise ValidationError("HealingIntent validation failed:\n" + "\n".join(f" • {error}" for error in errors))
 
 
 
185
 
186
  def _validate_risk_integration(self) -> None:
187
+ if self.risk_score is not None and not (0.0 <= self.risk_score <= 1.0):
188
+ raise ValidationError(f"Risk score must be between 0 and 1, got {self.risk_score}")
 
 
 
189
  if self.cost_projection is not None and self.cost_projection < 0:
190
  raise ValidationError(f"Cost projection cannot be negative, got {self.cost_projection}")
 
191
  if self.cost_confidence_interval is not None:
192
  low, high = self.cost_confidence_interval
193
  if low > high:
 
195
 
196
  @property
197
  def deterministic_id(self) -> str:
 
 
 
 
 
 
198
  data = {
199
  "action": self.action,
200
  "component": self.component,
 
203
  "detected_at": int(self.detected_at),
204
  "oss_edition": self.oss_edition,
205
  }
 
 
206
  json_str = json.dumps(data, sort_keys=True, default=str)
 
 
207
  hash_digest = hashlib.sha256(json_str.encode()).hexdigest()
208
  return f"intent_{hash_digest[:16]}"
209
 
210
  @property
211
  def age_seconds(self) -> float:
 
212
  return time.time() - self.created_at
213
 
214
  @property
215
  def is_executable(self) -> bool:
 
 
216
  if self.oss_edition == OSS_EDITION:
217
  return False
218
+ return self.status in [IntentStatus.CREATED, IntentStatus.PENDING_EXECUTION, IntentStatus.APPROVED]
 
 
 
 
 
219
 
220
  @property
221
  def is_oss_advisory(self) -> bool:
 
222
  return self.oss_edition == OSS_EDITION and not self.execution_allowed
223
 
224
  @property
225
  def requires_enterprise_upgrade(self) -> bool:
 
226
  return self.requires_enterprise and self.oss_edition == OSS_EDITION
227
 
228
  @property
229
  def confidence_interval(self) -> Optional[Tuple[float, float]]:
 
230
  if self.confidence_distribution:
231
+ return (self.confidence_distribution.get("p5", self.confidence), self.confidence_distribution.get("p95", self.confidence))
 
232
  return None
233
 
234
  def to_enterprise_request(self) -> Dict[str, Any]:
 
 
 
 
 
 
235
  return {
 
236
  "intent_id": self.deterministic_id,
237
  "action": self.action,
238
  "component": self.component,
239
  "parameters": self.parameters,
240
  "justification": self.justification,
 
 
241
  "confidence": self.confidence,
242
  "confidence_interval": self.confidence_interval,
243
  "risk_score": self.risk_score,
 
247
  "created_at": self.created_at,
248
  "source": self.source.value,
249
  "recommended_action": self.recommended_action.value if self.recommended_action else None,
 
 
250
  "oss_edition": self.oss_edition,
251
  "oss_license": self.oss_license,
252
  "requires_enterprise": self.requires_enterprise,
253
  "execution_allowed": self.execution_allowed,
254
  "version": self.VERSION,
 
 
255
  "oss_metadata": {
256
  "similar_incidents_count": len(self.similar_incidents) if self.similar_incidents else 0,
257
  "rag_similarity_score": self.rag_similarity_score,
 
264
  "learning_applied": False,
265
  "learning_reason": "OSS advisory mode does not persist or learn from outcomes",
266
  },
 
 
267
  "upgrade_url": ENTERPRISE_UPGRADE_URL,
268
  "enterprise_features": [
269
  "autonomous_execution",
 
282
  }
283
 
284
  def _get_confidence_basis(self) -> str:
 
285
  if self.recommended_action == RecommendedAction.DENY and self.policy_violations:
286
  return "policy_violation"
287
  if self.rag_similarity_score and self.rag_similarity_score > SIMILARITY_THRESHOLD:
 
291
  return "policy_only"
292
 
293
  def to_dict(self, include_oss_context: bool = False) -> Dict[str, Any]:
 
 
 
 
 
 
 
 
 
 
294
  data = asdict(self)
 
 
295
  if "source" in data and isinstance(data["source"], IntentSource):
296
  data["source"] = self.source.value
297
  if "status" in data and isinstance(data["status"], IntentStatus):
298
  data["status"] = self.status.value
299
  if "recommended_action" in data and isinstance(data["recommended_action"], RecommendedAction):
300
  data["recommended_action"] = self.recommended_action.value if self.recommended_action else None
 
 
301
  if not include_oss_context:
302
  data.pop("reasoning_chain", None)
303
  data.pop("similar_incidents", None)
 
305
  data.pop("decision_tree", None)
306
  data.pop("alternative_actions", None)
307
  data.pop("infrastructure_intent", None)
 
 
308
  data["deterministic_id"] = self.deterministic_id
309
  data["age_seconds"] = self.age_seconds
310
  data["is_executable"] = self.is_executable
 
312
  data["requires_enterprise_upgrade"] = self.requires_enterprise_upgrade
313
  data["version"] = self.VERSION
314
  data["confidence_interval"] = self.confidence_interval
 
315
  return data
316
 
317
+ def with_execution_result(self, execution_id: str, executed_at: float, result: Dict[str, Any],
318
+ status: IntentStatus = IntentStatus.COMPLETED, metadata: Optional[Dict[str, Any]] = None) -> "HealingIntent":
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  return HealingIntent(
320
+ action=self.action, component=self.component, parameters=self.parameters, justification=self.justification,
321
+ confidence=self.confidence, confidence_distribution=self.confidence_distribution, incident_id=self.incident_id,
322
+ detected_at=self.detected_at, risk_score=self.risk_score, risk_factors=self.risk_factors,
323
+ cost_projection=self.cost_projection, cost_confidence_interval=self.cost_confidence_interval,
324
+ recommended_action=self.recommended_action, decision_tree=self.decision_tree,
325
+ alternative_actions=self.alternative_actions, risk_profile=self.risk_profile,
326
+ reasoning_chain=self.reasoning_chain, similar_incidents=self.similar_incidents,
327
+ rag_similarity_score=self.rag_similarity_score, source=self.source, intent_id=self.intent_id,
328
+ created_at=self.created_at, oss_edition=self.oss_edition, oss_license=self.oss_license,
329
+ requires_enterprise=self.requires_enterprise, execution_allowed=self.execution_allowed,
330
+ infrastructure_intent_id=self.infrastructure_intent_id, policy_violations=self.policy_violations,
331
+ infrastructure_intent=self.infrastructure_intent, status=status, execution_id=execution_id,
332
+ executed_at=executed_at, execution_result=result,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  enterprise_metadata={**(self.enterprise_metadata or {}), **(metadata or {})},
334
+ human_overrides=self.human_overrides, approvals=self.approvals, comments=self.comments
 
 
 
 
335
  )
336
 
337
+ def with_human_approval(self, approver: str, approval_time: float, comments: Optional[str] = None,
338
+ overrides: Optional[Dict[str, Any]] = None) -> "HealingIntent":
339
+ approval_record = {"approver": approver, "timestamp": approval_time, "comments": comments, "overrides": overrides}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  new_overrides = list(self.human_overrides)
341
  if overrides:
342
+ new_overrides.append({"overrider": approver, "timestamp": approval_time, "overrides": overrides, "reason": comments})
343
+ new_approvals = list(self.approvals) + [approval_record]
 
 
 
 
 
 
 
 
344
  new_comments = list(self.comments)
345
  if comments:
346
+ new_comments.append({"author": approver, "timestamp": approval_time, "comment": comments})
 
 
 
 
 
347
  return HealingIntent(
348
+ action=self.action, component=self.component, parameters=self.parameters, justification=self.justification,
349
+ confidence=self.confidence, confidence_distribution=self.confidence_distribution, incident_id=self.incident_id,
350
+ detected_at=self.detected_at, risk_score=self.risk_score, risk_factors=self.risk_factors,
351
+ cost_projection=self.cost_projection, cost_confidence_interval=self.cost_confidence_interval,
352
+ recommended_action=self.recommended_action, decision_tree=self.decision_tree,
353
+ alternative_actions=self.alternative_actions, risk_profile=self.risk_profile,
354
+ reasoning_chain=self.reasoning_chain, similar_incidents=self.similar_incidents,
355
+ rag_similarity_score=self.rag_similarity_score, source=self.source, intent_id=self.intent_id,
356
+ created_at=self.created_at, status=IntentStatus.APPROVED_WITH_OVERRIDES if overrides else IntentStatus.APPROVED,
357
+ execution_id=self.execution_id, executed_at=self.executed_at, execution_result=self.execution_result,
358
+ enterprise_metadata=self.enterprise_metadata, human_overrides=new_overrides, approvals=new_approvals,
359
+ comments=new_comments, oss_edition=self.oss_edition, oss_license=self.oss_license,
360
+ requires_enterprise=self.requires_enterprise, execution_allowed=self.execution_allowed,
361
+ infrastructure_intent_id=self.infrastructure_intent_id, policy_violations=self.policy_violations,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  infrastructure_intent=self.infrastructure_intent
363
  )
364
 
365
  def mark_as_sent_to_enterprise(self) -> "HealingIntent":
 
 
 
 
 
366
  return HealingIntent(
367
+ action=self.action, component=self.component, parameters=self.parameters, justification=self.justification,
368
+ confidence=self.confidence, confidence_distribution=self.confidence_distribution, incident_id=self.incident_id,
369
+ detected_at=self.detected_at, risk_score=self.risk_score, risk_factors=self.risk_factors,
370
+ cost_projection=self.cost_projection, cost_confidence_interval=self.cost_confidence_interval,
371
+ recommended_action=self.recommended_action, decision_tree=self.decision_tree,
372
+ alternative_actions=self.alternative_actions, risk_profile=self.risk_profile,
373
+ reasoning_chain=self.reasoning_chain, similar_incidents=self.similar_incidents,
374
+ rag_similarity_score=self.rag_similarity_score, source=self.source, intent_id=self.intent_id,
375
+ created_at=self.created_at, status=IntentStatus.PENDING_EXECUTION, execution_id=self.execution_id,
376
+ executed_at=self.executed_at, execution_result=self.execution_result, enterprise_metadata=self.enterprise_metadata,
377
+ human_overrides=self.human_overrides, approvals=self.approvals, comments=self.comments,
378
+ oss_edition=self.oss_edition, oss_license=self.oss_license, requires_enterprise=self.requires_enterprise,
379
+ execution_allowed=self.execution_allowed, infrastructure_intent_id=self.infrastructure_intent_id,
380
+ policy_violations=self.policy_violations, infrastructure_intent=self.infrastructure_intent
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  )
382
 
383
  def mark_as_oss_advisory(self) -> "HealingIntent":
 
 
 
 
 
384
  return HealingIntent(
385
+ action=self.action, component=self.component, parameters=self.parameters, justification=self.justification,
386
+ confidence=self.confidence, confidence_distribution=self.confidence_distribution, incident_id=self.incident_id,
387
+ detected_at=self.detected_at, risk_score=self.risk_score, risk_factors=self.risk_factors,
388
+ cost_projection=self.cost_projection, cost_confidence_interval=self.cost_confidence_interval,
389
+ recommended_action=self.recommended_action, decision_tree=self.decision_tree,
390
+ alternative_actions=self.alternative_actions, risk_profile=self.risk_profile,
391
+ reasoning_chain=self.reasoning_chain, similar_incidents=self.similar_incidents,
392
+ rag_similarity_score=self.rag_similarity_score, source=self.source, intent_id=self.intent_id,
393
+ created_at=self.created_at, status=IntentStatus.OSS_ADVISORY_ONLY, execution_id=self.execution_id,
394
+ executed_at=self.executed_at, execution_result=self.execution_result, enterprise_metadata=self.enterprise_metadata,
395
+ human_overrides=self.human_overrides, approvals=self.approvals, comments=self.comments,
396
+ oss_edition=self.oss_edition, oss_license=self.oss_license, requires_enterprise=self.requires_enterprise,
397
+ execution_allowed=False, infrastructure_intent_id=self.infrastructure_intent_id,
398
+ policy_violations=self.policy_violations, infrastructure_intent=self.infrastructure_intent
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  )
400
 
401
  @classmethod
402
+ def from_infrastructure_intent(cls, infrastructure_intent: Any, action: str, component: str,
403
+ parameters: Dict[str, Any], justification: str, confidence: float = 0.85,
404
+ risk_score: Optional[float] = None, risk_factors: Optional[Dict[str, float]] = None,
405
+ cost_projection: Optional[float] = None, policy_violations: Optional[List[str]] = None,
406
+ recommended_action: Optional[RecommendedAction] = None,
407
+ source: IntentSource = IntentSource.INFRASTRUCTURE_ANALYSIS) -> "HealingIntent":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
  infrastructure_intent_id = getattr(infrastructure_intent, 'intent_id', None)
 
 
409
  if hasattr(infrastructure_intent, 'model_dump'):
410
  intent_dict = infrastructure_intent.model_dump()
411
  elif hasattr(infrastructure_intent, 'to_dict'):
412
  intent_dict = infrastructure_intent.to_dict()
413
  else:
414
  intent_dict = {"type": str(type(infrastructure_intent))}
 
415
  return cls(
416
+ action=action, component=component, parameters=parameters, justification=justification, confidence=confidence,
417
+ risk_score=risk_score, risk_factors=risk_factors, cost_projection=cost_projection,
418
+ policy_violations=policy_violations or [], recommended_action=recommended_action, source=source,
419
+ infrastructure_intent_id=infrastructure_intent_id, infrastructure_intent=intent_dict,
420
+ oss_edition=OSS_EDITION, requires_enterprise=True, execution_allowed=False
 
 
 
 
 
 
 
 
 
 
 
421
  )
422
 
423
  @classmethod
424
+ def from_analysis(cls, action: str, component: str, parameters: Dict[str, Any], justification: str,
425
+ confidence: float, confidence_std: float = 0.05,
426
+ similar_incidents: Optional[List[Dict[str, Any]]] = None,
427
+ reasoning_chain: Optional[List[Dict[str, Any]]] = None, incident_id: str = "",
428
+ source: IntentSource = IntentSource.OSS_ANALYSIS, rag_similarity_score: Optional[float] = None,
429
+ risk_score: Optional[float] = None, cost_projection: Optional[float] = None) -> "HealingIntent":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
430
  if similar_incidents and len(similar_incidents) > cls.MAX_SIMILAR_INCIDENTS:
431
  similar_incidents = similar_incidents[:cls.MAX_SIMILAR_INCIDENTS]
 
 
432
  conf_dist = ConfidenceDistribution(confidence, confidence_std)
 
 
433
  enhanced_confidence = confidence
434
  if similar_incidents:
435
+ similarity_scores = [inc.get("similarity", 0.0) for inc in similar_incidents if "similarity" in inc]
 
 
 
 
436
  if similarity_scores:
437
  avg_similarity = sum(similarity_scores) / len(similarity_scores)
 
438
  confidence_boost = min(0.2, avg_similarity * 0.3)
439
  enhanced_confidence = min(confidence * (1.0 + confidence_boost), cls.MAX_CONFIDENCE)
 
 
440
  final_rag_score = rag_similarity_score
441
  if final_rag_score is None and similar_incidents and len(similar_incidents) > 0:
442
+ top_similarities = [inc.get("similarity", 0.0) for inc in similar_incidents[:3] if "similarity" in inc]
 
 
 
 
 
443
  if top_similarities:
444
  final_rag_score = sum(top_similarities) / len(top_similarities)
 
445
  return cls(
446
+ action=action, component=component, parameters=parameters, justification=justification,
447
+ confidence=enhanced_confidence, confidence_distribution=conf_dist.to_dict(), incident_id=incident_id,
448
+ similar_incidents=similar_incidents, reasoning_chain=reasoning_chain, rag_similarity_score=final_rag_score,
449
+ source=source, risk_score=risk_score, cost_projection=cost_projection,
450
+ oss_edition=OSS_EDITION, requires_enterprise=True, execution_allowed=False
 
 
 
 
 
 
 
 
 
 
 
451
  )
452
 
453
  @classmethod
454
+ def from_rag_recommendation(cls, action: str, component: str, parameters: Dict[str, Any],
455
+ rag_similarity_score: float, similar_incidents: List[Dict[str, Any]],
456
+ justification_template: str = "Based on {count} similar historical incidents with {success_rate:.0%} success rate",
457
+ success_rate: Optional[float] = None, risk_score: Optional[float] = None,
458
+ cost_projection: Optional[float] = None) -> "HealingIntent":
 
 
 
 
 
 
 
 
 
 
 
 
459
  if not similar_incidents:
460
  raise ValidationError("RAG recommendation requires similar incidents")
 
 
461
  if success_rate is None:
462
  if len(similar_incidents) == 0:
463
  success_rate = 0.0
464
  else:
465
  successful = sum(1 for inc in similar_incidents if inc.get("success", False))
466
  success_rate = successful / len(similar_incidents)
467
+ justification = justification_template.format(count=len(similar_incidents), success_rate=success_rate or 0.0,
468
+ action=action, component=component)
469
+ base_confidence = rag_similarity_score * 0.8
 
 
 
 
 
 
 
 
470
  if success_rate:
471
  base_confidence = base_confidence * (0.7 + success_rate * 0.3)
472
+ return cls.from_analysis(action=action, component=component, parameters=parameters, justification=justification,
473
+ confidence=min(base_confidence, 0.95), similar_incidents=similar_incidents,
474
+ incident_id=similar_incidents[0].get("incident_id", "") if similar_incidents else "",
475
+ source=IntentSource.RAG_SIMILARITY, rag_similarity_score=rag_similarity_score,
476
+ risk_score=risk_score, cost_projection=cost_projection)
 
 
 
 
 
 
 
 
 
477
 
478
  @classmethod
479
  def from_dict(cls, data: Dict[str, Any]) -> "HealingIntent":
 
 
 
 
 
 
480
  version = data.get("version", "1.0.0")
 
 
481
  clean_data = data.copy()
 
 
482
  if "source" in clean_data and isinstance(clean_data["source"], str):
483
  clean_data["source"] = IntentSource(clean_data["source"])
 
484
  if "status" in clean_data and isinstance(clean_data["status"], str):
485
  clean_data["status"] = IntentStatus(clean_data["status"])
 
486
  if "recommended_action" in clean_data and isinstance(clean_data["recommended_action"], str):
487
  try:
488
  clean_data["recommended_action"] = RecommendedAction(clean_data["recommended_action"])
489
  except ValueError:
490
  clean_data["recommended_action"] = None
 
 
491
  clean_data.pop("deterministic_id", None)
492
  clean_data.pop("age_seconds", None)
493
  clean_data.pop("is_executable", None)
 
495
  clean_data.pop("requires_enterprise_upgrade", None)
496
  clean_data.pop("version", None)
497
  clean_data.pop("confidence_interval", None)
 
498
  return cls(**clean_data)
499
 
500
  def _normalize_parameters(self, params: Dict[str, Any]) -> Dict[str, Any]:
 
 
 
 
 
 
501
  normalized: Dict[str, Any] = {}
 
502
  for key, value in sorted(params.items()):
503
  normalized[key] = self._normalize_value(value)
 
504
  return normalized
505
 
506
  def _normalize_value(self, value: Any) -> Any:
 
507
  if isinstance(value, (int, float, str, bool, type(None))):
508
  return value
509
  elif isinstance(value, (list, tuple, set)):
510
+ return tuple(sorted(self._normalize_value(v) for v in value))
 
 
 
 
 
 
511
  elif isinstance(value, dict):
 
512
  return self._normalize_parameters(value)
513
  elif hasattr(value, '__dict__'):
 
514
  return self._normalize_parameters(value.__dict__)
515
  else:
 
516
  try:
517
  return str(value)
518
  except Exception:
 
519
  return f"<unserializable:{type(value).__name__}>"
520
 
521
  def get_oss_context(self) -> Dict[str, Any]:
 
 
 
 
 
522
  return {
523
  "reasoning_chain": self.reasoning_chain,
524
  "similar_incidents": self.similar_incidents,
 
534
  }
535
 
536
  def get_execution_summary(self) -> Dict[str, Any]:
 
 
 
 
 
537
  summary = {
538
  "intent_id": self.deterministic_id,
539
  "action": self.action,
 
552
  "policy_violations_count": len(self.policy_violations) if self.policy_violations else 0,
553
  "confidence_basis": self._get_confidence_basis(),
554
  }
 
555
  if self.executed_at:
556
  summary["executed_at"] = datetime.fromtimestamp(self.executed_at).isoformat()
557
  summary["execution_duration_seconds"] = self.executed_at - self.created_at
 
558
  if self.execution_result:
559
  summary["execution_success"] = self.execution_result.get("success", False)
560
  summary["execution_message"] = self.execution_result.get("message", "")
 
561
  if self.rag_similarity_score:
562
  summary["rag_similarity_score"] = self.rag_similarity_score
 
563
  if self.similar_incidents:
564
  summary["similar_incidents_count"] = len(self.similar_incidents)
 
565
  if self.approvals:
566
  summary["approvals_count"] = len(self.approvals)
567
  summary["approved_by"] = [a.get("approver") for a in self.approvals if a.get("approver")]
 
568
  if self.human_overrides:
569
  summary["overrides_count"] = len(self.human_overrides)
 
570
  return summary
571
 
572
  def is_immutable(self) -> bool:
 
573
  try:
 
574
  object.__setattr__(self, '_test_immutable', True)
575
  return False
576
  except Exception:
577
  return True
578
 
579
  def __repr__(self) -> str:
580
+ return (f"HealingIntent(id={self.deterministic_id[:8]}..., action={self.action}, "
581
+ f"component={self.component}, confidence={self.confidence:.2f}, "
582
+ f"risk={self.risk_score:.2f if self.risk_score else 'N/A'}, status={self.status.value})")
 
 
 
 
 
 
 
 
583
 
584
  class HealingIntentSerializer:
 
 
 
 
 
 
 
 
 
 
585
  SCHEMA_VERSION: ClassVar[str] = "2.0.0"
586
 
587
  @classmethod
588
  def serialize(cls, intent: HealingIntent, version: str = "2.0.0") -> Dict[str, Any]:
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  try:
590
  if version == "2.0.0":
591
  return {
 
604
  "has_cost_projection": intent.cost_projection is not None,
605
  }
606
  }
607
+ elif version in ["1.1.0", "1.0.0"]:
 
608
  data = intent.to_dict(include_oss_context=True)
 
 
609
  data.pop("confidence_distribution", None)
610
  data.pop("risk_score", None)
611
  data.pop("risk_factors", None)
 
621
  data.pop("infrastructure_intent_id", None)
622
  data.pop("policy_violations", None)
623
  data.pop("infrastructure_intent", None)
 
 
624
  if data.get("status") in [
625
  IntentStatus.EXECUTING_PARTIAL.value,
626
  IntentStatus.COMPLETED_PARTIAL.value,
 
630
  IntentStatus.APPROVED_WITH_OVERRIDES.value
631
  ]:
632
  data["status"] = IntentStatus.PENDING_EXECUTION.value
 
633
  return {
634
  "version": version,
635
  "schema_version": "1.1.0" if version == "1.1.0" else "1.0.0",
 
643
  }
644
  else:
645
  raise SerializationError(f"Unsupported version: {version}")
 
646
  except Exception as e:
647
  raise SerializationError(f"Failed to serialize HealingIntent: {e}") from e
648
 
649
  @classmethod
650
  def deserialize(cls, data: Dict[str, Any]) -> HealingIntent:
 
 
 
 
 
 
 
 
 
 
 
 
651
  try:
652
  version = data.get("version", "1.0.0")
653
+ intent_data = data.get("data", data)
 
654
  if version in ["2.0.0", "1.1.0", "1.0.0"]:
 
655
  if version.startswith("1."):
 
656
  intent_data.setdefault("confidence_distribution", None)
657
  intent_data.setdefault("risk_score", None)
658
  intent_data.setdefault("risk_factors", None)
 
668
  intent_data.setdefault("infrastructure_intent_id", None)
669
  intent_data.setdefault("policy_violations", [])
670
  intent_data.setdefault("infrastructure_intent", None)
 
671
  return HealingIntent.from_dict(intent_data)
672
  else:
673
  raise SerializationError(f"Unsupported version: {version}")
 
674
  except KeyError as e:
675
  raise SerializationError(f"Missing required field in serialized data: {e}") from e
676
  except Exception as e:
 
678
 
679
  @classmethod
680
  def to_json(cls, intent: HealingIntent, pretty: bool = False) -> str:
 
681
  try:
682
  serialized = cls.serialize(intent)
683
+ return json.dumps(serialized, indent=2 if pretty else None, default=str)
 
 
 
684
  except Exception as e:
685
  raise SerializationError(f"Failed to convert to JSON: {e}") from e
686
 
687
  @classmethod
688
  def from_json(cls, json_str: str) -> HealingIntent:
 
689
  try:
690
  data = json.loads(json_str)
691
  return cls.deserialize(data)
 
696
 
697
  @classmethod
698
  def to_enterprise_json(cls, intent: HealingIntent) -> str:
 
 
 
 
 
699
  try:
700
  enterprise_request = intent.to_enterprise_request()
701
  return json.dumps(enterprise_request, default=str)
 
704
 
705
  @classmethod
706
  def validate_for_oss(cls, intent: HealingIntent) -> bool:
 
 
 
 
 
 
707
  try:
 
708
  if intent.oss_edition != OSS_EDITION:
709
  return False
 
 
710
  if intent.execution_allowed:
711
  return False
 
 
712
  if intent.similar_incidents and len(intent.similar_incidents) > HealingIntent.MAX_SIMILAR_INCIDENTS:
713
  return False
 
 
714
  if not intent.is_immutable():
715
  return False
 
 
716
  if intent.executed_at is not None or intent.execution_id is not None:
717
  return False
 
718
  return True
 
719
  except Exception:
720
  return False
721
 
722
+ # Factory functions
723
+ def create_infrastructure_healing_intent(infrastructure_result: Any, action_mapping: Optional[Dict[str, str]] = None) -> HealingIntent:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
  if action_mapping is None:
725
+ action_mapping = {"approve": "execute", "deny": "block", "escalate": "escalate", "defer": "defer"}
 
 
 
 
 
 
 
726
  recommended_action = getattr(infrastructure_result, 'recommended_action', None)
727
  if recommended_action and hasattr(recommended_action, 'value'):
728
  action = action_mapping.get(recommended_action.value, "review")
729
  else:
730
  action = "review"
 
 
731
  parameters = {
732
  "infrastructure_intent_id": getattr(infrastructure_result, 'intent_id', None),
733
  "risk_score": getattr(infrastructure_result, 'risk_score', None),
 
735
  "policy_violations": getattr(infrastructure_result, 'policy_violations', []),
736
  "evaluation_details": getattr(infrastructure_result, 'evaluation_details', {})
737
  }
738
+ justification_parts = [getattr(infrastructure_result, 'justification', "Infrastructure analysis completed")]
 
 
 
 
 
739
  policy_violations = getattr(infrastructure_result, 'policy_violations', [])
740
  if policy_violations:
741
  justification_parts.append(f"Policy violations: {'; '.join(policy_violations)}")
 
742
  return HealingIntent.from_infrastructure_intent(
743
  infrastructure_intent=getattr(infrastructure_result, 'infrastructure_intent', None),
744
  action=action,
 
752
  source=IntentSource.INFRASTRUCTURE_ANALYSIS
753
  ).mark_as_oss_advisory()
754
 
755
+ def create_rollback_intent(component: str, revision: str = "previous", justification: str = "",
756
+ incident_id: str = "", similar_incidents: Optional[List[Dict[str, Any]]] = None,
757
+ rag_similarity_score: Optional[float] = None, risk_score: Optional[float] = None,
758
+ cost_projection: Optional[float] = None) -> HealingIntent:
 
 
 
 
 
 
 
 
759
  if not justification:
760
  justification = f"Rollback {component} to {revision} revision"
 
761
  return HealingIntent.from_analysis(
762
  action="rollback",
763
  component=component,
 
771
  cost_projection=cost_projection,
772
  ).mark_as_oss_advisory()
773
 
774
+ def create_restart_intent(component: str, container_id: Optional[str] = None, justification: str = "",
775
+ incident_id: str = "", similar_incidents: Optional[List[Dict[str, Any]]] = None,
776
+ rag_similarity_score: Optional[float] = None, risk_score: Optional[float] = None,
777
+ cost_projection: Optional[float] = None) -> HealingIntent:
 
 
 
 
 
 
 
 
778
  parameters = {}
779
  if container_id:
780
  parameters["container_id"] = container_id
 
781
  if not justification:
782
  justification = f"Restart container for {component}"
 
783
  return HealingIntent.from_analysis(
784
  action="restart_container",
785
  component=component,
 
793
  cost_projection=cost_projection,
794
  ).mark_as_oss_advisory()
795
 
796
+ def create_scale_out_intent(component: str, scale_factor: int = 2, justification: str = "",
797
+ incident_id: str = "", similar_incidents: Optional[List[Dict[str, Any]]] = None,
798
+ rag_similarity_score: Optional[float] = None, risk_score: Optional[float] = None,
799
+ cost_projection: Optional[float] = None) -> HealingIntent:
 
 
 
 
 
 
 
 
800
  if not justification:
801
  justification = f"Scale out {component} by factor {scale_factor}"
 
802
  return HealingIntent.from_analysis(
803
  action="scale_out",
804
  component=component,
 
812
  cost_projection=cost_projection,
813
  ).mark_as_oss_advisory()
814
 
815
+ def create_oss_advisory_intent(action: str, component: str, parameters: Dict[str, Any], justification: str,
816
+ confidence: float = 0.85, incident_id: str = "", risk_score: Optional[float] = None,
817
+ cost_projection: Optional[float] = None) -> HealingIntent:
 
 
 
 
 
 
 
 
 
 
 
 
 
818
  return HealingIntent(
819
  action=action,
820
  component=component,
 
830
  status=IntentStatus.OSS_ADVISORY_ONLY,
831
  )
832
 
 
 
833
  __all__ = [
 
834
  "HealingIntent",
 
 
835
  "ConfidenceDistribution",
836
  "HealingIntentSerializer",
 
 
837
  "IntentSource",
838
  "IntentStatus",
839
  "RecommendedAction",
 
 
840
  "HealingIntentError",
841
  "SerializationError",
842
  "ValidationError",
 
 
843
  "create_infrastructure_healing_intent",
844
  "create_rollback_intent",
845
  "create_restart_intent",