Core Philosophy
Vyuh Workflows separates orchestration, side effects, history, and storage. The executable source is a Dart function or a constrained JSON document. The runtime never stores a Dart stack frame.
Replay, Not Tokens
A run is history plus the current command projection. After every durable fact the runtime invokes the same versioned workflow from its entry point:
Completed awaits return recorded results. Unresolved awaits emit a command and mark the run blocked. running means a new fact is ready to reduce, not that a Dart isolate is parked.
Side Effects Belong in Activities
Workflow code may use if, switch, and loops over recorded values. It must not:
- call a network or database;
- read the wall clock or generate randomness;
- mutate globals;
- use
Future.waitor unregistered futures.
Those belong in versioned ActivityHandlers that receive a stable idempotencyKey. Human work is a userTask. External events are signals. Time is sleep.
One Vocabulary, Two Authoring Surfaces
| Concept | Dart | JSON | Runtime record |
|---|---|---|---|
| Identity | WorkflowRef(code, version) | code + version | version plus run |
| Automated work | flow.serviceTask | serviceTask | activity command |
| Assigned work | flow.userTask | userTask | user-task command |
| External event | flow.waitForSignal | signal | signal history |
| Time | flow.sleep | timer | timer command |
| Branch / loop | Dart control flow | switch, joins | replay decisions |
JSON compiles to an executable definition. Arbitrary Dart cannot be converted losslessly back into a graph.
Identity Is Immutable
code + version is the public identity. The fingerprint/digest is an integrity check. A run stores all three. Changing behavior requires a new version. Workers refuse to replay history against a different digest.
Storage Is the Coordinator
Correctness comes from:
- append-only history;
- unique
(run, operationKey, attempt)commands; - optimistic run revisions;
- leases and claim-generation fencing;
- atomic join and continue-as-new transactions.
Process affinity is not a correctness mechanism. API, decider, activity, and recovery roles can share a process or run separately.
Products Talk to the Service
Product Flutter apps and product APIs do not embed deciders or hold a service-role key. They call vyuh_workflow_service. cdx_feature_workflows renders inbox state. cdx_workflow_templates supplies the canonical approval definition.
The graph LegacyWorkflowEngine remains only so existing ELOG and DocsIQ runs can finish on the engine that started them.