# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## What this is A self-hosted HTTP service that looks up Swedish phone numbers ("who is calling me?") by scraping reverse-lookup sites. Providers are WASM components (Component Model / WASI p2) loaded from a directory at startup; the host does all fetching and caching. Design spec: `docs/superpowers/specs/2026-06-05-wasm-provider-service-design.md`. ## Commands ```bash just test # build components + run all tests (preferred) just run # build components + run the service just build # release build of everything cargo test -p whoareyou-provider-hitta # provider parser tests (native, no WASM) cargo test -p whoareyou-server --test component # WIT-boundary integration test cargo +nightly fmt # always nightly, not stable cargo clippy --workspace ./fetch-fixture # refresh an HTML fixture from hitta.se ``` The integration test needs the component built first — run via `just test`, or `cargo build --release --target wasm32-wasip2 -p whoareyou-provider-hitta` before bare `cargo test`. ## Architecture - `wit/provider.wit` — the provider contract (`metadata`/`requests`/`parse`). Components are pure: no network, no filesystem. The HOST fetches URLs. - `crates/providers/hitta` — parse logic in `parser.rs` is plain Rust, unit-tested natively against `fixtures/hitta/*.html`; `component.rs` is thin WIT glue, compiled only for `wasm32` (`cargo test` never touches WASM here). hitta.se serves Next.js App Router pages — data lives in RSC flight payloads (`self.__next_f.push`), NOT `__NEXT_DATA__` (that's the dead 2019 format kept in old fixtures as a Failed-path regression case). - `crates/server` — lib + thin bin. `service.rs` holds the `ProviderHandle` + `Fetch` traits and `LookupService` (moka cache, TTL 24h, key `provider:number`; fetch failures are NOT cached). `wasm.rs` implements `ProviderHandle` over wasmtime (fresh Store per call, epoch deadline ≈5s — `spawn_epoch_thread` must run once at startup or runaway guests hang instead of trapping). `http.rs` is axum: `GET /api/v1/number/{number}`, `GET /healthz`. ## Gotchas - Components build with plain `cargo build --target wasm32-wasip2` — no cargo-component. Output name uses underscores: `whoareyou_provider_hitta.wasm`; the justfile copies it to `components/hitta.wasm` (gitignored). - One provider failing maps to a per-provider `status` in the JSON response — never a non-200 for the whole lookup. `parse_failed` in logs (WARN) means a site changed its markup: refresh a fixture with `./fetch-fixture` and fix the parser. - `ParseError::NoData` vs `Failed`: a fetched page with no phone data is NoData (normal); a page that doesn't match the expected structure is Failed (scraper rot). Don't conflate them.