POST /api/v1/jobs accepts the whole list, validates the JWT + job ownership,
and finalizes the run server-side: per-chunk verifier_checks upserts,
processed_count/valid/risky/bad heartbeats on verifier_jobs, completed/error
finalization and risky+unprocessed refunds via the service-role ledger.
This removes the 'submitting client is gone' failure class (10 of the last 15
failed CSV runs on 2026-10-20/21): the browser no longer orchestrates chunking,
so a closed/throttled tab can no longer orphan a run holding thousands of
credits. classify_engine_result mirrors src/lib/verifier.ts classify() exactly
(NXDOMAIN -> Invalid/bad, dns_timeout/a_fallback_only -> Unknown/risky).
Frontend counterpart: runBulk v2 posts /jobs and polls the DB row only, with a
legacy chunk-loop fallback for engines predating this route (404/405).
Tests: tests/test_verifier_jobs.py (12 cases: classification edges, auth,
ownership, lifecycle finalization, chunk-failure refund path).
Yesterday
fix(entrypoint): start the celery worker only when CELERY_BULK_ENABLED=true — a misconfigured rediss:// broker caused a pointless 5s crash-restart loop while bulk actually runs syncRunning
Z User
4c14cbd
feat(main): warm the local risk scorer at startup — baked weights load from disk cache, first paying request never pays model load
Z User
1054555
v3.1.0: Part B architecture migration — eliminate Hugging Face inference credit dependency
Z User
6c516b6
- Change 1+2: new app/ml/local_scorer.py — in-process transformers
zero-shot pipeline (DistilBERT-class default
typeform/distilbert-base-uncased-mnli), device=-1, lazy load, fail-open
- Change 3: app/ml/hf_scorer.py -> app/ml/risk_scorer.py; the remote
router.huggingface.co HTTP path is REMOVED; AIRiskScorer now scores via
LocalRiskScorer with circuit breaker (model-load failure opens it
permanently) + PII-free feature-string TTL score cache (spec §2.2)
- Change 4: Dockerfile bakes model weights at build (HF_HOME=/app/models);
a running container makes zero network calls for scoring
- Change 5: HF_INFERENCE_TOKEN / ML_HF_TOKEN removed from config, .env,
.env.example, runtime.py and health status — no HF token exists in the
deployment surface
- runtime.py: EmailRiskModel drops token param (public Hub download only)
- tests: test_hf_scorer.py -> test_risk_scorer.py with local-only
architecture pins (no httpx, no remote endpoints, no token attr);
332 tests pass
- Part …
fix(auth): exact-match open paths for engine/status, metrics/inference, smtp/probe
FortyDN Dev
5979e23
_is_open_path() excludes exact prefix equals by design (health needed its own
_OPEN_EXACT entry); the new ops + worker routes are exact equals, so they were
still license-gated. Add them to _OPEN_EXACT — worker probes keep their own
X-Worker-Token guard.
The PORT secret is 8000, so uvicorn bound 8000 and the platform never
saw the app come up -> stuck APP_STARTING. Spaces always route to 7860.
Co-Authored-By: Claude Code <noreply@anthropic.com>
fix(entrypoint): PING-verify Space secret Redis URLs before trusting them
A stale secret (expired Upstash DB, NXDOMAIN) shadowed the local sidecar
and crash-looped the Celery worker -> RUNTIME_ERROR. Dead secrets are now
ignored and the sidecar takes over.
Co-Authored-By: Claude Code <noreply@anthropic.com>
fix: run local redis-server sidecar instead of fragile Upstash provisioning
Diagnosed via Space run logs: Celery worker crash-looped every ~9s
("broker_connection_retry_on_startup=False ... Shutting down") because the
Upstash start-redis provisioning did not succeed from the Space network, so
the broker fell back to localhost with nothing listening and the container
never became READY.
- Dockerfile(s): install redis-server; entrypoint starts a volatile local
sidecar (port 6379, 120mb LRU) and wires cache/broker/result to
redis://127.0.0.1:6379/{0,1,2} after a PING gate
- Space secrets still win (REDIS_URL/CELERY_BROKER_URL/CELERY_RESULT_BACKEND)
- Upstash free-tier provisioning kept only as last-resort fallback
- Celery: retry broker connect on startup (survive sidecar cold start)
- Entrypoint supervisor: restart sidecar/worker if they die; skip worker
entirely when no broker exists
Co-Authored-By: Claude Code <noreply@anthropic.com>