The outreach engine uses a per-property lock to enforce a single active run per property while distributing up to 20 article generations across a thread pool bounded by a concurrency cap, running each independent red-to-blue chain inside isolated try/catch blocks so individual failures never crash the batch.

sequenceDiagram
    autonumber
    actor Client
    participant Lock as Property Lock
    participant Pool as ThreadPoolExecutor
    participant Worker as Worker Thread
    participant DB as Database

    Client->>Lock: Request batch (N articles)
    alt Run already active
        Lock-->>Client: Reject request
    else Lock acquired
        Lock->>Pool: Spawn workers (max CONCURRENCY)
        loop Independent Red-to-Blue Chain
            Pool->>Worker: Run chain (isolated try/catch)
            Note over Worker: Red Writer<br/>-> Dead Link Pruner<br/>-> Banned Domain Check<br/>-> Blue Detector
            Worker->>DB: Stream result (Passed / Folded)
        end
        Worker-->>Pool: Task complete
        Pool-->>Lock: All workers done
        Lock-->>Client: Batch complete
    end