# ADR-0105: E27 Error Classification and Responsibility Boundaries

Status: Accepted

## Context

E27 functionality spans multiple layers with distinct responsibilities:
transport connectivity, protocol framing/crypto, and application-layer JSON APIs.

Without an explicit, stable error taxonomy, contributors may:
- misclassify failures (e.g., treating protocol errors as auth errors)
- implement inconsistent retry behavior
- surface confusing Home Assistant messages
- write tests that inadvertently lock in accidental behavior

Tests and diagnostics depend on consistent classification and messaging.

## Decision

E27 errors are classified into a small set of categories, with clear ownership
by layer and consistent handling expectations.

1. TransportError
   - Meaning: Connectivity failure (socket/serial) or inability to move bytes
   - Owned by: connection pump / transport layer
   - Examples: connect timeout, connection reset, EOF, DNS failure
   - Handling: reconnect/backoff policy applies; not a protocol fault

2. ProtocolError
   - Meaning: The bytes received cannot be interpreted as valid E27 protocol
   - Owned by: E27 backend framing/presentation/state machine layers
   - Examples:
     - invalid schema identifier
     - invalid protocol byte semantics
     - invalid pad_len values
     - framing parse failures
     - illegal state transitions
     - malformed envelope fields
   - Handling: treated as fatal for the current connection/session; reconnect may be attempted

3. CryptoError
   - Meaning: Valid frame structure, but cryptographic processing fails
   - Owned by: E27 backend presentation/crypto layer
   - Examples:
     - decryption failure (AES)
     - padding removal mismatch
     - word-swap mismatch
     - HMAC validation failure (when enforced)
   - Handling: treated as fatal for the current connection/session; reconnect may be attempted

4. AuthError
   - Meaning: Authentication or authorization failure at the application level
   - Owned by: E27 backend API layer / authorization controller
   - Examples:
     - invalid credentials / pairing / link-key missing or rejected
     - PIN escalation rejected
     - permission denied returned by API
   - Handling: not resolved by reconnect alone; requires user intervention or re-linking

5. ApiError
   - Meaning: Application-layer API request/response semantics fail
   - Owned by: E27 API message layer (domain modules)
   - Examples:
     - missing required JSON fields
     - schema mismatch in API payload
     - non-zero error_code indicating an API failure not strictly authorization-related
     - response does not correlate to request (seq mismatch)
   - Handling: may be retryable depending on error_code; does not imply protocol corruption

6. ConfigError
   - Meaning: Local configuration is missing, inconsistent, or invalid
   - Owned by: integration/config management layer above backend
   - Examples:
     - missing link keys when required for operation
     - invalid URL scheme or incomplete configuration
   - Handling: requires configuration repair, not reconnect

Classification rules:

- A failure MUST be classified by the layer that detects it.
- Application code must not downgrade ProtocolError/CryptoError into ApiError.
- TransportError is never reported as a protocol failure.
- Where ambiguous, prefer ProtocolError over ApiError for non-JSON failures,
  and ApiError over ProtocolError for valid JSON that fails semantic validation.

## Rationale

A stable taxonomy enables:
- consistent retries and reconnection behavior
- clear Home Assistant user-facing messaging
- deterministic testing and troubleshooting
- future protocol hardening (e.g., HMAC enforcement) without reinterpreting errors

## Consequences

- Tests may assert error category boundaries
- Logging and diagnostics can consistently summarize failure causes
- Retry policy can be layered:
  - TransportError -> reconnect
  - ProtocolError/CryptoError -> reset session and reconnect
  - AuthError/ConfigError -> user remediation required

## Scope / Non-Goals

- Does not define exact exception classes or names
- Does not mandate retry timing or backoff values
- Does not define specific error_code-to-category mapping tables

## References

- ADR-0100: E27 Framing and Presentation Layer Semantics
- ADR-0101: Schema-0 Envelope Semantics and Protocol Byte Meaning
- ADR-0103: Session Lifecycle Boundaries — Unframed vs Framed Traffic and Responsibilities
- HelpDealerAPI_UL documentation
