Skip to content

Item, badge, container

The physical worldScanSDKholdaccumulateaccumulate.from: subjectconditionalAccumulator

Three scans place an item in a container: the item says which, the badge says who, and the container scan writes both rows at once.

The situation

At a bench where bags go into bins, every act is one bag going into one bin. The associate should scan the bag, badge in, scan the bin, and move on. Nothing to type, nothing to tap.

The recipe

The bag scan holds the bag as a subject. The bin scan is the act.

start.ts (rules)
// 12:0, bag label: hold the bag and show its bin, large
{ query: { roles: ['bagging'] }, verb: 'hold',
params: { hold: { ttlSeconds: 300, label: '{scan.target}', headline: '{item.binKey}',
expect: { schemes: [13], prompt: 'Walk to this bin and scan it.' } } } },
// 13:0, bin label: the held bag joins the bin it names
{ query: { roles: ['binning'], status: 'pending' }, verb: 'accumulate',
requireActingIdentity: true,
subject: { schemes: [12] },
match: { facets: ['binKey'] },
refuse: { markdown: "That's bin {container.binKey}. This bag goes in **{subject.binKey}**." },
done: { markdown: 'Drop it in **{container.binKey}**. All good.' },
params: { itemKey: '{subject.orderId}', accumulate: { from: 'subject' } } },

The bin is an open accumulator (conditionalAccumulator with accumulate), and each bag waits on its own one-slot row (accumulate: { max: 1 }). The badge can come before the bag or between the bag and the bin.

The guarantee

The container scan is one reciprocal statement: the bin gains the bag and the bag’s row gains the bin, both rows or neither. Of two racing acts on the same row, exactly one wins. A bag already in the scanned bin answers executed with already: true, and nothing is written twice. A bin scan that needs a badge answers not_primed with replayable: true, and the station replays it once a badge primes. See Scan codes.