claude-mpm 4.3.22__py3-none-any.whl → 4.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/WORKFLOW.md +2 -14
- claude_mpm/cli/commands/configure.py +2 -29
- claude_mpm/cli/commands/doctor.py +2 -2
- claude_mpm/cli/commands/mpm_init.py +3 -3
- claude_mpm/cli/parsers/configure_parser.py +4 -15
- claude_mpm/core/framework/__init__.py +38 -0
- claude_mpm/core/framework/formatters/__init__.py +11 -0
- claude_mpm/core/framework/formatters/capability_generator.py +356 -0
- claude_mpm/core/framework/formatters/content_formatter.py +283 -0
- claude_mpm/core/framework/formatters/context_generator.py +180 -0
- claude_mpm/core/framework/loaders/__init__.py +13 -0
- claude_mpm/core/framework/loaders/agent_loader.py +202 -0
- claude_mpm/core/framework/loaders/file_loader.py +213 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +151 -0
- claude_mpm/core/framework/loaders/packaged_loader.py +208 -0
- claude_mpm/core/framework/processors/__init__.py +11 -0
- claude_mpm/core/framework/processors/memory_processor.py +222 -0
- claude_mpm/core/framework/processors/metadata_processor.py +146 -0
- claude_mpm/core/framework/processors/template_processor.py +238 -0
- claude_mpm/core/framework_loader.py +277 -1798
- claude_mpm/hooks/__init__.py +9 -1
- claude_mpm/hooks/kuzu_memory_hook.py +352 -0
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/services/agents/memory/content_manager.py +5 -2
- claude_mpm/services/agents/memory/memory_file_service.py +1 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +1 -0
- claude_mpm/services/core/path_resolver.py +1 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +1 -0
- claude_mpm/services/mcp_config_manager.py +67 -4
- claude_mpm/services/mcp_gateway/core/process_pool.py +281 -0
- claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +3 -13
- claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
- claude_mpm/services/mcp_gateway/tools/__init__.py +13 -2
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +36 -6
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +542 -0
- claude_mpm/services/shared/__init__.py +2 -1
- claude_mpm/services/shared/service_factory.py +8 -5
- claude_mpm/services/unified/__init__.py +65 -0
- claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +473 -0
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +643 -0
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +804 -0
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +661 -0
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +696 -0
- claude_mpm/services/unified/config_strategies/__init__.py +190 -0
- claude_mpm/services/unified/config_strategies/config_schema.py +689 -0
- claude_mpm/services/unified/config_strategies/context_strategy.py +748 -0
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +999 -0
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +871 -0
- claude_mpm/services/unified/config_strategies/unified_config_service.py +802 -0
- claude_mpm/services/unified/config_strategies/validation_strategy.py +1105 -0
- claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
- claude_mpm/services/unified/deployment_strategies/base.py +557 -0
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +486 -0
- claude_mpm/services/unified/deployment_strategies/local.py +594 -0
- claude_mpm/services/unified/deployment_strategies/utils.py +672 -0
- claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
- claude_mpm/services/unified/interfaces.py +499 -0
- claude_mpm/services/unified/migration.py +532 -0
- claude_mpm/services/unified/strategies.py +551 -0
- claude_mpm/services/unified/unified_analyzer.py +534 -0
- claude_mpm/services/unified/unified_config.py +688 -0
- claude_mpm/services/unified/unified_deployment.py +470 -0
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/METADATA +15 -15
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/RECORD +71 -32
- claude_mpm/cli/commands/configure_tui.py +0 -1927
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,532 @@
|
|
1
|
+
"""
|
2
|
+
Migration Utilities for Service Consolidation
|
3
|
+
=============================================
|
4
|
+
|
5
|
+
This module provides utilities for migrating from the existing 314 service files
|
6
|
+
to the consolidated unified service architecture. It includes service mapping,
|
7
|
+
backward compatibility wrappers, and feature flags for gradual rollout.
|
8
|
+
|
9
|
+
Key Components:
|
10
|
+
1. ServiceMapper: Maps legacy services to unified services
|
11
|
+
2. Compatibility wrappers: Maintain backward compatibility
|
12
|
+
3. Feature flags: Control gradual migration rollout
|
13
|
+
4. Migration status tracking: Monitor migration progress
|
14
|
+
|
15
|
+
Migration Strategy:
|
16
|
+
- Phase 1: Create unified interfaces and strategies
|
17
|
+
- Phase 2: Implement unified services with strategy pattern
|
18
|
+
- Phase 3: Create compatibility wrappers for legacy code
|
19
|
+
- Phase 4: Gradually migrate consumers to unified services
|
20
|
+
- Phase 5: Deprecate and remove legacy services
|
21
|
+
"""
|
22
|
+
|
23
|
+
import inspect
|
24
|
+
from dataclasses import dataclass, field
|
25
|
+
from enum import Enum
|
26
|
+
from pathlib import Path
|
27
|
+
from typing import Any, Callable, Dict, List, Optional, Set, Type, TypeVar
|
28
|
+
|
29
|
+
from claude_mpm.core.logging_utils import get_logger
|
30
|
+
|
31
|
+
logger = get_logger(__name__)
|
32
|
+
|
33
|
+
# Type variables
|
34
|
+
T = TypeVar("T")
|
35
|
+
ServiceType = TypeVar("ServiceType")
|
36
|
+
|
37
|
+
|
38
|
+
class MigrationStatus(Enum):
|
39
|
+
"""Status of service migration."""
|
40
|
+
|
41
|
+
NOT_STARTED = "not_started"
|
42
|
+
IN_PROGRESS = "in_progress"
|
43
|
+
TESTING = "testing"
|
44
|
+
COMPLETED = "completed"
|
45
|
+
DEPRECATED = "deprecated"
|
46
|
+
REMOVED = "removed"
|
47
|
+
|
48
|
+
|
49
|
+
class FeatureFlag(Enum):
|
50
|
+
"""Feature flags for controlling migration rollout."""
|
51
|
+
|
52
|
+
USE_UNIFIED_DEPLOYMENT = "use_unified_deployment"
|
53
|
+
USE_UNIFIED_ANALYZER = "use_unified_analyzer"
|
54
|
+
USE_UNIFIED_CONFIG = "use_unified_config"
|
55
|
+
ENABLE_COMPATIBILITY_MODE = "enable_compatibility_mode"
|
56
|
+
LOG_MIGRATION_WARNINGS = "log_migration_warnings"
|
57
|
+
ENFORCE_NEW_INTERFACES = "enforce_new_interfaces"
|
58
|
+
ALLOW_LEGACY_FALLBACK = "allow_legacy_fallback"
|
59
|
+
|
60
|
+
|
61
|
+
@dataclass
|
62
|
+
class ServiceMapping:
|
63
|
+
"""
|
64
|
+
Mapping between legacy service and unified service.
|
65
|
+
|
66
|
+
Attributes:
|
67
|
+
legacy_path: Path to legacy service module
|
68
|
+
legacy_class: Legacy service class name
|
69
|
+
unified_service: Unified service class
|
70
|
+
unified_strategy: Strategy to use in unified service
|
71
|
+
status: Migration status
|
72
|
+
compatibility_wrapper: Optional compatibility wrapper class
|
73
|
+
notes: Migration notes and considerations
|
74
|
+
"""
|
75
|
+
|
76
|
+
legacy_path: str
|
77
|
+
legacy_class: str
|
78
|
+
unified_service: str
|
79
|
+
unified_strategy: Optional[str] = None
|
80
|
+
status: MigrationStatus = MigrationStatus.NOT_STARTED
|
81
|
+
compatibility_wrapper: Optional[str] = None
|
82
|
+
notes: str = ""
|
83
|
+
|
84
|
+
|
85
|
+
@dataclass
|
86
|
+
class MigrationMetrics:
|
87
|
+
"""
|
88
|
+
Metrics for tracking migration progress.
|
89
|
+
|
90
|
+
Attributes:
|
91
|
+
total_services: Total number of services to migrate
|
92
|
+
migrated_services: Number of successfully migrated services
|
93
|
+
in_progress: Number of services currently being migrated
|
94
|
+
deprecated_services: Number of deprecated services
|
95
|
+
removed_services: Number of removed services
|
96
|
+
migration_errors: Count of migration errors
|
97
|
+
start_date: Migration start date
|
98
|
+
target_date: Target completion date
|
99
|
+
"""
|
100
|
+
|
101
|
+
total_services: int = 314 # Current service count
|
102
|
+
migrated_services: int = 0
|
103
|
+
in_progress: int = 0
|
104
|
+
deprecated_services: int = 0
|
105
|
+
removed_services: int = 0
|
106
|
+
migration_errors: int = 0
|
107
|
+
start_date: str = ""
|
108
|
+
target_date: str = ""
|
109
|
+
|
110
|
+
@property
|
111
|
+
def completion_percentage(self) -> float:
|
112
|
+
"""Calculate migration completion percentage."""
|
113
|
+
if self.total_services == 0:
|
114
|
+
return 0.0
|
115
|
+
return (self.migrated_services / self.total_services) * 100
|
116
|
+
|
117
|
+
@property
|
118
|
+
def remaining_services(self) -> int:
|
119
|
+
"""Calculate remaining services to migrate."""
|
120
|
+
return self.total_services - self.migrated_services - self.removed_services
|
121
|
+
|
122
|
+
|
123
|
+
class ServiceMapper:
|
124
|
+
"""
|
125
|
+
Maps legacy services to unified services and manages migration.
|
126
|
+
|
127
|
+
This class maintains the mapping between old service implementations
|
128
|
+
and new unified services, facilitating gradual migration.
|
129
|
+
"""
|
130
|
+
|
131
|
+
def __init__(self):
|
132
|
+
"""Initialize service mapper."""
|
133
|
+
self._mappings: Dict[str, ServiceMapping] = {}
|
134
|
+
self._feature_flags: Dict[FeatureFlag, bool] = {
|
135
|
+
flag: False for flag in FeatureFlag
|
136
|
+
}
|
137
|
+
self._metrics = MigrationMetrics()
|
138
|
+
self._logger = get_logger(f"{__name__}.ServiceMapper")
|
139
|
+
self._initialize_mappings()
|
140
|
+
|
141
|
+
def _initialize_mappings(self) -> None:
|
142
|
+
"""Initialize default service mappings."""
|
143
|
+
# Example mappings for deployment services
|
144
|
+
self.add_mapping(
|
145
|
+
ServiceMapping(
|
146
|
+
legacy_path="claude_mpm.services.agent_deployment",
|
147
|
+
legacy_class="AgentDeploymentService",
|
148
|
+
unified_service="UnifiedDeploymentService",
|
149
|
+
unified_strategy="AgentDeploymentStrategy",
|
150
|
+
status=MigrationStatus.NOT_STARTED,
|
151
|
+
notes="Consolidate with other deployment services",
|
152
|
+
)
|
153
|
+
)
|
154
|
+
|
155
|
+
# Example mappings for analyzer services
|
156
|
+
self.add_mapping(
|
157
|
+
ServiceMapping(
|
158
|
+
legacy_path="claude_mpm.services.code_analyzer",
|
159
|
+
legacy_class="CodeAnalyzer",
|
160
|
+
unified_service="UnifiedAnalyzer",
|
161
|
+
unified_strategy="CodeAnalysisStrategy",
|
162
|
+
status=MigrationStatus.NOT_STARTED,
|
163
|
+
notes="Merge with complexity and dependency analyzers",
|
164
|
+
)
|
165
|
+
)
|
166
|
+
|
167
|
+
# Example mappings for configuration services
|
168
|
+
self.add_mapping(
|
169
|
+
ServiceMapping(
|
170
|
+
legacy_path="claude_mpm.services.project_config",
|
171
|
+
legacy_class="ProjectConfigService",
|
172
|
+
unified_service="UnifiedConfigManager",
|
173
|
+
unified_strategy="ProjectConfigStrategy",
|
174
|
+
status=MigrationStatus.NOT_STARTED,
|
175
|
+
notes="Consolidate all config services",
|
176
|
+
)
|
177
|
+
)
|
178
|
+
|
179
|
+
def add_mapping(self, mapping: ServiceMapping) -> None:
|
180
|
+
"""
|
181
|
+
Add a service mapping.
|
182
|
+
|
183
|
+
Args:
|
184
|
+
mapping: Service mapping to add
|
185
|
+
"""
|
186
|
+
key = f"{mapping.legacy_path}.{mapping.legacy_class}"
|
187
|
+
self._mappings[key] = mapping
|
188
|
+
self._logger.debug(f"Added mapping for {key}")
|
189
|
+
|
190
|
+
def get_mapping(self, legacy_service: str) -> Optional[ServiceMapping]:
|
191
|
+
"""
|
192
|
+
Get mapping for a legacy service.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
legacy_service: Legacy service identifier
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
Optional[ServiceMapping]: Service mapping if found
|
199
|
+
"""
|
200
|
+
return self._mappings.get(legacy_service)
|
201
|
+
|
202
|
+
def get_unified_service(
|
203
|
+
self, legacy_path: str, legacy_class: str
|
204
|
+
) -> Optional[str]:
|
205
|
+
"""
|
206
|
+
Get unified service for a legacy service.
|
207
|
+
|
208
|
+
Args:
|
209
|
+
legacy_path: Legacy service module path
|
210
|
+
legacy_class: Legacy service class name
|
211
|
+
|
212
|
+
Returns:
|
213
|
+
Optional[str]: Unified service name if mapped
|
214
|
+
"""
|
215
|
+
key = f"{legacy_path}.{legacy_class}"
|
216
|
+
mapping = self._mappings.get(key)
|
217
|
+
return mapping.unified_service if mapping else None
|
218
|
+
|
219
|
+
def update_status(
|
220
|
+
self, legacy_service: str, status: MigrationStatus
|
221
|
+
) -> bool:
|
222
|
+
"""
|
223
|
+
Update migration status for a service.
|
224
|
+
|
225
|
+
Args:
|
226
|
+
legacy_service: Legacy service identifier
|
227
|
+
status: New migration status
|
228
|
+
|
229
|
+
Returns:
|
230
|
+
bool: True if status updated
|
231
|
+
"""
|
232
|
+
mapping = self._mappings.get(legacy_service)
|
233
|
+
if not mapping:
|
234
|
+
return False
|
235
|
+
|
236
|
+
old_status = mapping.status
|
237
|
+
mapping.status = status
|
238
|
+
|
239
|
+
# Update metrics
|
240
|
+
if old_status != status:
|
241
|
+
if status == MigrationStatus.COMPLETED:
|
242
|
+
self._metrics.migrated_services += 1
|
243
|
+
elif status == MigrationStatus.IN_PROGRESS:
|
244
|
+
self._metrics.in_progress += 1
|
245
|
+
elif status == MigrationStatus.DEPRECATED:
|
246
|
+
self._metrics.deprecated_services += 1
|
247
|
+
elif status == MigrationStatus.REMOVED:
|
248
|
+
self._metrics.removed_services += 1
|
249
|
+
|
250
|
+
self._logger.info(
|
251
|
+
f"Updated {legacy_service} status: {old_status} -> {status}"
|
252
|
+
)
|
253
|
+
return True
|
254
|
+
|
255
|
+
def set_feature_flag(self, flag: FeatureFlag, enabled: bool) -> None:
|
256
|
+
"""
|
257
|
+
Set a feature flag value.
|
258
|
+
|
259
|
+
Args:
|
260
|
+
flag: Feature flag to set
|
261
|
+
enabled: Whether to enable the flag
|
262
|
+
"""
|
263
|
+
self._feature_flags[flag] = enabled
|
264
|
+
self._logger.info(f"Feature flag {flag.value} set to {enabled}")
|
265
|
+
|
266
|
+
def is_feature_enabled(self, flag: FeatureFlag) -> bool:
|
267
|
+
"""
|
268
|
+
Check if a feature flag is enabled.
|
269
|
+
|
270
|
+
Args:
|
271
|
+
flag: Feature flag to check
|
272
|
+
|
273
|
+
Returns:
|
274
|
+
bool: True if feature is enabled
|
275
|
+
"""
|
276
|
+
return self._feature_flags.get(flag, False)
|
277
|
+
|
278
|
+
def get_metrics(self) -> MigrationMetrics:
|
279
|
+
"""
|
280
|
+
Get migration metrics.
|
281
|
+
|
282
|
+
Returns:
|
283
|
+
MigrationMetrics: Current migration metrics
|
284
|
+
"""
|
285
|
+
return self._metrics
|
286
|
+
|
287
|
+
def list_mappings(
|
288
|
+
self, status_filter: Optional[MigrationStatus] = None
|
289
|
+
) -> List[ServiceMapping]:
|
290
|
+
"""
|
291
|
+
List all service mappings.
|
292
|
+
|
293
|
+
Args:
|
294
|
+
status_filter: Optional filter by migration status
|
295
|
+
|
296
|
+
Returns:
|
297
|
+
List[ServiceMapping]: List of service mappings
|
298
|
+
"""
|
299
|
+
mappings = list(self._mappings.values())
|
300
|
+
|
301
|
+
if status_filter:
|
302
|
+
mappings = [m for m in mappings if m.status == status_filter]
|
303
|
+
|
304
|
+
return mappings
|
305
|
+
|
306
|
+
|
307
|
+
def create_compatibility_wrapper(
|
308
|
+
legacy_class: Type[T],
|
309
|
+
unified_service: Any,
|
310
|
+
method_mappings: Optional[Dict[str, str]] = None,
|
311
|
+
) -> Type[T]:
|
312
|
+
"""
|
313
|
+
Create a compatibility wrapper for a legacy service.
|
314
|
+
|
315
|
+
This function dynamically creates a wrapper class that maintains the
|
316
|
+
legacy interface while delegating to the unified service implementation.
|
317
|
+
|
318
|
+
Args:
|
319
|
+
legacy_class: Legacy service class to wrap
|
320
|
+
unified_service: Unified service instance
|
321
|
+
method_mappings: Optional mapping of legacy to unified method names
|
322
|
+
|
323
|
+
Returns:
|
324
|
+
Type[T]: Wrapper class maintaining legacy interface
|
325
|
+
"""
|
326
|
+
method_mappings = method_mappings or {}
|
327
|
+
|
328
|
+
class CompatibilityWrapper:
|
329
|
+
"""
|
330
|
+
Dynamic compatibility wrapper for legacy services.
|
331
|
+
|
332
|
+
This wrapper maintains the legacy interface while delegating
|
333
|
+
operations to the unified service implementation.
|
334
|
+
"""
|
335
|
+
|
336
|
+
def __init__(self, *args, **kwargs):
|
337
|
+
"""Initialize wrapper with unified service."""
|
338
|
+
self._unified_service = unified_service
|
339
|
+
self._logger = get_logger(
|
340
|
+
f"{__name__}.{legacy_class.__name__}Wrapper"
|
341
|
+
)
|
342
|
+
self._logger.debug(
|
343
|
+
f"Created compatibility wrapper for {legacy_class.__name__}"
|
344
|
+
)
|
345
|
+
|
346
|
+
def __getattr__(self, name: str) -> Any:
|
347
|
+
"""
|
348
|
+
Delegate attribute access to unified service.
|
349
|
+
|
350
|
+
Args:
|
351
|
+
name: Attribute name
|
352
|
+
|
353
|
+
Returns:
|
354
|
+
Any: Attribute value from unified service
|
355
|
+
|
356
|
+
Raises:
|
357
|
+
AttributeError: If attribute not found
|
358
|
+
"""
|
359
|
+
# Check if method is mapped to a different name
|
360
|
+
unified_name = method_mappings.get(name, name)
|
361
|
+
|
362
|
+
# Try to get from unified service
|
363
|
+
if hasattr(self._unified_service, unified_name):
|
364
|
+
attr = getattr(self._unified_service, unified_name)
|
365
|
+
|
366
|
+
# Log deprecation warning if configured
|
367
|
+
if ServiceMapper().is_feature_enabled(
|
368
|
+
FeatureFlag.LOG_MIGRATION_WARNINGS
|
369
|
+
):
|
370
|
+
self._logger.warning(
|
371
|
+
f"Using compatibility wrapper for {legacy_class.__name__}.{name}. "
|
372
|
+
f"Please migrate to unified service."
|
373
|
+
)
|
374
|
+
|
375
|
+
return attr
|
376
|
+
|
377
|
+
# Fallback to legacy implementation if allowed
|
378
|
+
if ServiceMapper().is_feature_enabled(
|
379
|
+
FeatureFlag.ALLOW_LEGACY_FALLBACK
|
380
|
+
):
|
381
|
+
if hasattr(legacy_class, name):
|
382
|
+
self._logger.warning(
|
383
|
+
f"Falling back to legacy implementation for {name}"
|
384
|
+
)
|
385
|
+
return getattr(legacy_class, name)
|
386
|
+
|
387
|
+
raise AttributeError(
|
388
|
+
f"'{legacy_class.__name__}' wrapper has no attribute '{name}'"
|
389
|
+
)
|
390
|
+
|
391
|
+
# Copy class metadata
|
392
|
+
CompatibilityWrapper.__name__ = legacy_class.__name__
|
393
|
+
CompatibilityWrapper.__module__ = legacy_class.__module__
|
394
|
+
CompatibilityWrapper.__doc__ = (
|
395
|
+
f"Compatibility wrapper for {legacy_class.__name__}.\n\n"
|
396
|
+
f"This class maintains backward compatibility while delegating to "
|
397
|
+
f"the unified service implementation."
|
398
|
+
)
|
399
|
+
|
400
|
+
# Copy method signatures for better IDE support
|
401
|
+
for name, method in inspect.getmembers(legacy_class, inspect.isfunction):
|
402
|
+
if not name.startswith("_"):
|
403
|
+
setattr(CompatibilityWrapper, name, method)
|
404
|
+
|
405
|
+
return CompatibilityWrapper
|
406
|
+
|
407
|
+
|
408
|
+
class MigrationValidator:
|
409
|
+
"""
|
410
|
+
Validates migration compatibility and correctness.
|
411
|
+
|
412
|
+
This class ensures that unified services properly implement
|
413
|
+
the functionality of the legacy services they replace.
|
414
|
+
"""
|
415
|
+
|
416
|
+
def __init__(self):
|
417
|
+
"""Initialize migration validator."""
|
418
|
+
self._logger = get_logger(f"{__name__}.MigrationValidator")
|
419
|
+
|
420
|
+
def validate_interface_compatibility(
|
421
|
+
self, legacy_class: Type, unified_class: Type
|
422
|
+
) -> List[str]:
|
423
|
+
"""
|
424
|
+
Validate that unified service implements legacy interface.
|
425
|
+
|
426
|
+
Args:
|
427
|
+
legacy_class: Legacy service class
|
428
|
+
unified_class: Unified service class
|
429
|
+
|
430
|
+
Returns:
|
431
|
+
List[str]: List of compatibility issues
|
432
|
+
"""
|
433
|
+
issues = []
|
434
|
+
|
435
|
+
# Get public methods from legacy class
|
436
|
+
legacy_methods = {
|
437
|
+
name for name, _ in inspect.getmembers(
|
438
|
+
legacy_class, inspect.ismethod
|
439
|
+
)
|
440
|
+
if not name.startswith("_")
|
441
|
+
}
|
442
|
+
|
443
|
+
# Get public methods from unified class
|
444
|
+
unified_methods = {
|
445
|
+
name for name, _ in inspect.getmembers(
|
446
|
+
unified_class, inspect.ismethod
|
447
|
+
)
|
448
|
+
if not name.startswith("_")
|
449
|
+
}
|
450
|
+
|
451
|
+
# Check for missing methods
|
452
|
+
missing = legacy_methods - unified_methods
|
453
|
+
if missing:
|
454
|
+
issues.append(
|
455
|
+
f"Missing methods in unified service: {', '.join(missing)}"
|
456
|
+
)
|
457
|
+
|
458
|
+
# Check method signatures
|
459
|
+
for method_name in legacy_methods & unified_methods:
|
460
|
+
legacy_sig = inspect.signature(getattr(legacy_class, method_name))
|
461
|
+
unified_sig = inspect.signature(getattr(unified_class, method_name))
|
462
|
+
|
463
|
+
if legacy_sig != unified_sig:
|
464
|
+
issues.append(
|
465
|
+
f"Method signature mismatch for {method_name}: "
|
466
|
+
f"legacy={legacy_sig}, unified={unified_sig}"
|
467
|
+
)
|
468
|
+
|
469
|
+
return issues
|
470
|
+
|
471
|
+
def validate_behavior_compatibility(
|
472
|
+
self,
|
473
|
+
legacy_instance: Any,
|
474
|
+
unified_instance: Any,
|
475
|
+
test_cases: List[Dict[str, Any]],
|
476
|
+
) -> List[str]:
|
477
|
+
"""
|
478
|
+
Validate that unified service behavior matches legacy.
|
479
|
+
|
480
|
+
Args:
|
481
|
+
legacy_instance: Legacy service instance
|
482
|
+
unified_instance: Unified service instance
|
483
|
+
test_cases: List of test cases with method, args, kwargs
|
484
|
+
|
485
|
+
Returns:
|
486
|
+
List[str]: List of behavior differences
|
487
|
+
"""
|
488
|
+
differences = []
|
489
|
+
|
490
|
+
for test_case in test_cases:
|
491
|
+
method_name = test_case["method"]
|
492
|
+
args = test_case.get("args", ())
|
493
|
+
kwargs = test_case.get("kwargs", {})
|
494
|
+
|
495
|
+
try:
|
496
|
+
# Execute on legacy service
|
497
|
+
legacy_result = getattr(legacy_instance, method_name)(
|
498
|
+
*args, **kwargs
|
499
|
+
)
|
500
|
+
|
501
|
+
# Execute on unified service
|
502
|
+
unified_result = getattr(unified_instance, method_name)(
|
503
|
+
*args, **kwargs
|
504
|
+
)
|
505
|
+
|
506
|
+
# Compare results
|
507
|
+
if legacy_result != unified_result:
|
508
|
+
differences.append(
|
509
|
+
f"Different results for {method_name}: "
|
510
|
+
f"legacy={legacy_result}, unified={unified_result}"
|
511
|
+
)
|
512
|
+
|
513
|
+
except Exception as e:
|
514
|
+
differences.append(
|
515
|
+
f"Error testing {method_name}: {str(e)}"
|
516
|
+
)
|
517
|
+
|
518
|
+
return differences
|
519
|
+
|
520
|
+
|
521
|
+
# Global service mapper instance
|
522
|
+
_global_mapper = ServiceMapper()
|
523
|
+
|
524
|
+
|
525
|
+
def get_service_mapper() -> ServiceMapper:
|
526
|
+
"""
|
527
|
+
Get the global service mapper instance.
|
528
|
+
|
529
|
+
Returns:
|
530
|
+
ServiceMapper: Global mapper instance
|
531
|
+
"""
|
532
|
+
return _global_mapper
|