v2.9.0
End-user impacting:
- Default severity level is now 25, down from 50, and comes from the model bundle.
- The --fetch flag is now --follow, with --follow-depth controlling chained hops (compatibility alias preserved)
- The suspicious ceiling is a flat 3000 instead of 4 × level, so raising -l moves only the hostile line.
Features
- New /v1/lookup takes batched queries and a caller-supplied FP budget, returning allow, block, unanalyzed, or unavailable.
- New /v1/analyze streams NDJSON progress and accepts force=1 and a per-request follow policy.
- GET /lookup and GET /status answer without analyzing, even while the model is still loading.
- New POST /analyze-purl resolves the package and its registry provenance server-side.
- --llm takes a failover chain so you grade locally and fall back to a billed endpoint only on refusal.
- Added --llm openrouter with openrouter/auto routing, and no model is hardcoded anywhere.
- Bearer tokens are read from files under ~/.tok/, never from argv or the environment.
- --token-file requires a bearer token on every route but /_/health, and loopback is not exempt.
- Added Cloudflare tunnel support plus make deploy for systemd, FreeBSD, and Bastille jails.
- Every request emits one structured access-log line with per-phase timings.
- Dependencies are skipped against hopper's shared corpus and not rescanned for 30 days.
- Windows gains mimalloc, physical-core sizing, safe extraction, and symlink handling.
- Warns when the host malloc is a debug build.
Fixes
- Fixed two panics on multi-byte UTF-8 that killed the whole analysis.
- /analyze can now be forced past a cached verdict after an engine upgrade.
- Fixed OpenRouter auto-routes, orphaned LLM permits, and request gating.
- The interpret circuit breaker now probes with one caller after cooldown instead of all of them.
- Unretrievable artifacts are now distinct from server errors.
- Bytes carrying a mismatched or unverifiable pin are scanned instead of dropped.
- Fixed the default bind identity, hopper registry uploads, the upload API, and replica failover.
- Uploads no longer queue before a verdict exists, which had raced hopper's claim queue.
Optimizations
- PGO in make release cuts 8% of wall time and 11% of CPU with identical output.
- Each payload gets a private thread pool sized by load, taking a 128-PURL sweep from 200s to 53s and p90 from 5.3s to 1.8s.
- Large archives take a bounded slot instead of oversubscribing the host.
- Idle pull-worker threads run at lower priority so background work never costs request latency.
- LLM admission adds a size veto and separate background concurrency, halving benign calls with no verdict changes.
- Worker latency is now a decayed percentile rather than a mean, so old incidents stop steering routing.
- Concurrent identical analyses collapse into a single run.
- Bloom filters moved to the burton crate with an LRU cache on the lookup path.