# Migration Guide: 0.1.0 → 1.0.0

This guide covers all changes from pymfp 0.1.0 (Alpha) to 1.0.0 (Stable).

## Breaking Changes

### RuntimeConfig

New fields added (all have defaults, so existing code continues to work):

| Field | Type | Default | Phase |
|-------|------|---------|-------|
| `storage` | `StorageConfig \| None` | `None` | Phase 2 |
| `supported_algorithms` | `tuple[bytes, ...]` | `(b"aes-256-gcm",)` | Phase 5 |

### DeliveredMessage

The duplicate `message_id` field was removed in Phase 1. If you were accessing `message_id` as a positional field, update to use the keyword or single field.

### AgentCallable / AsyncAgentCallable

Both are now exported in `__all__`. `AsyncAgentCallable` is the type for async agent handlers:
```python
AsyncAgentCallable = Callable[[DeliveredMessage], Awaitable[None]]
```

`bind_agent()` auto-detects async callables via `inspect.iscoroutinefunction()`.

### Rate Limiting

The cumulative message counter has been replaced with a 1-second sliding window rate limiter. Agents are no longer permanently quarantined after hitting the rate limit — they can send again after the window passes.

### Storage Encryption

Storage at-rest encryption now uses random nonces (previously deterministic). Databases created with 0.1.0 encryption are **not** compatible with 1.0.0 decryption. To migrate encrypted databases:
1. Export data using 0.1.0
2. Import using 1.0.0

Unencrypted databases (the default) are fully compatible.

## New Features

### Persistence (Phase 2)
```python
from mfp import Runtime, RuntimeConfig
from mfp.storage.engine import StorageConfig

rt = Runtime(RuntimeConfig(storage=StorageConfig(path="state.db")))
# All state automatically persisted to SQLite
```

### Federation (Phase 3)
```python
# Bootstrap bilateral channel
bc = rt.bootstrap_bilateral_deterministic(peer_runtime_id)
# Establish cross-runtime channel
crc = rt.establish_cross_runtime_channel(local_agent, remote_id, bc.bilateral_id)
```

### Async Support (Phase 4)
```python
async def my_agent(msg: DeliveredMessage) -> None:
    await process(msg.payload)

agent_id = rt.bind_agent(my_agent)  # Auto-detected as async
receipt = await rt.send_async(agent_id, channel_id, b"payload")
```

### Algorithm Negotiation (Phase 5)
```python
from mfp.federation.bilateral import negotiate_algorithm

alg = negotiate_algorithm(
    local_supported=(b"aes-256-gcm",),
    peer_supported=(b"aes-256-gcm", b"chacha20-poly1305"),
)
```

### Audit Events (Phase 5-6)
```python
from mfp.observability.logging import AuditEventType, log_audit_event
# All state-changing operations now emit structured audit events
# with automatic redaction of sensitive fields
```

## New Error Codes

| Code | Description | Phase |
|------|-------------|-------|
| `TIMEOUT` | Agent callable exceeded timeout | Phase 1 |
| `DUPLICATE_MESSAGE` | Message ID already processed | Phase 1 |

## Spec Compliance

All 4 open questions from the MFP specification are resolved:
- OQ1: Isolation tiers (Level 1 MUST, Level 2 SHOULD, Level 3 MAY)
- OQ2: Encoding algorithm registry (AES-256-GCM required)
- OQ3: Entropy floor (256-bit CSPRNG minimum)
- OQ4: Recovery convergence (bounded iterations + escalation)

RFC 2119 conformance language added to all 6 specification documents.
