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).