All docs

Verification engine

Verification engine

Module: packages/core/src/verification/engine.ts Worker: apps/mcp/src/workers.ts (BullMQ queue verification)

Pipeline

complete_task(taskId)
        │
        │  Task lands in `needs_review` with verification_status='pending'.
        │  completeTask enqueues a verification job (jobId=`verify-{taskId}`).
        ▼
[ verification worker ]
        │
        │  1. SELECT task by id (loads snapshot verificationContract)
        │  2. isBlockedByReview?  → pending(blocked_by_review), retry later
        │  3. switch (contract.kind):
        │      none    → skipped (state already done)
        │      manual  → skipped (human gate stays)
        │      github_pr → verifyGitHubPr(client, ref)
        │      gitlab_mr → verifyGitLabMr(client, ref)
        │      commands → failed (unsupported until sandboxed exec lands)
        │  4. verdict:
        │      passed  → UPDATE tasks SET state='done', verification_status='passed'
        │      failed  → markNeedsReview(reason='verification.<code>')
        │      pending → return; worker re-enqueues with exponential backoff
        │  5. After MAX_ATTEMPTS=10 pending in a row → failed(reason=verification.timeout)
        │
        ▼
[ pub/sub: pubsub:org:{orgId}:tasks ]
       task.verification.{passed|failed|pending|skipped}

external_ref parsing

GitHub PRs come in as owner/repo#123, GitLab MRs as group/proj!42. The default parser accepts either separator. Tasks without an external_ref on a github_pr/gitlab_mr contract fail with reason verification.missing_external_ref.

Reasons (the needs_review_reason codes)

Provider clients

The orchestrator is dependency-injected — the worker passes a { github, gitlab } deps bag. Today the bag is empty in the runtime worker (apps/mcp/src/workers.ts), so any task with kind='github_pr' or kind='gitlab_mr' will throw with the explicit message verification: github_pr task requires deps.github client. Wiring the Octokit / gitbeaker adapters happens when an installation is provisioned (task 30/31 runbooks). The throw is intentional — we don't want a silent "passes everything" stub in production.

Retry & backoff

The default BullMQ options in packages/shared/src/queues.ts give exponential backoff with 5 attempts; the engine itself caps at MAX_ATTEMPTS=10 if the caller passes attempt. Real wall-clock budget is ~1 hour for a PR to merge after complete_task — beyond that the task goes to needs_review for human attention.