Skip to content

Fill a checklist by scan

The physical worldScanSDKDashboardbatchfillfill.into: subjectfill.labelsroster

A batch row lists the codes an order expects; each scan checks one off, and the last fill completes the row and wakes the workflow.

The situation

An order expects a known set of items, some of them twice. A person matches each physical item to the order by scanning it, and needs to see what is still missing in plain words, not codes.

The recipe

The workflow parks a batch whose keys are the expected codes. A code expected twice is declared <code>#1 and <code>#2.

workflows/match.ts
const matched = await conditional<Record<string, unknown>>(`match-${orderId}`, {
role: 'matching',
metadata: { orderId },
envelope: { item_labels: labels },
batch: ['00012345678905#1', '00012345678905#2', '00098765432109'],
});

The item scan, while the order is held, fills the next open key for its code:

rule 16:0 Item barcode
{ "query": { "roles": ["matching"] }, "verb": "fill",
"subject": { "schemes": [12] },
"refuse": { "markdown": "Not one of this order's items. Still to match: {fill.pending}." },
"done": { "markdown": "Matched. Next: {fill.next}" },
"params": { "fill": { "into": "subject", "labels": "envelope.item_labels",
"label": "{label.name}, size {label.size}" } } }

The answer carries progress: { filled, total, remaining }, and the subject stays held while items remain.

The guarantee

Each fill is one guarded statement: the payload lands only while its key is pending, a third scan of a code expected twice is refused, and the last fill resolves the row and wakes the wait atomically. Each fill records its actor and a database-clock time. See Batches and accumulators.