# Task ID: 2

**Title:** Implement Constants and Exception Hierarchy

**Status:** pending

**Dependencies:** 1

**Priority:** high

**Description:** Create the constants module with API URLs, exit codes, and defaults, plus the custom exception hierarchy for error handling.

**Details:**

Create `src/teams_phone/constants.py`:
```python
GRAPH_API_BASE = "https://graph.microsoft.com/beta"
GRAPH_API_V1_BASE = "https://graph.microsoft.com/v1.0"
DEFAULT_CONFIG_PATH = "~/.teams-phone/config.toml"
DEFAULT_CACHE_PATH = "~/.teams-phone/cache"
DEFAULT_TOKEN_PATH = "~/.teams-phone/tokens"
CSV_STALE_DAYS = 30
DEFAULT_TIMEOUT = 30
MAX_RETRIES = 3

class ExitCode(IntEnum):
    SUCCESS = 0
    GENERAL_ERROR = 1
    AUTH_ERROR = 2
    AUTHZ_ERROR = 3
    NOT_FOUND = 4
    VALIDATION_ERROR = 5
    RATE_LIMIT = 6
    CONFIG_ERROR = 7
    CONTRACT_ERROR = 8
```

Create `src/teams_phone/exceptions.py` with hierarchy:
- TeamsPhoneError (base)
- AuthenticationError, AuthorizationError, NotFoundError, ValidationError, RateLimitError, ConfigurationError, ContractError
- Each with exit_code property and remediation message support

**Test Strategy:**

Unit tests in `tests/unit/test_exceptions.py` verifying each exception has correct exit_code, can include remediation message, and inherits properly.

---

## Implementation Notes

### Session: 2026-01-28 22:35 - Agent: claude-opus-4-5-20251101

**Status:** Implemented

#### What Was Done
- Implemented `src/teams_phone/constants.py` with:
  - Graph API URLs (beta and v1.0)
  - Default file paths for config, cache, and tokens
  - Timeout and retry settings (DEFAULT_TIMEOUT=30, MAX_RETRIES=3, CSV_STALE_DAYS=30)
  - ExitCode IntEnum with values 0-8 and comprehensive docstrings
- Implemented `src/teams_phone/exceptions.py` with:
  - TeamsPhoneError base class with message and remediation support
  - 7 specialized exception subclasses (AuthenticationError, AuthorizationError, NotFoundError, ValidationError, RateLimitError, ConfigurationError, ContractError)
  - Each exception has exit_code class attribute mapping to ExitCode enum
  - Custom `__str__` method that formats remediation with "To fix:" prefix
- Created `tests/unit/test_exceptions.py` with 26 unit tests covering:
  - Exit code mapping for all exceptions
  - Inheritance hierarchy verification
  - Remediation message handling
  - Exception raising and catching behavior

#### Key Decisions Made
- **Used class attribute for exit_code**: Defined `exit_code: int = ExitCode.X` as a class attribute rather than instance property for simplicity and consistency. All instances of an exception class share the same exit code.
- **Keyword-only remediation**: Made `remediation` a keyword-only argument (`*, remediation: str | None = None`) to prevent accidental positional usage and improve code clarity.
- **Exit code 8 documentation**: Added clear docstring note explaining that CONTRACT_ERROR (exit 8) is intentionally undocumented in user-facing specs as it indicates internal errors users cannot remediate.

#### Patterns Discovered
- **IntEnum for shell compatibility**: Using `IntEnum` allows both semantic comparisons (`exc.exit_code == ExitCode.AUTH_ERROR`) and integer comparisons (`exc.exit_code == 2`) which is useful for shell scripts.
- **Docstring pattern**: Module and class docstrings follow Google style already established in `src/teams_phone/__init__.py`.

#### Open Items for Next Agent
- [ ] Exception subclasses (TokenExpiredError, UserNotFoundError, etc.) to be added when specific features need them
- [ ] CLI layer will handle formatting with Rich library - exceptions stay simple

#### Gotchas and Warnings
- **Mypy strict mode**: All functions need complete type hints. The `exit_code` class attribute is typed as `int` (not `ExitCode`) because IntEnum values are ints.
- **Remediation formatting**: The `__str__` method adds "\n\nTo fix:\n" prefix - don't include that in the remediation string itself.
