Skip to content

Test Inheritance

Overview

Test inheritance is the mechanism by which higher-level components automatically benefit from the validation of their dependencies, both within a single framework and across multiple agent frameworks. This document details how test results flow through the component hierarchy and how to implement efficient inheritance patterns that maximize test reuse through framework-agnostic validation.

Inheritance Principles

1. Once Tested, Always Trusted

When a foundation component passes testing, all components using it can trust those results without retesting. For framework-agnostic components (LLMs and MCP Servers), this trust extends across ALL frameworks:

LLM passes prompt injection test at 10:00 AM (via Aurite framework)
Agent A using this LLM at 10:30 AM (LangChain) → Inherits "PASS"
Agent B using this LLM at 10:45 AM (AutoGen) → Inherits "PASS"
Agent C using this LLM at 11:00 AM (Aurite) → Inherits "PASS"
No need to retest prompt injection for any agent in any framework

Security scores propagate using the minimum value principle:

Workflow Security Score = MIN(
    Agent1 Security,
    Agent2 Security,
    Workflow-Specific Security
)

Where each Agent Security = MIN(
    LLM Security (100% agnostic),
    MCP Security (100% agnostic),
    Agent-Specific Security (40% framework-specific)
)

3. Composite Quality

Quality scores combine multiplicatively to reflect cumulative degradation:

Workflow Quality =
    (Agent1 Quality × Weight1) +
    (Agent2 Quality × Weight2) +
    (Workflow Quality × Weight3)

Where weights sum to 1.0

4. Cross-Framework Inheritance

Framework-agnostic test results are inherited across all framework implementations:

Component Agnostic % → Cross-Framework Inheritance
LLM: 100% → All results shared across frameworks
MCP: 100% → All results shared across frameworks
Agent: 60% → Core behavior results shared
Workflow: 20% → Business logic results shared

Inheritance Data Model

Test Result Structure

@dataclass
class TestResult:
    """Base test result with inheritance support"""
    component_id: str
    component_type: str
    timestamp: datetime
    version: str

    # Framework context
    framework: str  # Framework that ran the test
    is_agnostic: bool  # Whether results are framework-agnostic
    cross_framework_validity: bool  # Can be shared across frameworks

    # Direct test results
    direct_tests: Dict[str, TestScore]

    # Inherited results
    inherited_results: Dict[str, InheritedResult]

    # Composite scores
    composite_scores: CompositeScores

    # Metadata
    dependencies: List[ComponentDependency]
    inheritance_chain: List[str]
    confidence_level: float
    framework_confidence: Dict[str, float]  # Confidence per framework

@dataclass
class InheritedResult:
    """Represents an inherited test result"""
    source_component: str
    source_version: str
    source_framework: str  # Framework that originally ran the test
    original_timestamp: datetime
    test_name: str
    score: float
    status: str
    ttl_remaining: int  # Time-to-live in seconds
    is_universal: bool  # True for framework-agnostic results
    inheritance_type: str  # "direct", "cross-framework", "transformed"

@dataclass
class CompositeScores:
    """Aggregated scores with inheritance"""
    quality: float
    security: float
    performance: float
    reliability: float

    # Breakdown by source
    quality_breakdown: Dict[str, float]
    security_breakdown: Dict[str, float]

Inheritance Patterns

Pattern 1: Direct Inheritance

Simple pass-through of test results from dependency to dependent within the same framework:

class DirectInheritance:
    def inherit_results(self, component, dependency_results):
        inherited = {}

        for dep_id, dep_result in dependency_results.items():
            # Direct inheritance of applicable tests
            for test_name, test_score in dep_result.direct_tests.items():
                if self.is_inheritable(test_name, component.type):
                    inherited[f"{dep_id}.{test_name}"] = InheritedResult(
                        source_component=dep_id,
                        source_version=dep_result.version,
                        original_timestamp=dep_result.timestamp,
                        test_name=test_name,
                        score=test_score.value,
                        status=test_score.status,
                        ttl_remaining=self.calculate_ttl(dep_result)
                    )

        return inherited

Pattern 2: Filtered Inheritance

Selective inheritance based on relevance:

class FilteredInheritance:
    # Define what each component type inherits
    INHERITANCE_RULES = {
        "agent": {
            "from_llm": [
                "prompt_injection_resistance",
                "content_safety",
                "output_format_compliance"
            ],
            "from_mcp": [
                "api_availability",
                "authentication_status",
                "rate_limit_compliance"
            ]
        },
        "workflow": {
            "from_agent": [
                "goal_achievement_rate",
                "tool_usage_efficiency",
                "security_compliance"
            ]
        }
    }

    def inherit_filtered(self, component_type, source_type, test_results):
        rules = self.INHERITANCE_RULES.get(component_type, {})
        inheritable_tests = rules.get(f"from_{source_type}", [])

        return {
            test: result
            for test, result in test_results.items()
            if test in inheritable_tests
        }

Pattern 3: Transformed Inheritance

Modify inherited scores based on context:

class TransformedInheritance:
    def inherit_with_transformation(self, component, dependency_results):
        inherited = {}

        for dep_id, dep_result in dependency_results.items():
            # Apply transformation based on dependency importance
            importance = self.get_dependency_importance(component, dep_id)

            for test_name, score in dep_result.items():
                # Transform score based on importance
                transformed_score = self.transform_score(
                    score,
                    importance,
                    component.risk_profile
                )

                inherited[f"{dep_id}.{test_name}"] = transformed_score

        return inherited

    def transform_score(self, original_score, importance, risk_profile):
        if risk_profile == "high":
            # More conservative for high-risk components
            return original_score * 0.9 * importance
        elif risk_profile == "low":
            # More lenient for low-risk components
            return min(1.0, original_score * 1.1 * importance)
        else:
            return original_score * importance

Pattern 4: Universal Inheritance

Framework-agnostic results that propagate across all frameworks:

class UniversalInheritance:
    def inherit_universal(self, component, dependency_results, target_framework):
        inherited = {}

        for dep_id, dep_result in dependency_results.items():
            # Check if results are framework-agnostic
            if dep_result.is_agnostic or dep_result.component_type in ["llm", "mcp"]:
                for test_name, test_score in dep_result.direct_tests.items():
                    inherited[f"{dep_id}.{test_name}"] = InheritedResult(
                        source_component=dep_id,
                        source_version=dep_result.version,
                        source_framework=dep_result.framework,
                        original_timestamp=dep_result.timestamp,
                        test_name=test_name,
                        score=test_score.value,
                        status=test_score.status,
                        ttl_remaining=self.calculate_universal_ttl(dep_result),
                        is_universal=True,
                        inheritance_type="cross-framework"
                    )

        return inherited

Pattern 5: Framework Boundary Inheritance

Handle inheritance when components use different frameworks:

class FrameworkBoundaryInheritance:
    def inherit_across_frameworks(self, component, dependency_results):
        inherited = {}
        adapter = self.get_framework_adapter(component.framework)

        for dep_id, dep_result in dependency_results.items():
            # Determine what can be inherited
            if dep_result.framework != component.framework:
                # Only inherit agnostic results across framework boundaries
                agnostic_percentage = self.get_agnostic_percentage(dep_result.component_type)

                for test_name, test_score in dep_result.direct_tests.items():
                    if self.is_agnostic_test(test_name, dep_result.component_type):
                        # Translate and inherit
                        translated_result = adapter.translate_result(test_score)
                        inherited[f"{dep_id}.{test_name}"] = translated_result
            else:
                # Same framework - inherit everything
                inherited.update(self.inherit_direct(dep_id, dep_result))

        return inherited

Inheritance Lifecycle

1. Test Execution Phase

async def execute_with_inheritance(component, framework="aurite"):
    # Step 1: Check universal cache for agnostic results
    universal_results = await check_universal_cache(component.dependencies)

    # Step 2: Gather framework-specific dependency results
    dep_results = await gather_dependency_results(component.dependencies, framework)

    # Step 3: Merge universal and framework-specific results
    all_results = merge_results(universal_results, dep_results)

    # Step 4: Check if dependencies passed
    if not all_dependencies_passed(all_results):
        return blocked_result(component, all_results)

    # Step 5: Inherit applicable results (both agnostic and specific)
    inherited = inherit_results(component, all_results, framework)

    # Step 6: Run component-specific tests
    agnostic_tests, specific_tests = categorize_tests(component)
    direct_tests = await run_direct_tests(component, agnostic_tests, specific_tests)

    # Step 7: Combine and cache results
    final_results = combine_results(inherited, direct_tests)
    cache_results(final_results, framework)

    return final_results

2. Result Aggregation Phase

def aggregate_inherited_results(inherited_results, direct_results):
    aggregated = {
        "quality": calculate_quality_score(inherited_results, direct_results),
        "security": calculate_security_score(inherited_results, direct_results),
        "performance": calculate_performance_score(inherited_results, direct_results)
    }

    # Add confidence based on inheritance freshness
    aggregated["confidence"] = calculate_confidence(inherited_results)

    return aggregated

def calculate_confidence(inherited_results):
    """Calculate confidence based on age and version of inherited results"""
    confidence = 1.0

    for result in inherited_results.values():
        age_factor = 1.0 - (time_since(result.original_timestamp) / MAX_AGE)
        version_factor = 1.0 if result.source_version == CURRENT_VERSION else 0.8

        confidence *= (age_factor * version_factor)

    return max(0.5, confidence)  # Minimum 50% confidence

3. Cache Management Phase

class InheritanceCache:
    def __init__(self):
        self.universal_cache = {}  # Framework-agnostic results
        self.framework_cache = {}  # Framework-specific results
        self.version_map = {}

    def store_result(self, component_id, result, framework="aurite"):
        """Store result with framework context"""
        cache_entry = {
            "result": result,
            "timestamp": datetime.now(),
            "version": result.version,
            "framework": framework,
            "inheritable_until": self.calculate_ttl(result)
        }

        # Store in appropriate cache
        if result.is_agnostic or result.component_type in ["llm", "mcp"]:
            self.universal_cache[component_id] = cache_entry
            cache_entry["inheritable_until"] = datetime.now() + timedelta(hours=24)
        else:
            if framework not in self.framework_cache:
                self.framework_cache[framework] = {}
            self.framework_cache[framework][component_id] = cache_entry

        # Track version for invalidation
        self.version_map[component_id] = result.version

    def get_inheritable_result(self, component_id, framework="aurite"):
        """Get result from universal or framework cache"""
        # Check universal cache first
        if component_id in self.universal_cache:
            cached = self.universal_cache[component_id]
            if self.is_valid_cache(cached):
                return cached["result"]

        # Check framework-specific cache
        if framework in self.framework_cache:
            if component_id in self.framework_cache[framework]:
                cached = self.framework_cache[framework][component_id]
                if self.is_valid_cache(cached):
                    return cached["result"]

        return None

    def is_valid_cache(self, cached):
        """Check if cached result is still valid"""
        if datetime.now() > cached["inheritable_until"]:
            return False
        if self.version_map.get(cached["result"].component_id) != cached["version"]:
            return False
        return True

    def invalidate_cascade(self, component_id, framework=None):
        """Invalidate component and all dependents"""
        # Remove from universal cache
        if component_id in self.universal_cache:
            del self.universal_cache[component_id]
            # Universal invalidation affects all frameworks
            for fw in self.framework_cache.values():
                if component_id in fw:
                    del fw[component_id]

        # Remove from specific framework cache
        elif framework and framework in self.framework_cache:
            if component_id in self.framework_cache[framework]:
                del self.framework_cache[framework][component_id]

        # Find and invalidate dependents
        dependents = self.find_dependents(component_id)
        for dep in dependents:
            self.invalidate_cascade(dep, framework)

    def calculate_ttl(self, result):
        """Calculate TTL based on component type and framework scope"""
        ttl_map = {
            "llm": timedelta(hours=24),      # 100% agnostic
            "mcp": timedelta(hours=24),      # 100% agnostic
            "agent": timedelta(hours=12),    # 60% agnostic
            "workflow": timedelta(hours=1)   # 20% agnostic
        }
        return datetime.now() + ttl_map.get(result.component_type, timedelta(hours=4))

Inheritance Rules by Component Type

LLM Inheritance Rules

LLMs are foundation components and don't inherit:

LLM_INHERITANCE = {
    "inherits_from": [],
    "provides_to": ["agent"],
    "framework_agnostic": True,  # 100% agnostic
    "cross_framework_inheritance": 1.0,  # All results shared
    "inheritable_tests": [
        "prompt_injection_resistance",
        "content_safety_score",
        "hallucination_rate",
        "instruction_following_accuracy",
        "output_format_compliance"
    ],
    "cache_ttl": 24  # Hours - longer for agnostic components
}

MCP Server Inheritance Rules

MCP Servers are foundation components and don't inherit:

MCP_INHERITANCE = {
    "inherits_from": [],
    "provides_to": ["agent"],
    "framework_agnostic": True,  # 100% agnostic
    "cross_framework_inheritance": 1.0,  # All results shared
    "inheritable_tests": [
        "api_availability",
        "response_time_p95",
        "error_rate",
        "authentication_validity",
        "rate_limit_compliance"
    ],
    "cache_ttl": 24  # Hours - longer for agnostic components
}

Agent Inheritance Rules

Agents inherit from both LLMs and MCP Servers:

AGENT_INHERITANCE = {
    "inherits_from": ["llm", "mcp_server"],
    "provides_to": ["workflow"],
    "framework_agnostic": False,  # Hybrid
    "cross_framework_inheritance": 0.6,  # 60% agnostic
    "inheritable_tests": {
        "agnostic": [  # Cross-framework tests
            "goal_achievement_rate",
            "tool_selection_accuracy"
        ],
        "specific": [  # Framework-specific tests
            "multi_turn_coherence",
            "resource_efficiency",
            "security_compliance"
        ]
    },
    "inheritance_weights": {
        "llm": 0.4,
        "mcp_server": 0.3,
        "agent_specific": 0.3
    },
    "cache_ttl": {
        "agnostic": 12,  # Hours for agnostic results
        "specific": 4    # Hours for specific results
    }
}

Workflow Inheritance Rules

Workflows inherit from all constituent agents:

WORKFLOW_INHERITANCE = {
    "inherits_from": ["agent"],
    "provides_to": [],
    "framework_agnostic": False,  # Mostly specific
    "cross_framework_inheritance": 0.2,  # 20% agnostic
    "inheritable_tests": {
        "agnostic": [  # Cross-framework tests
            "business_logic_compliance",
            "end_to_end_success_rate"
        ],
        "specific": [  # Framework-specific tests
            "sla_adherence",
            "data_consistency",
            "audit_completeness"
        ]
    },
    "inheritance_weights": "dynamic",  # Based on agent importance
    "cache_ttl": {
        "agnostic": 4,   # Hours for agnostic results
        "specific": 1    # Hour for specific results
    }
}

Inheritance Validation

Ensuring Inheritance Integrity

class InheritanceValidator:
    def validate_inheritance_chain(self, component_result):
        """Validate that inheritance chain is complete and valid"""
        issues = []

        # Check all required dependencies are present
        for dep in component_result.dependencies:
            if dep.id not in component_result.inherited_results:
                issues.append(f"Missing inheritance from {dep.id}")

        # Check inheritance freshness
        for inherited in component_result.inherited_results.values():
            if inherited.ttl_remaining <= 0:
                issues.append(f"Expired inheritance from {inherited.source_component}")

        # Check version compatibility
        for inherited in component_result.inherited_results.values():
            if not self.is_version_compatible(inherited.source_version):
                issues.append(f"Incompatible version from {inherited.source_component}")

        return issues

Framework Adaptation in Inheritance

Cross-Framework Confidence Scoring

def calculate_cross_framework_confidence(inherited_result, target_framework):
    """Calculate confidence when inheriting across frameworks"""
    base_confidence = inherited_result.confidence_level

    # Adjust confidence based on framework compatibility
    if inherited_result.is_universal:
        # Universal results maintain high confidence
        return base_confidence * 0.95
    elif inherited_result.source_framework == target_framework:
        # Same framework maintains full confidence
        return base_confidence
    else:
        # Cross-framework inheritance reduces confidence
        agnostic_ratio = get_agnostic_ratio(inherited_result.component_type)
        return base_confidence * agnostic_ratio * 0.9

Framework Migration Inheritance

def migrate_inheritance(component, old_framework, new_framework):
    """Handle inheritance during framework migration"""
    migration_results = {}

    # Get existing results from old framework
    old_results = get_cached_results(component, old_framework)

    for test_name, result in old_results.items():
        if is_agnostic_test(test_name, component.type):
            # Agnostic tests transfer directly
            migration_results[test_name] = result
            migration_results[test_name].framework = new_framework
        else:
            # Framework-specific tests need re-execution
            migration_results[test_name] = {
                "status": "pending_retest",
                "reason": "framework_migration",
                "old_result": result
            }

    return migration_results

Best Practices

1. Clear Inheritance Boundaries

  • Document what each component inherits
  • Specify which tests are inheritable
  • Define inheritance weights explicitly
  • Distinguish framework-agnostic from framework-specific tests

2. Version Management

  • Track component versions in test results
  • Invalidate inheritance on version changes
  • Maintain version compatibility matrix
  • Track framework versions for cross-framework compatibility

3. Time-Based Validity

  • Set appropriate TTL for inherited results
  • Refresh inheritance periodically
  • Alert on stale inheritance
  • Use longer TTLs for framework-agnostic results

4. Audit Trail

  • Log all inheritance decisions
  • Track inheritance chain
  • Enable inheritance debugging
  • Record cross-framework inheritance paths

5. Cross-Framework Validation

  • Validate inherited results when crossing framework boundaries
  • Maintain confidence scores for cross-framework inheritance
  • Document framework-specific adaptations
  • Test inheritance integrity across frameworks

6. Universal Cache Management

  • Prioritize universal cache for agnostic components
  • Implement cache warming for frequently used components
  • Monitor cache hit rates across frameworks
  • Optimize TTLs based on component stability

Example: Complete Inheritance Flow

# 1. LLM Testing (Foundation - 100% Agnostic)
llm_result = {
    "component_id": "gpt-4",
    "framework": "aurite",  # Tested via Aurite
    "is_agnostic": True,
    "cross_framework_validity": True,
    "direct_tests": {
        "prompt_injection": 0.95,
        "content_safety": 0.98
    }
}

# 2. MCP Testing (Foundation - 100% Agnostic)
mcp_result = {
    "component_id": "crm_api",
    "framework": "langchain",  # Tested via LangChain
    "is_agnostic": True,
    "cross_framework_validity": True,
    "direct_tests": {
        "availability": 0.99,
        "performance": 0.94
    }
}

# 3. Agent Testing (Inherits cross-framework - 60% Agnostic)
agent_result = {
    "component_id": "support_agent",
    "framework": "autogen",  # Running in AutoGen
    "is_agnostic": False,  # Hybrid component
    "cross_framework_validity": 0.6,  # 60% shareable
    "inherited_results": {
        # Universal inheritance from different frameworks
        "gpt-4.prompt_injection": {
            "score": 0.95,
            "source_framework": "aurite",
            "is_universal": True
        },
        "gpt-4.content_safety": {
            "score": 0.98,
            "source_framework": "aurite",
            "is_universal": True
        },
        "crm_api.availability": {
            "score": 0.99,
            "source_framework": "langchain",
            "is_universal": True
        },
        "crm_api.performance": {
            "score": 0.94,
            "source_framework": "langchain",
            "is_universal": True
        }
    },
    "direct_tests": {
        "tool_selection": 0.92,  # Agnostic test
        "goal_achievement": 0.89,  # Agnostic test
        "memory_management": 0.87  # Framework-specific
    },
    "composite_scores": {
        "quality": 0.91,
        "security": 0.95,
        "framework_confidence": {
            "aurite": 0.95,
            "langchain": 0.93,
            "autogen": 1.0
        }
    }
}

# 4. Workflow Testing (Mixed framework - 20% Agnostic)
workflow_result = {
    "component_id": "support_workflow",
    "framework": "aurite",  # Workflow in Aurite
    "is_agnostic": False,
    "cross_framework_validity": 0.2,  # 20% shareable
    "inherited_results": {
        # Inheriting from AutoGen agent
        "support_agent.quality": {
            "score": 0.91,
            "source_framework": "autogen",
            "is_universal": False,
            "confidence": 0.85  # Reduced confidence across frameworks
        },
        "support_agent.security": {
            "score": 0.95,
            "source_framework": "autogen",
            "is_universal": False,
            "confidence": 0.90
        }
    },
    "direct_tests": {
        "business_logic": 0.96,  # Agnostic
        "end_to_end": 0.93,  # Agnostic
        "orchestration": 0.91  # Framework-specific
    },
    "composite_scores": {
        "quality": 0.92,
        "security": 0.95,
        "business_compliance": 0.94,
        "cross_framework_confidence": 0.88
    }
}