The process engine

A pure reducer advances closed Template syntax; a canonical application service handles commands, policy and persistence; a separate worker drives pending automatic work.

Start and edit

platform/runtime/src/application-service.ts pins a registered immutable execution definition when starting a process. Domain field expansion and source compilation happened before registration, not inside the runtime. Startup defaults are compiled expressions, evaluated with explicit startup context. Sharing starts private unless the authorized application changes it.

The current compatibility policy checks the API's process-write permission; source template.permissions, runInputs and startExpression are not newly activated start gates. Do not treat a source-only field as an authorization guarantee.

Step updates address an occurrence id, not just an activity key. The service checks process, activity and field access, filters permitted updates, writes current memory and appends sparse field audit. Completion validates required fields and the compiled completion predicate. Past edits in loose mode do not replay completed effects. Reopen preserves history and creates a new visit.

Automatic work

platform/runtime/src/machine.ts reduces sequential composition, choice, iteration, failure and recovery. It knows no Dune, Safe or application step tags. Integration/app authoring builds those operations from generic syntax. A process suspends at an effect; the host executes only its fixed generic schema under configured authority.

Waits record their chosen deadline. Host-dependent timestamp parsing is a journaled parse-time effect; pure UTC calculations take explicit time input. A resumed recorded wait does not recalculate its business schedule.

Known failures may enter the definition's recovery/backoff branch. An uncertain external outcome instead creates a reconciliation hold. Do not equate a transport exception with proof that the remote action did not occur. Automatic activities cannot be manually completed to skip their work.

Worker and storage

applications/main/src/jobs/step-execution-job.ts exposes the scheduler assembled by application composition. platform/runtime/src/application-scheduler.ts polls, skips terminal/held/human-waiting work, bounds advances, and isolates each process's errors. Its in-process busy guard prevents overlapping ticks; durable claims and revision checks protect effect occurrences across contenders.

The scheduler still scans stored aggregates rather than using an indexed work queue. Keep the supported deployment topology conservative—normally one worker per shared store—until the actual storage/lease and crash-recovery policy is verified. See storage and deployment bindings.

Outcomes and projections

The machine distinguishes success, failure and pending execution. The public compatibility DTO still uses running/completed plus error; records derive failure from the error. A hold is surfaced as attention required, not a successful completion. Stored machine state and public presentation are deliberately different contracts.

Where each stage is driven from

StageDriver
StartPOST /api/process through the application service
EditPUT /api/process/{id}/steps/{stepId}
Complete an interactionPOST /api/process/{id}/steps/{stepId}/complete
Automatic effects and waitsExplicit worker entrypoint
Abandon/reopen/sharingAuthorized application-service commands

Use npm run dev:all when local runs need both the web app and worker. The standalone API does not silently launch a polling worker.


Known gaps

Transparent reconciliation, bounded product retry policies, retention/compaction and parallel join semantics remain follow-up work. Synthetic persistence and concurrency tests do not establish production hosting or live-provider guarantees.