---
phase: 03-registry-compatibility
plan: 03
type: execute
wave: 2
depends_on: [03-01, 03-02]
files_modified:
  - src/clawrium/core/registry.py
  - tests/test_registry.py
autonomous: true
requirements: [REG-03]

must_haves:
  truths:
    - "System validates host capabilities against claw requirements"
    - "Compatibility check returns pass/fail with specific reasons"
    - "All requirement types are checked: OS, arch, memory, GPU, dependencies"
  artifacts:
    - path: "src/clawrium/core/registry.py"
      provides: "Compatibility checking function"
      exports: ["check_compatibility", "CompatibilityResult"]
    - path: "tests/test_registry.py"
      provides: "Compatibility checking tests"
      min_tests: 8
  key_links:
    - from: "src/clawrium/core/registry.py"
      to: "src/clawrium/core/hardware.py"
      via: "HardwareInfo type"
      pattern: "HardwareInfo"
    - from: "check_compatibility"
      to: "ManifestEntry"
      via: "sparse matrix matching"
      pattern: "for entry in manifest"
---

<objective>
Implement compatibility checking between host hardware and claw requirements.

Purpose: Before installing a claw, the system must validate that the host meets all requirements. This is a sparse matrix match - only explicitly supported combinations are valid. The function provides specific failure reasons for unsupported hosts.

Output: check_compatibility() function that validates hosts against claw manifests with detailed pass/fail results.
</objective>

<execution_context>
@/home/devashish/workspace/ric03uec/clawrium/.claude/get-shit-done/workflows/execute-plan.md
@/home/devashish/workspace/ric03uec/clawrium/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-registry-compatibility/03-CONTEXT.md

<interfaces>
<!-- From 03-01: Registry types -->

```python
class Requirements(TypedDict):
    min_memory_mb: int
    gpu_required: bool
    dependencies: dict[str, str]

class ManifestEntry(TypedDict):
    version: str
    os: str
    os_version: str
    arch: str
    requirements: Requirements

class ClawManifest(TypedDict):
    name: str
    description: str
    entries: list[ManifestEntry]
```

<!-- From 03-02: Extended HardwareInfo -->

```python
class HardwareInfo(TypedDict):
    architecture: str
    processor_cores: int
    processor_count: int
    memtotal_mb: int
    mounts: list[dict]
    gpu: GpuInfo
    os: str           # e.g., "ubuntu"
    os_version: str   # e.g., "24.04"
```

<!-- Target CompatibilityResult type -->

```python
class CompatibilityResult(TypedDict):
    compatible: bool
    matched_entry: ManifestEntry | None  # The entry that matched, if any
    reasons: list[str]  # Empty if compatible, failure reasons if not
```
</interfaces>
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Task 1: Implement compatibility checking</name>
  <files>
    src/clawrium/core/registry.py
    tests/test_registry.py
  </files>
  <read_first>
    - /home/devashish/workspace/ric03uec/clawrium/src/clawrium/core/registry.py (existing registry module from 03-01)
    - /home/devashish/workspace/ric03uec/clawrium/src/clawrium/core/hardware.py (HardwareInfo TypedDict)
    - /home/devashish/workspace/ric03uec/clawrium/.planning/phases/03-registry-compatibility/03-CONTEXT.md (D-10 through D-13 compatibility rules)
  </read_first>
  <behavior>
    - Test: check_compatibility with matching os/arch/version returns compatible=True, matched_entry set
    - Test: check_compatibility with wrong OS returns compatible=False, reason="Requires ubuntu 24.04, host has debian 12"
    - Test: check_compatibility with wrong arch returns compatible=False, reason="Requires x86_64, host has aarch64"
    - Test: check_compatibility with insufficient memory returns compatible=False, reason="Requires 2048MB RAM, host has 1024MB"
    - Test: check_compatibility with GPU required but not present returns compatible=False, reason="Requires GPU, host has none"
    - Test: check_compatibility with dependency version mismatch returns compatible=False, reason="Requires nodejs >=20.0.0"
    - Test: check_compatibility with all requirements met returns compatible=True, reasons=[]
    - Test: check_compatibility with nonexistent claw raises ManifestNotFoundError
  </behavior>
  <action>
    1. Add CompatibilityResult TypedDict to registry.py:
       ```python
       class CompatibilityResult(TypedDict):
           compatible: bool
           matched_entry: ManifestEntry | None
           reasons: list[str]
       ```

    2. Implement check_compatibility function in registry.py:
       ```python
       def check_compatibility(
           claw_name: str,
           hardware: HardwareInfo,
           version: str | None = None
       ) -> CompatibilityResult:
           """Check if host hardware is compatible with a claw.

           Args:
               claw_name: Name of the claw (e.g., "openclaw")
               hardware: HardwareInfo dict from host
               version: Optional specific version to check (default: any version)

           Returns:
               CompatibilityResult with compatible bool, matched_entry, and reasons list

           Raises:
               ManifestNotFoundError: If claw manifest doesn't exist
           """
       ```

       Implementation logic (per D-10 through D-13):
       a. Load manifest via load_manifest(claw_name)
       b. Filter entries by version if specified
       c. For each entry, check in order:
          - OS match: entry.os == hardware["os"]
          - OS version match: entry.os_version == hardware["os_version"]
          - Architecture match: entry.arch == hardware["architecture"]
          - Memory: hardware["memtotal_mb"] >= entry.requirements["min_memory_mb"]
          - GPU: if entry.requirements["gpu_required"], hardware["gpu"]["present"] must be True
          - Dependencies: for each dep, version must satisfy requirement (use packaging.version)
       d. If all checks pass for any entry, return compatible=True with that entry
       e. If no entry matches, collect all failure reasons and return compatible=False

    3. For dependency version checking, use packaging library:
       ```python
       from packaging.version import Version
       from packaging.specifiers import SpecifierSet

       def _check_dependency_version(required: str, installed: str | None) -> bool:
           """Check if installed version satisfies requirement."""
           if installed is None:
               return False
           try:
               spec = SpecifierSet(required)
               return Version(installed) in spec
           except Exception:
               return False
       ```

    4. Add tests to test_registry.py covering all <behavior> cases.
       Create mock hardware dicts for each scenario.

    5. Export CompatibilityResult and check_compatibility in module __all__.
  </action>
  <verify>
    <automated>uv run pytest tests/test_registry.py -v -k compatibility</automated>
  </verify>
  <acceptance_criteria>
    - src/clawrium/core/registry.py contains "class CompatibilityResult"
    - src/clawrium/core/registry.py contains "def check_compatibility("
    - src/clawrium/core/registry.py contains "from packaging" (version checking)
    - tests/test_registry.py contains "test_check_compatibility_matching"
    - tests/test_registry.py contains "test_check_compatibility_wrong_os"
    - tests/test_registry.py contains "test_check_compatibility_insufficient_memory"
    - tests/test_registry.py contains "test_check_compatibility_gpu_required"
    - uv run pytest tests/test_registry.py -v -k compatibility exits 0
    - uv run pytest tests/test_registry.py -v exits 0 (all tests)
  </acceptance_criteria>
  <done>
    - CompatibilityResult TypedDict defined with compatible, matched_entry, reasons fields
    - check_compatibility() validates all requirement types
    - Sparse matrix matching: only explicit entries are supported
    - Specific failure reasons provided for each failed check
    - Version requirements use packaging.specifiers for semver comparison
    - All compatibility tests pass
  </done>
</task>

</tasks>

<verification>
```bash
# Verify compatibility function exists
grep -n "def check_compatibility" src/clawrium/core/registry.py

# Verify CompatibilityResult type
grep -n "class CompatibilityResult" src/clawrium/core/registry.py

# Verify packaging import
grep -n "from packaging" src/clawrium/core/registry.py

# Run compatibility tests
uv run pytest tests/test_registry.py -v -k compatibility

# Run all registry tests
uv run pytest tests/test_registry.py -v

# Test compatibility in Python
uv run python -c "
from clawrium.core.registry import check_compatibility

# Create matching hardware
hardware = {
    'os': 'ubuntu',
    'os_version': '24.04',
    'architecture': 'x86_64',
    'memtotal_mb': 4096,
    'gpu': {'present': False, 'vendor': None, 'error': None},
    'processor_cores': 4,
    'processor_count': 1,
    'mounts': []
}

result = check_compatibility('openclaw', hardware)
print(f'Compatible: {result[\"compatible\"]}')
print(f'Matched entry: {result[\"matched_entry\"][\"version\"] if result[\"matched_entry\"] else None}')
print(f'Reasons: {result[\"reasons\"]}')
"
```
</verification>

<success_criteria>
- check_compatibility() returns CompatibilityResult with compatible bool
- OS, arch, memory, GPU, dependencies all checked
- Sparse matrix: only explicit manifest entries match
- Failure reasons are specific: "Requires X, host has Y"
- Version requirements validated with packaging.specifiers
- All tests pass including new compatibility tests
</success_criteria>

<output>
After completion, create `.planning/phases/03-registry-compatibility/03-03-SUMMARY.md`
</output>
