worklists.dev

complete takes an event hash, not a boolean

A workforce system knows a button was pressed. A task closed with an event hash knows that an attested who scanned at an attested place inside the window. The type signature is the whole product.

One thesis: complete takes an event hash, not a boolean, and that one decision in the type signature is the difference between a system that records a button was pressed and a system that records work was done. Everything else on this door is support for it.

The boolean is the problem

Every task system you have integrated with closes a task the same way: somebody taps Done, and a completed: true lands in a row with a timestamp. The system is honest about what it knows. It knows that at 06:14 a session with a given login produced a tap. It does not know who was holding the device, where the device was, or whether the bag of lettuce that task was about was anywhere near it.

Then a chargeback arrives for a short shipment, or an auditor asks for the receiving record on a lot under a recall, and the boolean is produced as evidence. It is not accepted, and it should not be. A boolean is a claim by the application. Nobody outside the application can check it.

What the signature does instead

complete(record, {
  taskId, tenant,
  artifact: { kind: "event-hash", digest },
  by, at, actionId, seq, ns,
});

The closing argument is the hash of an EPCIS event that already exists on the spine — a CBV §8.9 event hash from epcis.dev. That event was captured through an attestation of the performer's identity, at a read point, at a time. So what the task record holds at settle is a pointer to *a real who, at a real place, inside the window*. The record of work done is the same object as the evidence it happened.

The package refuses eight shapes of settlement with a typed problem, among them true, a bare string, a pack digest, a 63-hex digest, and a second settle on a closed task. The one that actually occurs in practice is the empty digest. A settle path that has nothing to hash yet reaches for "" rather than for the error, and a system that accepted it would be back to a boolean with extra steps. It is refused.

A receiving count, end to end

A PO for forty cases of lettuce arrives at transactions.dev. dispatch converts it into a receiving task at dock 12 with a window. On Monday morning a receiver points a scanner at the SSCC on the pallet. The barcode layer decodes the mark and names the step; the identity rail attests who is holding the device; the event lands on the spine and comes back with a hash.

complete(task, hash) fires. The task folds to settled. Ask trace about it later and you get the PO that dispatched it, the receiver's attested identity, dock 12, 06:14, and the event hash — and the event itself is one more hop away on the spine, where it was always going to be, whether or not any task had existed.

Notice what the receiver did: one scan. No tap, no confirm dialog, no form. The close path requires no reading because the confirm is the scan.

What it refuses to do, and why

It does not write to the spine. There is one public write door in this family, and it is epcis.dev.capture. complete returns a captureIntent; it never performs the capture. The package's surface test greps its own source for fetch, XMLHttpRequest, node:http and WebSocket and fails on a hit. A work door that could write events would be a second source of evidence, and two sources is how evidence stops being evidence.

There is no reopen. A completed task is closed. If the wrong event closed it, the correction happens at the event grain: epcis.dev.correct emits a new event carrying an errorDeclaration, and the task's history shows the original settle and the correction beside it. A reopen verb would make the task record editable and break the append-only law one layer up.

It never returns a score. The settle carries the hash and its attestation grade. It does not carry a duration, a count against a target, or anything that could be summed across people. That is a boundary on the door, not a rendering choice.

For the vendor

If your product already emits EPCIS events, you are most of the way there. The work is to stop treating task completion as a field your UI sets and start treating it as a pointer your UI obtains. The hash exists the instant the capture is acknowledged; complete is one call with it.

Your customer asked for task completion that cannot be faked. It falls out of the spine rather than being built on top of it. Get started with the package and settle one task with one real hash, and then try to settle it with true. The refusal is the demonstration.

Get started.

Say what you will dispatch. Access opens the verbs against your own demand, the closing event validated at epcis.dev, and the frontline app under your own name.