# Phase 7: Mission Generation Pipeline — UAT Testing

## Summary

Built the mission generation pipeline with:
- Per-category LLM mission generation (7 categories in defined order)
- Validation and auto-fix for LLM hallucinations (file paths, line ranges, prerequisite cycles)
- LangGraph pipeline with SQLite checkpointing for fault-tolerant, resumable execution
- Public API exports via `unfamiliar.llm` package

## New Files

- `src/unfamiliar/llm/missions/schemas.py` — Pydantic models for LLM structured output
- `src/unfamiliar/llm/missions/prompts.py` — Mission generation prompt template
- `src/unfamiliar/llm/missions/context.py` — Category-specific context builder
- `src/unfamiliar/llm/missions/generator.py` — Per-category mission generator
- `src/unfamiliar/llm/missions/validation.py` — Validation and auto-fix utilities
- `src/unfamiliar/llm/missions/pipeline.py` — LangGraph pipeline with checkpointing
- `src/unfamiliar/llm/missions/__init__.py` — Package exports

## Modified Files

- `src/unfamiliar/llm/exceptions.py` — Added `MissionGenerationError`
- `src/unfamiliar/llm/__init__.py` — Added mission pipeline exports

## Automated Testing

Run linting to verify all code quality checks:

```bash
# Ruff linting
ruff check src/unfamiliar/llm/

# Python syntax validation
python3 -m py_compile src/unfamiliar/llm/missions/*.py
python3 -m py_compile src/unfamiliar/llm/exceptions.py
python3 -m py_compile src/unfamiliar/llm/__init__.py
```

Expected: All checks pass with no errors.

## Manual Testing Steps

### 1. Verify Imports

```python
# In a Python REPL with the project installed or PYTHONPATH set
from unfamiliar.llm import (
    run_mission_pipeline,
    PipelineResult,
    CATEGORY_ORDER,
    MissionGenerationError,
)
from unfamiliar.llm.missions import (
    generate_category_missions,
    CategoryMissionsResponse,
    ValidationResult,
)

print("All imports successful")
print("Category order:", [c.value for c in CATEGORY_ORDER])
```

Expected: No import errors. Category order should be:
1. architecture
2. data_flow
3. domain_business_logic
4. dependencies
5. conventions
6. testing
7. technical_debt

### 2. Verify Exception Hierarchy

```python
from unfamiliar.llm import MissionGenerationError, LLMError, BriefingGenerationError

# MissionGenerationError should inherit from LLMError
assert issubclass(MissionGenerationError, LLMError)

# Should store category and attempts
exc = MissionGenerationError("Test error", category="testing", attempts=3)
assert exc.category == "testing"
assert exc.attempts == 3
print("Exception hierarchy verified")
```

### 3. Verify Schema Models

```python
from unfamiliar.llm.missions.schemas import (
    MissionFileRefResponse,
    MissionItemResponse,
    ChainResponse,
    CategoryMissionsResponse,
)

# Create a sample file ref
file_ref = MissionFileRefResponse(
    file_path="src/main.py",
    line_start=10,
    line_end=20,
    description="Entry point to the application"
)
print("File ref:", file_ref.model_dump())

# Create a sample mission
mission = MissionItemResponse(
    title="The Entry Point",
    title_plain="Understand the Entry Point",
    description="Investigate the main entry point of the application",
    difficulty="quick",
    completion_condition="You can explain what happens when the app starts",
    security_tag=False,
    standard_tag=None,
    narrative_intro="The door stood ajar...",
    narrative_outro="Another mystery solved.",
    file_refs=[file_ref],
    module_index=0,
    prerequisite_titles=[],
)
print("Mission:", mission.title_plain)

# Create a sample response
response = CategoryMissionsResponse(
    missions=[mission],
    chains=[],
)
print("Response has", len(response.missions), "missions")
```

### 4. Verify Validation Functions

```python
from pathlib import Path
from unfamiliar.llm.missions.validation import (
    validate_file_refs,
    validate_prerequisites,
    ValidationResult,
)
from unfamiliar.llm.missions.schemas import MissionFileRefResponse, MissionItemResponse
from unfamiliar.constants import InvestigationCategory

# Test file ref validation
repo_path = Path("/project")  # This repository

# Valid file ref
valid_ref = MissionFileRefResponse(
    file_path="src/unfamiliar/llm/__init__.py",
    line_start=1,
    line_end=10,
    description="LLM module exports"
)
validated, warnings = validate_file_refs([valid_ref], repo_path)
print("Valid refs:", len(validated), "Warnings:", warnings)

# Invalid file ref (non-existent file)
invalid_ref = MissionFileRefResponse(
    file_path="nonexistent/file.py",
    line_start=1,
    line_end=10,
    description="Should be removed"
)
validated, warnings = validate_file_refs([invalid_ref], repo_path)
print("Invalid refs removed:", len(validated) == 0)
print("Warnings:", warnings)
```

### 5. Verify Prerequisite Validation

```python
from unfamiliar.llm.missions.schemas import MissionItemResponse
from unfamiliar.llm.missions.validation import validate_prerequisites
from unfamiliar.constants import InvestigationCategory

# Create missions with circular prerequisites
mission_a = MissionItemResponse(
    title="Mission A",
    title_plain="Mission A",
    description="Test",
    difficulty="quick",
    completion_condition="Done",
    security_tag=False,
    standard_tag=None,
    narrative_intro="",
    narrative_outro="",
    file_refs=[],
    module_index=0,
    prerequisite_titles=["Mission B"],  # Creates cycle
)

mission_b = MissionItemResponse(
    title="Mission B",
    title_plain="Mission B",
    description="Test",
    difficulty="quick",
    completion_condition="Done",
    security_tag=False,
    standard_tag=None,
    narrative_intro="",
    narrative_outro="",
    file_refs=[],
    module_index=0,
    prerequisite_titles=["Mission A"],  # Creates cycle
)

validated, warnings, fixes = validate_prerequisites(
    [mission_a, mission_b], InvestigationCategory.ARCHITECTURE
)
print("Cycle broken:", "Broke cycle" in " ".join(fixes))
print("Warnings:", warnings)
```

### 6. Verify Category Order

```python
from unfamiliar.llm.missions import CATEGORY_ORDER
from unfamiliar.constants import InvestigationCategory

expected_order = [
    InvestigationCategory.ARCHITECTURE,
    InvestigationCategory.DATA_FLOW,
    InvestigationCategory.DOMAIN_BUSINESS_LOGIC,
    InvestigationCategory.DEPENDENCIES,
    InvestigationCategory.CONVENTIONS,
    InvestigationCategory.TESTING,
    InvestigationCategory.TECHNICAL_DEBT,
]

assert CATEGORY_ORDER == expected_order, "Category order mismatch"
print("Category order verified:", [c.value for c in CATEGORY_ORDER])
```

## Edge Cases to Check

1. **Empty file refs list**: Should return empty list with no warnings
2. **All file paths invalid**: Should return empty list with warnings for each
3. **Line numbers out of range**: Should be clamped to file bounds
4. **Circular prerequisites**: Should be detected and broken
5. **All missions have prerequisites (no roots)**: Should create a root by removing prereqs
6. **Unreachable missions**: Should be made into roots
7. **Depth > MAX_PREREQUISITE_DEPTH (3)**: Should trim deepest edges

## Phase Completion Checklist

- [x] All imports work without errors
- [x] Exception hierarchy is correct
- [x] Schema models instantiate correctly
- [x] Validation removes invalid file paths
- [x] Validation clamps line numbers to bounds
- [x] Prerequisite cycle detection works
- [x] Root mission creation works
- [x] CATEGORY_ORDER matches requirements
- [x] `ruff check src/unfamiliar/llm/` passes with zero errors
- [x] All Python files compile successfully

## Known Limitations

- Full pipeline testing requires an LLM provider (API key needed)
- SQLite checkpointing requires `langgraph-checkpoint-sqlite` package (falls back to in-memory if unavailable)
- Mission generation quality depends on the LLM model used

## Next Steps

After approval, proceed to Phase 8 (Testing Phase) to write:
- Unit tests for validation functions
- Property-based tests for cycle detection, depth enforcement, root guarantee
- Integration tests for the full pipeline (mocked LLM)
