- checkAuth() reads the expected token from a TOKEN_KINDS table
(read -> HEALTH_TOKEN, ingest -> HOSTS_INGEST_TOKEN, claude-ingest ->
CLAUDE_USAGE_INGEST_TOKEN); each ingestion token fails closed to a 503
naming its own variable. Still one gate, one tokenMatches() call. A route
naming an unknown kind fails module load.
- readBody() takes its ceiling per route: 4 KiB for /hosts/<id>, 64 KiB for
/claude-usage.
- claude-usage.js: pure, exported sanitizeClaudeUsage() for contract
schemaVersion 1 (whitelist rebuild, invalid values dropped, list bounds).
- POST /claude-usage: 400 on invalid JSON or schemaVersion, server-stamped
receivedAt, atomic write (pid-suffixed temp, mode 600, rename), 204.
- GET /claude-usage: re-sanitized snapshot with ageSeconds, stale and
staleAfterSeconds (CLAUDE_USAGE_STALE_SECONDS, default 2700), or no_data.
- Dockerfile COPY ships claude-usage.js.
- auth.test.js: the checkAuth() equality allowlist loses the former
`route.tokenKind === "ingest"` entry, which the table removes. The pin
only got stricter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>