Skip to content

Human Review Queue

HumanReviewQueue is a durable human-in-the-loop gate for halted outputs and post-halt correction proposals. It is separate from ReviewQueue, which is only the continuous batching queue for scorer throughput.

The queue stores pending cases, reviewer decisions, release decisions, and retry requests in SQLite. Candidate text is never included in default audit payloads; callers must explicitly request it when they are inside the tenant boundary.

from director_ai import HumanReviewQueue

queue = HumanReviewQueue("review.db")

case = queue.enqueue_case(
    candidate_text="Corrected answer that still needs review.",
    evidence_refs=("kb://policy-42", "trace://halt-17"),
    tenant_id="tenant-a",
    request_id="req-123",
    source_kind="halt",
    reason="coherence halt",
)

queue.decide(
    case.case_id,
    reviewer_id="reviewer-1",
    action="approve",
    reason="source verified",
)

released_text = queue.release(
    case.case_id,
    reviewer_id="reviewer-1",
    release_id="release-20260513-001",
)

Correction Proposals

Use enqueue_correction_proposal() to connect the queue to CorrectionLoop. The correction loop still supplies verifier consensus and an unreleased candidate; the human review queue supplies durable reviewer approval and release audit.

case = queue.enqueue_correction_proposal(
    proposal,
    tenant_id="tenant-a",
    request_id="req-123",
    reason="post-halt correction proposal",
)

State Transitions

Current status Allowed action New status Release text available
pending approve approved No
approved release() released Yes
pending reject rejected No
pending request_retry retry_requested No

Rejected, retry-requested, and released cases cannot be re-decided. release() requires an approved case, a reviewer id, and a release id.

Retry Gate

retry_payload() is available only after a reviewer requests retry. It returns tenant-safe routing context and evidence references, never candidate text.

queue.decide(
    case.case_id,
    reviewer_id="reviewer-1",
    action="request_retry",
    reason="needs fresher source",
    metadata={"retry_budget": 1},
)

payload = queue.retry_payload(case.case_id)

Tenant-Safe Audit

HumanReviewCase.to_dict() excludes candidate_text by default:

audit_payload = case.to_dict()
assert "candidate_text" not in audit_payload

Use include_candidate=True only inside a tenant-controlled review surface.

Full API

director_ai.core.runtime.human_review.HumanReviewQueue

HumanReviewQueue(db_path: str | Path = ':memory:')

SQLite-backed human review queue with gated release and retry paths.

enqueue_case

enqueue_case(*, candidate_text: str, evidence_refs: Sequence[str], tenant_id: str = '', request_id: str = '', source_kind: str = 'halt', reason: str = '', safety_event: SafetyEvent | Mapping[str, Any] | None = None, metadata: Mapping[str, str] | None = None, case_id: str | None = None) -> HumanReviewCase

Add a pending review case.

enqueue_correction_proposal

enqueue_correction_proposal(proposal: CorrectionProposal, *, tenant_id: str = '', request_id: str = '', reason: str = '', metadata: Mapping[str, str] | None = None) -> HumanReviewCase

Queue a correction proposal for human release approval.

get_case

get_case(case_id: str) -> HumanReviewCase

Return one review case by id.

list_cases

list_cases(*, status: ReviewStatus | None = None, tenant_id: str | None = None, limit: int = 0) -> list[HumanReviewCase]

List cases, newest first, optionally filtered by status or tenant.

decide

decide(case_id: str, *, reviewer_id: str, action: str, reason: str = '', metadata: Mapping[str, str] | None = None) -> HumanReviewCase

Apply a reviewer decision and append it to the audit trail.

release

release(case_id: str, *, reviewer_id: str, release_id: str) -> str

Return candidate text only after a case has been approved.

retry_payload

retry_payload(case_id: str) -> dict[str, Any]

Return tenant-safe retry instructions only after retry approval.

decisions

decisions(case_id: str) -> list[HumanReviewDecision]

Return append-only decision history for one case.

close

close() -> None

Close the backing database. Safe to call multiple times.

director_ai.core.runtime.human_review.HumanReviewCase dataclass

HumanReviewCase(case_id: str, status: ReviewStatus, source_kind: str, candidate_text: str, evidence_refs: Sequence[str], tenant_id: str = '', request_id: str = '', reason: str = '', safety_event: Mapping[str, Any] | None = None, metadata: Mapping[str, str] = dict(), release_id: str = '', created_at: float = time.time(), updated_at: float = time.time())

Durable case awaiting explicit reviewer decision.

to_dict

to_dict(*, include_candidate: bool = False) -> dict[str, Any]

Serialise a tenant-safe case payload.

Candidate text is excluded by default because review queues commonly feed dashboards, alerts, and audit exports outside the tenant boundary.

director_ai.core.runtime.human_review.HumanReviewDecision dataclass

HumanReviewDecision(decision_id: str, case_id: str, reviewer_id: str, action: ReviewAction, reason: str = '', metadata: Mapping[str, str] = dict(), timestamp: float = time.time())

Append-only reviewer decision for one queued case.

to_dict

to_dict() -> dict[str, Any]

Return a JSON-safe audit record.