# AMI SDK Changelog

All notable changes to the AMI SDK will be documented in this file.

## [0.1.0] - 2025-10-06

### Added

#### Phase 1: Foundation (COMPLETED ✅)

**Phase 1.1: Configuration & Environment**
- **Module**: `ami/config.py`
- **Tests**: 15 passing (`sdk_tests/unit/test_config.py`)
- **Features**:
  - Immutable `AMIConfig` frozen dataclass
  - Static `.create()` factory method with environment loading
  - Precedence: method args > constructor args > env > defaults
  - Support for all tenancy fields (org, team, workspace, project + ID variants)
  - ID fields override slug fields in resolution
  - Context resolution helpers (`resolve_context`, `require_workspace`, `require_project`)
  - Base URL normalization (trailing slash removal)

**Phase 1.2: Error Taxonomy**
- **Module**: `ami/errors.py`
- **Tests**: 25 passing (`sdk_tests/unit/test_errors.py`)
- **Features**:
  - Base `AMIError` exception with message, status_code, and details
  - HTTP 4xx client errors: Unauthorized (401), Forbidden (403), NotFound (404), BadRequest (400), Conflict (409), PreconditionFailed (412), Unprocessable (422), RateLimited (429)
  - HTTP 5xx server errors: ServerError (500-599)
  - Network errors: NetworkError, TimeoutError
  - HTTP response mapping function (`map_http_error`)
  - Rate limit error with retry_after support

**Phase 1.3: HTTP Transport Layer**
- **Module**: `ami/transport.py`
- **Tests**: 24 passing (`sdk_tests/unit/test_transport.py`)
- **Features**:
  - `HTTPTransport` class wrapping httpx.Client
  - Connection pooling with configurable timeout
  - Retry logic with exponential backoff + jitter
  - Retry policies: NEVER, IDEMPOTENT, ALWAYS (enum-based strategy)
  - Rate limit handling (429 + Retry-After header respect)
  - Network/timeout error handling with custom exceptions
  - Context manager protocol (`__enter__`/`__exit__`) for resource cleanup
  - HTTP methods: `get()`, `post()`, `put()`, `patch()`, `delete()`

#### Phase 2.1: Atom Models (COMPLETED ✅)

- **Module**: `ami/atoms.py`
- **Tests**: 28 passing (`sdk_tests/unit/test_atoms.py`)
- **Features**:
  - Factory functions: `state()`, `tag()`, `event()`, `ulid()`
  - `StateAtom` with dotted key validation (2-7 parts, regex pattern)
  - `TagAtom` with kind (≤64) and value (≤128) length validation
  - `EventAtom` with topic validation (3-4 tokens: S.V.O or P.S.V.O)
  - Nested models: `EventAnchor`, `EventCorrelation`, `AnchorRole`
  - Atom serialization to dict for wire format
  - ULID generation and ordering

#### Phase 2.2: Wire Serialization (COMPLETED ✅)

- **Module**: `ami/serializers.py`
- **Tests**: 26 passing (`sdk_tests/unit/test_serializers.py`)
- **Features**:
  - `serialize_atom()` converts atoms to JSON wire format
  - `serialize_atoms()` batch serialization for multiple atoms
  - `parse_event_topic()` splits topics into {subject, verb, object} or {predicate, subject, verb, object}
  - `normalize_topic()` applies NFKC Unicode normalization + case folding
  - `deserialize_invoke_response()` parses API responses with selected EMUs
  - `deserialize_action()` handles all action types (tool_call, decision_prompt, route, context_directive)
  - Support for unknown action types (forward compatibility)
  - Event atom serialization leverages existing `to_dict()` methods

#### Phase 2.3: Action and Request/Response Models (COMPLETED ✅)

- **Module**: `ami/models.py`
- **Tests**: 34 passing (`sdk_tests/unit/test_models.py`)
- **Features**:
  - **Action Types**: `ActionToolCall`, `ActionDecisionPrompt`, `ActionRoute`, `ActionContextDirective`
  - **Action Union**: Type-safe `Action` union for all action variants
  - **Invoke Options**: `InvokeOptions` with dry_run, top_k, store_read_cutoff_ts, version pinning
  - **Trace Options**: `TraceOptions` for enabling detailed trace data
  - **Request Model**: `InvokeRequest` with context_ts, correlation, atoms, options, trace
  - **Response Models**: `InvokeResponse`, `SelectedItem`, `IdempotencyMeta`
  - Auto-initialization of options and trace in `InvokeRequest.__post_init__()`
  - Full support for multi-selection (top_k > 1) with scoring

#### Phase 3.1: AMIClient Core Implementation (PARTIAL ✅)

- **Module**: `ami/client.py`
- **Tests**: 152 unit tests passing (integration tests deferred to Phase 3.2+)
- **Features**:
  - **AMIClient Class**: Main SDK entry point with context manager protocol
  - **invoke() Method**: Full parameter support (workspace, project, atoms, idempotency_key, options, trace, context_ts, correlation_trace_id)
  - **Configuration**: Constructor delegates to `AMIConfig.create()` with all tenancy fields
  - **Context Resolution**: Method-level workspace/project override config defaults
  - **Idempotency**: Key validation (≤256 bytes UTF-8), header injection
  - **Request Building**: Serializes atoms, builds payload with optional fields
  - **Response Deserialization**: Maps API response to `InvokeResponse` model
  - **Error Handling**: Proper exception mapping via transport layer
  - **Resource Cleanup**: Context manager protocol (`with AMIClient(...) as client:`)
- **Limitations (Phase 3.1)**:
  - Action deserialization simplified to raw dicts (API format differs from spec)
  - Integration tests created but not passing (sync/async mismatch)
  - Full typed action parsing deferred to Phase 3.2+
- **Files Created**:
  - `sdk/ami/client.py` - AMIClient implementation
  - `sdk_tests/integration/test_client_invoke.py` - 17 integration test stubs
  - `sdk_tests/conftest.py` - pytest fixture registration
- **Enhanced**:
  - `sdk/ami/serializers.py` - Added `deserialize_selected_item()`, `deserialize_invoke_response()`

#### Infrastructure
- SDK package structure with separate testing directory (`sdk/` and `sdk_tests/`)
- Package configuration (`pyproject.toml`) with httpx, pydantic, python-ulid dependencies
- Test infrastructure with pytest, pytest-mock for HTTP mocking
- Separate test paths completely isolated from API tests (`tests/`)
- Comprehensive test coverage with TDD approach

### Testing Summary
- **Total Unit Tests**: **152 passing** ✅
- **Module Breakdown**:
  - `test_config.py`: 15 tests (configuration, environment, precedence)
  - `test_errors.py`: 25 tests (error hierarchy, HTTP mapping)
  - `test_transport.py`: 24 tests (HTTP client, retries, network errors)
  - `test_atoms.py`: 28 tests (atom factories, validation, serialization)
  - `test_serializers.py`: 26 tests (wire format, topic parsing, deserialization)
  - `test_models.py`: 34 tests (actions, invoke options, request/response)

### Design Patterns Applied
1. **Factory Method**: Config.create(), atom builders (state, tag, event)
2. **Strategy Pattern**: RetryPolicy enum for different retry strategies
3. **Exception Hierarchy**: Complete error taxonomy matching API
4. **Frozen Dataclass**: Immutable configuration with validation
5. **Context Manager**: HTTPTransport resource cleanup

### SOLID Principles Verification
✅ **Single Responsibility**: Each module has one reason to change
✅ **Open/Closed**: Extensible via strategies (retry policies), closed for modification
✅ **Liskov Substitution**: All atoms serialize to dict, all errors inherit from AMIError
✅ **Interface Segregation**: Focused interfaces (config, transport, atoms)
✅ **Dependency Inversion**: Depends on abstractions (Transport, not httpx directly)

### Next Milestones
- [x] **Phase 2.2**: Wire serialization/deserialization (26 tests) ✅
- [x] **Phase 2.3**: Action and request/response models (34 tests) ✅
- [x] **Phase 3.1**: AMIClient invoke method (core impl complete, integration deferred) ✅
- [ ] **Phase 3.2**: Async SDK client + full integration tests (~18 tests)
- [ ] **Phase 3.3**: Event ingestion methods (~10 integration tests)
- [ ] **Phase 4**: Advanced features (batch writer, EMU factory, ACK) (~40 tests)
- [ ] **Phase 5**: Validators and retry policies (~27 tests)

**Current Status**: Core sync SDK complete with 152 unit tests passing
**Next Step**: Phase 3.2 - Async client implementation for FastAPI integration tests

---

## Development Commands

```bash
# Run all SDK unit tests
uv run pytest sdk_tests/unit/ -v

# Run specific module
uv run pytest sdk_tests/unit/test_config.py -v       # 15 tests ✅
uv run pytest sdk_tests/unit/test_errors.py -v       # 25 tests ✅
uv run pytest sdk_tests/unit/test_transport.py -v    # 24 tests ✅
uv run pytest sdk_tests/unit/test_atoms.py -v        # 28 tests ✅
uv run pytest sdk_tests/unit/test_serializers.py -v  # 26 tests ✅
uv run pytest sdk_tests/unit/test_models.py -v       # 34 tests ✅

# Run with coverage
uv run pytest sdk_tests/unit/ --cov=ami --cov-report=term-missing
```
