docs: add error handling patterns and module dependencies to CLAUDE.md
All checks were successful
Tests / lint (push) Successful in 3s
Tests / test (push) Successful in 30s

- Document 3 graceful degradation patterns with code examples
- Add Service Fallback Matrix for optional services
- Add module dependency tree with change impact guide

chore: fix typecheck environment

- Add mypy to dev dependencies in pyproject.toml
- Fix tox.ini typecheck environment to install mypy explicitly
This commit is contained in:
Trip T
2026-03-11 22:21:07 -04:00
parent 05bd7f03f4
commit c7f92f6d7b
3 changed files with 100 additions and 0 deletions

View File

@@ -111,6 +111,55 @@ tox -e dev # Start dashboard with auto-reload
---
## Error Handling Patterns
All optional services (Ollama, Redis, AirLLM, voice, etc.) must degrade gracefully. Three approved patterns:
### Pattern 1: Optional Return (data retrieval)
```python
def get_user_setting(key: str) -> Optional[str]:
try:
return db.query(...)
except Exception as exc:
logger.warning("Setting lookup failed: %s", exc)
return None
```
### Pattern 2: Fallback Value (computations)
```python
def compute_embedding(text: str) -> list[float]:
try:
return model.encode(text)
except Exception as exc:
logger.warning("Embedding failed, using hash: %s", exc)
return hash_based_fallback(text)
```
### Pattern 3: Feature Disable (optional services)
```python
async def transcribe_audio(audio: bytes) -> str:
try:
return await voice_service.transcribe(audio)
except ServiceUnavailable:
logger.warning("Voice service unavailable — feature disabled")
return "" # Silently disable feature
```
### Service Fallback Matrix
| Service | When Unavailable | Fallback Behavior |
|---------|------------------|-------------------|
| Ollama | No local LLM | Claude backend (if ANTHROPIC_API_KEY set) |
| Redis | Cache/storage down | In-memory dict (ephemeral) |
| AirLLM | Import error or no Apple Silicon | Ollama backend |
| Voice (Piper) | Service down | Browser Web Speech API |
| WebSocket | Connection failed | HTTP polling (degraded) |
| Telegram/Discord | No token configured | Bot doesn't start (logs only) |
**Rule:** Never crash the app when an optional service is down. Log at WARNING level and continue.
---
## Frontend Architecture
### Stylesheets
@@ -181,3 +230,50 @@ McToast.show('Request failed', 'error'); // red border
| `brain/` | Identity system, memory interface |
| `timmy_serve/` | API server |
| `config.py` | Pydantic settings (foundation for all modules) |
## Module Dependencies
```
config.py # Foundation — no internal dependencies
├── timmy/ # Core agent
│ ├── Uses: config, brain, infrastructure
│ └── Impact: 🔴 High — used by dashboard, integrations, timmy_serve
├── brain/ # Memory system
│ ├── Uses: config
│ └── Impact: 🟡 Medium — used by timmy, spark
├── infrastructure/ # Shared services
│ ├── Uses: config
│ └── Impact: 🔴 High — used by ALL packages
│ ├── ws_manager # WebSocket connections
│ ├── notifier # Push notifications
│ └── event_bus # Pub/sub events
├── spark/ # Intelligence engine
│ ├── Uses: config, brain
│ └── Impact: 🟢 Low — self-contained
├── integrations/ # External services
│ ├── Uses: config, infrastructure
│ └── Impact: 🟡 Medium — isolated by vendor
├── dashboard/ # Web UI
│ ├── Uses: ALL packages
│ └── Impact: 🔴 High — entry point, orchestrates everything
└── timmy_serve/ # API server
├── Uses: config, timmy, infrastructure
└── Impact: 🟡 Medium — standalone service
```
### Change Impact Guide
| If you modify... | You should test... |
|------------------|-------------------|
| `config.py` | Full suite (`tox -e ci`) — affects everything |
| `infrastructure/` | Unit + integration + functional |
| `timmy/` | Unit tests + chat/CLI tests |
| `dashboard/routes/` | Dashboard route tests (usually isolated) |
| `brain/` | Brain client/worker tests + timmy tests |

View File

@@ -73,6 +73,7 @@ selenium = ">=4.20.0"
pytest-randomly = "^4.0.1"
pytest-xdist = "^3.8.0"
ruff = ">=0.8.0"
mypy = ">=1.0.0"
[tool.poetry.scripts]
timmy = "timmy.cli:main"

View File

@@ -38,6 +38,9 @@ commands =
[testenv:typecheck]
description = Static type checking with mypy
commands_pre =
deps =
mypy>=1.0.0
commands =
mypy src --ignore-missing-imports --no-error-summary