wiki/sources/legacy/Design-2026-05-03-phase1-complete.md
Scout Design Log — Phase 1 Complete (2026-05-03)
What Was Built This Session (continuation from earlier in day)
Phase 1 is now fully built across all components:
| Component | Files | Commit |
|---|---|---|
| FastAPI service | scout/api/config.py, deps.py, main.py, middleware/auth.py, routers/ (6 files) |
c040bb9 |
| Docker | docker/Dockerfile, docker/docker-compose.yml, .env.example |
d96481c |
| Claude skill | scout/skill/scout.md |
29344d1 |
FastAPI Architecture Decisions
get_crawler lives in deps.py, not main.py
Circular import issue: routers need to import get_crawler, and main.py imports routers. Putting get_crawler in deps.py breaks the cycle cleanly. main.py re-exports it via from scout.api.deps import get_crawler so test imports still work.
ScoutCrawler as lifespan singleton
@asynccontextmanager
async def lifespan(app: FastAPI):
app.state.crawler = ScoutCrawler(llm_api_key=settings.llm_api_key)
yield
Never constructed per-request. Required for testability — tests override via app.dependency_overrides[get_crawler] = lambda: mock_crawler.
Auth middleware exempts /health
AuthMiddleware(BaseHTTPMiddleware) reads X-API-Key header. /health path bypasses auth entirely — required for Docker healthcheck to work without credentials.
Routers have zero error handling
All error handling is in the mode functions (catch + return success=False). Routers are pure delegation — one line each. 4xx errors come only from auth (403) and Pydantic validation (422).
Docker Architecture Decisions
shm_size: 1gb is mandatory
Playwright's Chromium uses /dev/shm for inter-process communication. Default Docker shared memory (64MB) causes browser crashes under load. shm_size: '1gb' in docker-compose.yml prevents this.
System deps installed explicitly (not via playwright install-deps)
playwright install-deps chromium requires root and works on Debian/Ubuntu but is fragile across Docker base images. Explicit apt-get install of known Chromium deps is more reliable and audit-friendly.
Build context is .. (repo root), not docker/
Dockerfile COPYs pyproject.toml and scout/ from the repo root. docker-compose.yml sets context: .. to make this work.
Scope Decision: No fact-checking in Scout
Arijit proposed adding Perplexity cross-validation to Scout (crawl + search = fact-check). Rejected: - Violates single responsibility — Scout is a crawler, not a validator - This already exists in PRISM's intel_company 3-track pipeline (WebFetch + Perplexity + Synthesis LLM) - Adds latency and Perplexity API key dependency to every Scout consumer - Reconciliation logic belongs in the application layer (PRISM), not infrastructure (Scout)
Test State at Phase 1 Complete
Unit + contract: 70 passing
Integration: 6 passing (real Crawl4AI v0.7.7)
pyright: 0 errors
ruff: clean
Unit tests for API use app.dependency_overrides — no real Crawl4AI, no network.
What's Not Done Yet
- Smoke test — HTTP stack (
uvicorn scout.api.main:app+ real curl) never run - PRISM Phase 4 — intel_hiring + intel_company migration to ScoutCrawler not started
- Skill registration —
scout/skill/scout.mdwritten but not installed in Claude Code - Extract integration test — skipped (needs LLM API key); manual verification needed
Next Session Entry Point
Run smoke test first (SESSION.md has exact commands). Then PRISM Phase 4.