EVERY DEMO RUN IS A LIVE PIPELINE — NOT A SCRIPT

Verdict.

//ARCHITECTURE

How Verdict works

Eleven stages, run in this order for a reason: identity resolution before spend, extraction before verification, verification before scoring, scoring before a draft is ever written.

  1. //00

    Validate + idempotency

    Ordinary code. Required fields, email/domain normalization. Replaying a submissionId returns the existing result — never reprocesses.

  2. //01

    Identity resolution

    Runs BEFORE enrichment/scoring, deliberately. Exact email or domain match only counts as "confident" — name similarity, even a perfect score, never auto-merges.

  3. //02

    Classify message

    Haiku labels the message into approved categories. Vendor pitches, job applications, and student research hard-disqualify here, before any research spend.

  4. //03

    Find research source

    Looks up a domain in the seeded fixture corpus. An ambiguous or missing identity means no safe source to pick — enrichment correctly returns nothing rather than guessing.

  5. //04

    Extract facts

    Haiku reads the source page and extracts only explicitly stated facts into a fixed field schema, with a verbatim supporting quote for each. There is no field for a score, a discount, or an instruction — structurally, nothing else can land here.

  6. //05

    Verify facts

    Two independent checks per fact: a deterministic quote-in-source substring check (free, catches fabricated quotes), then a batched Haiku pass judging entailment and flagging quotes that read as instructions rather than facts. Only what survives both becomes "verified".

  7. //06

    Evidence-sufficiency gate

    Ordinary code. Counts resolved ICP criteria against a floor. Below the floor: no score is ever computed — the lead returns the specific questions that would unblock it.

  8. //07

    Score (if the gate is open)

    Deterministic points-based scoring across 7 criteria, each with cited evidence. A veto on B2B-fit or region disqualifies regardless of the numeric total.

  9. //08

    Propose CRM change set

    A diff, never a write. Possible identity matches propose nothing — a human resolves the merge. Confident matches propose an update; new leads propose a create.

  10. //09

    Draft outreach (gated)

    Only for qualified bands, and only using the lead's own message plus verified facts. Every claim the draft makes is independently re-verified against that same grounding text — never trusted from the drafting call's self-report.

  11. //10

    Audit + jobs

    Every stage above writes a started/completed/failed audit event with duration. A Postgres jobs table tracks attempts — the durable queue, not an external service.

Stack

  • Next.js 16 (App Router) + TypeScript, Supabase Postgres (RLS-locked, service-role only)
  • Claude Haiku for every model call, temperature pinned to 0
  • Durable job queue: a Postgres table with attempts/backoff — no external queue service
  • Enrichment reads a seeded fictional “mini-web”, not the live internet — deterministic, $0, every citation a real in-app URL
  • Rate limiting + a race-safe daily spend cap (Postgres FOR UPDATE, not read-then-write)