# Migration Guide: v1 to v2 (Thin Middleware)

This guide covers migrating from LockStock Integrations v1.x (Guard daemon + local crypto) to v2.x (thin SaaS middleware).

## Overview

| Feature | v1.x (LockStockMiddleware) | v2.x (LockStockThinMiddleware) |
|---------|---------------------------|-------------------------------|
| Daemon required | Yes (Guard daemon) | No |
| Local crypto | Yes (HMAC signing) | No (server handles all) |
| SSE streaming | Limited (response buffering) | Full support (pure ASGI) |
| Authentication | Unix socket + chain sync | API key (Bearer token) |
| Complexity | High (daemon lifecycle) | Low (just HTTP calls) |

## When to Migrate

**Migrate to v2 if:**
- You're deploying to serverless/container environments
- You need reliable SSE streaming for LLM responses
- You want simpler deployment (no daemon to manage)
- You're okay with API key authentication

**Stay on v1 if:**
- You need hardware-bound security (TPM/HSM)
- You're running air-gapped/offline
- You need the two-party verification protocol

## Migration Steps

### 1. Update Dependencies

```bash
# Old
pip install lockstock-integrations[guard,fastapi]

# New
pip install lockstock-integrations[fastapi]
```

### 2. Get API Key

Log into the LockStock dashboard and create an API key for your agent:

1. Go to **Settings > API Keys**
2. Click **Create Key**
3. Select scope: `stamp:write`
4. Copy the key (starts with `lsk_admin_`)

### 3. Update Middleware Configuration

**Before (v1):**
```python
from fastapi import FastAPI
from lockstock_fastapi import LockStockMiddleware

app = FastAPI()

app.add_middleware(
    LockStockMiddleware,
    agent_id="agent_abc123",
    guard_socket="/var/run/lockstock-guard/guard.sock",
    server_endpoint="https://lockstock-api-i9kp.onrender.com",
)
```

**After (v2):**
```python
from fastapi import FastAPI
from lockstock_fastapi import LockStockThinMiddleware

app = FastAPI()

app.add_middleware(
    LockStockThinMiddleware,
    agent_id="agent_abc123",
    api_key="lsk_admin_...",  # From dashboard
    server_url="https://lockstock-api-i9kp.onrender.com",
    path_tasks={
        "/v1/chat/completions": "chatcompletion",
        "/v1/models": "network",
        "/health": None,  # Excluded from stamping
    },
)
```

### 4. Remove Guard Daemon

If you were running the Guard daemon, you can now remove it:

```bash
# Stop the daemon
lockstock-guard stop

# Optional: Remove daemon package
pip uninstall lockstock-guard
```

### 5. Update Environment Variables

**Before:**
```bash
LOCKSTOCK_SOCKET=/var/run/lockstock-guard/guard.sock
LOCKSTOCK_SERVER_URL=https://lockstock-api-i9kp.onrender.com
LOCKSTOCK_AGENT_ID=agent_abc123
```

**After:**
```bash
LOCKSTOCK_SERVER_URL=https://lockstock-api-i9kp.onrender.com
LOCKSTOCK_AGENT_ID=agent_abc123
LOCKSTOCK_API_KEY=lsk_admin_...
```

### 6. Configure Path Tasks

The thin middleware requires explicit path-to-task mapping:

```python
path_tasks = {
    # Stamp these endpoints with their task types
    "/v1/chat/completions": "chatcompletion",
    "/v1/embeddings": "embedding",
    "/v1/models": "network",

    # Exclude these from stamping (use None)
    "/health": None,
    "/metrics": None,
    "/readiness": None,
}
```

### 7. Response Stamping (Auto-Inferred)

The v1 daemon stamped responses automatically. The thin client now does the same
by default — `response_tasks` is auto-inferred from `path_tasks` using the
`TASK + "RESPONSE"` convention enforced by the server's agent registry.

**You do not need to configure response_tasks.** If you omit it (or pass `None`),
the middleware infers it:

```python
# This is all you need — response_tasks auto-inferred as:
# {"CHATCOMPLETION": "CHATCOMPLETIONRESPONSE", "NETWORK": "NETWORKRESPONSE"}
app.add_middleware(
    LockStockThinMiddleware,
    agent_id="agent_abc123",
    api_key="lsk_admin_...",
    path_tasks={
        "/v1/chat/completions": "CHATCOMPLETION",
        "/v1/models": "NETWORK",
    },
)
```

The three-way semantics for `response_tasks`:

| Value | Behavior |
|-------|----------|
| `None` (default) | Auto-infer from `path_tasks`. Each task `X` gets response task `XRESPONSE`. Matches daemon behavior. |
| Explicit dict | Use as-is. For custom response task names that don't follow the convention. |
| `{}` (empty dict) | Conscious opt-out. Disables response stamping. Logs a warning at startup. |

If you need to disable response stamping (rare — think carefully before doing this),
pass an explicit empty dict:

```python
    response_tasks={},  # I understand responses will not be audited
```

The middleware will log a warning:
```
WARNING - response_tasks is explicitly empty — outbound responses will NOT be stamped on chain.
```

Response stamps are fire-and-forget (non-blocking) and don't affect response latency.

### 8. Blocking Mode (Fail-Closed by Default)

The thin middleware defaults to `block_on_rejection=True` — if a stamp is rejected
or the server is unreachable, the request is blocked with HTTP 503. This matches
the daemon's security posture: **no stamp = no action.**

This is the correct default for compliance-critical deployments. The daemon enforced
this architecturally (it was the network path — if it couldn't stamp, traffic
couldn't flow). The thin client enforces it via configuration.

To disable blocking (proceed unstamped on failure — use only for development/testing):

```python
app.add_middleware(
    LockStockThinMiddleware,
    agent_id="agent_abc123",
    api_key="lsk_admin_...",
    path_tasks={"/v1/chat/completions": "chatcompletion"},
    block_on_rejection=False,  # WARNING: fail-open, no accountability on server outage
)
```

## Response Headers

Both v1 and v2 inject `X-LockStock-*` headers into responses:

| Header | Description |
|--------|-------------|
| `X-LockStock-Status` | `accepted`, `skipped`, or `rejected` |
| `X-LockStock-Seq` | Sequence number (if accepted) |
| `X-LockStock-Hash` | State hash (if accepted) |
| `X-LockStock-Trace` | Trace ID for debugging |
| `X-LockStock-Reason` | Reason (if skipped/rejected) |

## Troubleshooting

### "Connection error" in logs

Check that `server_url` is reachable:

```bash
curl -I https://lockstock-api-i9kp.onrender.com/health
```

### "401 Unauthorized" from /v1/stamp

Your API key is invalid or expired. Generate a new one from the dashboard.

### "403 Task not allowed"

The task type isn't in your agent's `allowed_tasks`. Update the agent in the dashboard.

### "409 Conflict" retries exhausted

High concurrency is causing chain conflicts. The middleware retries 3 times with backoff, but if you're seeing this repeatedly, consider:
- Reducing concurrent requests
- Batching requests
- Contacting support for rate limit increase

## API Changes

### Removed in v2

- `guard_socket` parameter (no daemon)
- `LockStockMiddleware.sync_chain()` (server is authoritative)
- Local chain state tracking (server handles this)

### Added in v2

- `api_key` parameter (required)
- `path_tasks` parameter (explicit task mapping)
- `response_tasks` parameter (auto-inferred from `path_tasks` by default — override only if needed)
- `block_on_rejection` parameter (default: `True` — fail-closed, matching daemon behavior)
- `timeout` parameter (HTTP timeout)
- `max_retries` parameter (409 retry count)

## Questions?

- Documentation: https://d3cipher.ai/docs
- Support: support@d3cipher.ai
- Dashboard: https://lockstock-api-i9kp.onrender.com/dashboard
