# v0.7.0 Rust-first Migration Plan

| Field | Value |
|------|-----|
| Version | 0.7.0 |
| Status | FINAL |
| Created | 2026-05-17 |

## 1. Boundary Principles

### C-Side Retained

The C side continues to own the following responsibilities, which are tightly bound to the NGINX runtime and lifecycle:

| Responsibility | Reason | Migration Status |
|------|------|---------|
| Module registration (ngx_module_t) | NGINX API | Never migrate |
| Directive entries (ngx_command_t) | NGINX API | Never migrate |
| Filter hooks | NGINX API | Never migrate |
| Pool allocation | NGINX memory model | Never migrate |
| Chain forwarding | NGINX output model | Never migrate |
| Header list modification | NGINX data structures | Never migrate |
| SHM/slab/rbtree operations | NGINX shared memory | Never migrate |
| Log adapter | NGINX log API | Never migrate |
| Request finalization | NGINX lifecycle | Never migrate |
| dynconf reload trigger | NGINX signal handling | Never migrate |

### Rust-Side Owned (0.7.0 New/Strengthened)

| Responsibility | Current Status | 0.7.0 Target | Task |
|------|---------|-----------|------|
| Accept negotiation | Partially on C side | Fully migrated to Rust | TASK-A05 |
| Bounded decompression | Rust side (no budget) | Strengthen budget upper bound | TASK-A03 |
| Decompression error categories | Lossy mapping | Complete FFI error codes | TASK-A04 |
| Conditional request/ETag | C side | Migrate to Rust | TASK-B02 |
| URL/Host validation | Partially on C side | Fully migrated to Rust | TASK-B03 |
| Response header plan | C side inline | Rust builds plan + C atomically applies | TASK-B04 |
| Decision engine | Scattered on C side | Rust pure-function decision | TASK-B05 |
| Reason-code single source | C+Rust dual definition | Rust enum single source | TASK-B06 |
| Config validation | Partially on C side | Rust dry-run validation | TASK-E02 |

## 2. Migration Contract

Each FFI function must document:

```text
Function name:       FFI function signature
Ownership side:      C | Rust | Shared
Migration status:    Original | Migrating | Migrated | Never migrate
Compatibility:       ABI stability requirements
Added in version:    0.7.0 | 0.6.x | earlier
```

### 0.7.0 New FFI Functions

| FFI Function | Ownership | Signature Summary | Task |
|----------|------|---------|------|
| `markdown_negotiate_accept` | Rust | `(accept_header, available_variants) → AcceptResult` | TASK-A05 |
| `markdown_decompress_bounded` | Rust | `(input, budget) → DecompResult` | TASK-A03 |
| `markdown_make_decision` | Rust | `(context_snapshot) → DecisionResult` | TASK-B05 |
| `markdown_check_conditional` | Rust | `(if_none_match, if_modified_since, etag, last_modified) → ConditionalResult` | TASK-B02 |
| `markdown_validate_url` | Rust | `(url, forwarded_host, forwarded_proto) → UrlResult` | TASK-B03 |
| `markdown_build_header_plan` | Rust | `(decision) → HeaderPlan` | TASK-B04 |
| `markdown_get_reason_code_string` | Rust | `(code) → *const c_char` | TASK-B06 |
| `markdown_validate_config` | Rust | `(config_bytes) → ValidationResult` | TASK-E02 |

### 0.7.0 New FFI Structs

| Struct | Purpose | repr(C) | Task |
|--------|------|---------|------|
| `FFIAcceptResult` | Accept negotiation result | Yes | TASK-A05 |
| `FFIDecompResult` | Bounded decompression result | Yes | TASK-A03 |
| `FFIDecisionResult` | Decision engine result | Yes | TASK-B05 |
| `FFIConditionalResult` | Conditional request result | Yes | TASK-B02 |
| `FFIHeaderPlan` | Response header plan | Yes | TASK-B04 |
| `FFIUrlResult` | URL validation result | Yes | TASK-B03 |
| `FFIValidationResult` | Config validation result | Yes | TASK-E02 |

## 3. Migration Priority

| Priority | Migration Item | Risk | Complexity | Task |
|--------|--------|------|--------|------|
| P0 | Accept negotiation | High (protocol safety) | Medium | TASK-A05 |
| P0 | Bounded decompression | High (zip bomb) | Medium | TASK-A03 |
| P0 | Decompression error categories | Medium (metrics accuracy) | Low | TASK-A04 |
| P1 | Conditional request/ETag | Medium (cache correctness) | Medium | TASK-B02 |
| P1 | URL/Host validation | Medium (injection defense) | Low | TASK-B03 |
| P1 | Response header plan | Low | Medium | TASK-B04 |
| P1 | Decision engine | Medium (maintainability) | High | TASK-B05 |
| P1 | Reason-code single source | Medium (consistency) | Medium | TASK-B06 |
| P2 | Config validation | Low | Low | TASK-E02 |

## 4. Boundary Rules

1. **Rust receives immutable snapshots**: All inputs are byte slices and normalized config snapshots
2. **Rust returns explicit types**: enum, reason code, plan, owned buffer
3. **C applies plan**: Uses NGINX API to apply atomically
4. **C owns memory**: NGINX pool manages all request-lifetime memory
5. **Rust explicitly frees**: Rust-owned memory has FFI release functions
6. **No text parsing**: C does not parse Rust error text
7. **No blocking**: No hidden blocking operations in worker request path
8. **repr(C) layout**: All cross-boundary structs
9. **Tail-append only**: New fields are only appended to struct tail
10. **Feature-gated no drift**: Feature-gated fields do not change layout

## 5. ADR References

- ADR-0001: Use Rust for Conversion (foundational decision)
- ADR-0010: Rust-first C/Rust Boundary Evolution (0.7.0 new, to be created)

## Document Updates

| Version | Date | Author | Changes |
|------|------|------|------|
| 0.7.0-draft | 2026-05-17 | spec-agent | Initial v0.7.0 Rust-first migration plan |
