# Constraint Checking System

This module provides an inheritance-based constraint checking system for validating candidates against constraints in the Local Deep Research framework.

## Architecture

The system is built around inheritance and provides multiple implementations:

### Base Class
- **`BaseConstraintChecker`**: Abstract base class defining the interface

### Concrete Implementations
- **`DualConfidenceChecker`**: Uses positive/negative/uncertainty confidence scoring
- **`ThresholdChecker`**: Simple threshold-based checking
- **`StrictChecker`**: Example of very strict constraint validation

### Supporting Components
- **`EvidenceAnalyzer`**: Analyzes evidence using dual confidence scoring
- **`RejectionEngine`**: Makes rejection decisions based on evidence
- **`ConstraintCheckResult`**: Data class containing evaluation results

## Usage Examples

### Using DualConfidenceChecker
```python
from constraint_checking import DualConfidenceChecker

checker = DualConfidenceChecker(
    model=llm,
    evidence_gatherer=evidence_function,
    negative_threshold=0.25,  # Reject if negative evidence > 25%
    positive_threshold=0.4,   # Reject if positive evidence < 40%
)

result = checker.check_candidate(candidate, constraints)
```

### Using ThresholdChecker
```python
from constraint_checking import ThresholdChecker

checker = ThresholdChecker(
    model=llm,
    evidence_gatherer=evidence_function,
    satisfaction_threshold=0.7,     # Individual constraint threshold
    required_satisfaction_rate=0.8  # Overall satisfaction rate needed
)

result = checker.check_candidate(candidate, constraints)
```

### Using StrictChecker
```python
from constraint_checking import StrictChecker

checker = StrictChecker(
    model=llm,
    evidence_gatherer=evidence_function,
    strict_threshold=0.9,        # Very high threshold
    name_pattern_required=True   # NAME_PATTERN constraints are mandatory
)

result = checker.check_candidate(candidate, constraints)
```

## Creating Custom Variants

To create your own constraint checker variant:

1. **Inherit from BaseConstraintChecker**:
```python
from .base_constraint_checker import BaseConstraintChecker, ConstraintCheckResult

class MyCustomChecker(BaseConstraintChecker):
    def __init__(self, *args, my_param=0.5, **kwargs):
        super().__init__(*args, **kwargs)
        self.my_param = my_param
```

2. **Implement required methods**:
```python
    def check_candidate(self, candidate, constraints):
        # Your implementation here
        return ConstraintCheckResult(...)

    def should_reject_candidate(self, candidate, constraint, evidence_data):
        # Your rejection logic here
        return should_reject, reason
```

3. **Add custom logic**:
```python
    def _my_custom_evaluation(self, candidate, constraint):
        # Your custom evaluation logic
        pass
```

## Integration with Strategies

Use in your strategy by initializing the checker:

```python
class MyStrategy(BaseStrategy):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Choose your constraint checker
        self.constraint_checker = DualConfidenceChecker(
            model=self.model,
            evidence_gatherer=self._gather_evidence_for_constraint,
            # ... other parameters
        )

    def _evaluate_candidate(self, candidate):
        result = self.constraint_checker.check_candidate(candidate, self.constraints)

        # Process result
        candidate.evaluation_results = result.detailed_results
        candidate.score = result.total_score

        return result.total_score
```

## Available Checkers

### DualConfidenceChecker
- **Best for**: Nuanced evaluation with detailed confidence scoring
- **Parameters**: `negative_threshold`, `positive_threshold`, `uncertainty_penalty`, `negative_weight`
- **Output**: Detailed positive/negative/uncertainty scores per constraint

### ThresholdChecker
- **Best for**: Fast, simple constraint checking
- **Parameters**: `satisfaction_threshold`, `required_satisfaction_rate`
- **Output**: Simple satisfied/not satisfied per constraint

### StrictChecker
- **Best for**: Cases requiring very high confidence
- **Parameters**: `strict_threshold`, `name_pattern_required`
- **Output**: Binary pass/fail with strict requirements

## Extending the System

The inheritance-based design makes it easy to:

1. **Create specialized checkers** for specific domains
2. **Mix and match components** (e.g., use DualConfidence evidence analysis with custom rejection logic)
3. **Add new constraint types** with custom handling
4. **Implement domain-specific optimizations**

See `strict_checker.py` for an example of creating a custom variant.
