Skip to content

Confidence-gated escalation

The escalation boundaryDashboardHTTPSDKMCPconditionalproxyActivities

The workflow finishes on its own when the model is confident and parks a review row when it is not, so people see only the uncertain cases.

The situation

A model scores each item. Most scores are high and need no one. A few are borderline, and those should land in front of a reviewer with the model’s reasoning attached, while the workflow waits for the answer.

The recipe

workflows/review-item.ts
import { Durable } from '@hotmeshio/hotmesh';
import { conditional, type LTEnvelope } from '@hotmeshio/long-tail';
import * as activities from './activities';
const { analyzeItem } = Durable.workflow.proxyActivities<typeof activities>({ activities });
export async function reviewItem(envelope: LTEnvelope) {
const { itemId } = envelope.data;
const analysis = await analyzeItem(itemId);
if (analysis.confidence >= 0.85) {
return { type: 'return' as const, data: { approved: true, analysis } };
}
const { workflowId } = Durable.workflow.workflowInfo();
const review = await conditional<{ approved: boolean; notes?: string }>(`review-${workflowId}`, {
role: 'reviewer',
description: `Review needed (confidence ${analysis.confidence})`,
metadata: { itemId, confidence: analysis.confidence },
envelope: { analysis },
timeout: '48h',
});
if (!review) return { type: 'return' as const, data: { approved: false, reason: 'no-review' } };
return { type: 'return' as const, data: { approved: review.approved, notes: review.notes } };
}

The model call is a checkpointed activity. Above the threshold the workflow returns. Below it, conditional writes one reviewer row carrying the score as a facet and the analysis as context, then waits.

The guarantee

The confident path writes no row. The uncertain path writes exactly one row, in the same commit as the wait, and the workflow resumes with the reviewer’s typed payload. Because confidence is a metadata facet, the queue can sort and filter on it with a range query. See Conditional.