Release v0.0.68
Overviewβ
This release introduces four new capabilities and a substantial subflow stability hardening set. Workflow output mapping lets a flow declare an output script whose result is returned directly as the HTTP response body β with the script's status code and headers β on synchronous start/transition calls (#785, #790). Free-form payload support allows instance start and transition endpoints to accept arbitrary JSON bodies without the standard attributes envelope, resolved automatically or via the x-vnext-payload-mode header (#785, #788). A new built-in StateStore task (TaskType = 17) brings a caching primitive to the workflow pipeline on top of Dapr state stores, with get / set / delete commands, TTL, and optimistic concurrency (#792). Transition history now snapshots the externally visible state per transition: effectiveState, effectiveStateType, effectiveStateSubType, and stage (#793). Five fixes eliminate an entire class of stuck-subflow scenarios in deep and synchronous subflow chains (#784, #787, #789, #791, #794). This release runs on component schema 0.0.49.
Featuresβ
Workflow output mapping for sync responses (#785, #790)β
A workflow can now declare an optional output script (standard scriptCode object, implementing IOutputHandler) at the attributes level. When an instance is started or transitioned with sync=true and the flow has an output script, the script's mapped result is returned directly as the HTTP response body β together with the script's statusCode and headers β instead of the standard StartInstanceOutput / TransitionOutput envelope. This mirrors the existing Function endpoint behavior and lets a flow shape its own API contract.
{
"attributes": {
"type": "F",
"output": {
"type": "L",
"code": "<base64-encoded IOutputHandler script>",
"encoding": "B64"
}
// ... states, startTransition, labels ...
}
}
Behavior details:
- The direct-response bypass applies only when the output script actually ran β an output may intentionally return an empty body with its own status code and headers.
- Subflow instances are excluded:
/sub/instances/startand subflow transitions keep the standard envelope, since parent/child correlation relies on it. - If the output script fails, the platform logs the error and falls back to the standard response β output mapping is never allowed to break the request.
- With
sync=falsethe response is unchanged ({ id, status }).
Reference: issues #785, #790 β see also Workflow component β Output Mapping and Async / Sync.
Free-form payload on instance start and transition (#785, #788)β
The instance start and transition endpoints now accept free-form JSON bodies. A body without a top-level attributes key is automatically normalized into the standard shape β {"customer_id":"123"} becomes {"attributes":{"customer_id":"123"}} β so external callers no longer need to know the platform envelope.
Payload mode is resolved per request:
| Signal | Effect |
|---|---|
x-vnext-payload-mode: raw header | Body is treated as free-form even if it contains a top-level attributes key |
x-vnext-payload-mode: standard header | Body is treated as the standard DTO even if it has no attributes key |
| No header | Presence of a top-level attributes key selects standard mode; otherwise free-form |
A follow-up fix (#788) ensures camelCase keys (key, stage, attributes) in standard-mode bodies bind correctly by using web-compatible JSON serializer options.
Reference: issues #785, #788 β see also REST API β Instance Endpoints.
StateStore task β caching primitive for the pipeline (#792)β
A new built-in task type, StateStore (TaskType = 17), reads and writes a Dapr state store component from the workflow/function pipeline. It is the caching primitive for flows, supporting three commands that mirror the Dapr state API verbs:
| Command | Behavior |
|---|---|
get | Read the value for key; a cache miss returns success with data = null and Found = false |
set | Write/update key with value, with optional ttlInSeconds and ETag-based optimistic concurrency |
delete | Delete a single key, a bulk keys[] list, or keys matched by a Dapr state Query API query |
{
"key": "cache-customer-profile",
"version": "1.0.0",
"domain": "core",
"flow": "sys-tasks",
"flowVersion": "1.0.0",
"tags": ["cache"],
"attributes": {
"type": "17",
"config": {
"command": "set",
"key": "customer:42:profile",
"value": { "name": "Ada" },
"ttlInSeconds": 300,
"consistency": "Strong",
"concurrency": "LastWrite"
}
}
}
- When
storeNameis omitted, the executing runtime'sDAPR_STATE_STORE_NAMEconfiguration value is used (vnext-statein the shipped environments). - Every task-supplied key is stored under the fixed
custom:prefix to prevent collisions with engine-owned cache entries. concurrency(FirstWrite/LastWrite) andconsistency(Eventual/Strong) map to the corresponding Dapr state options.
Reference: issue #792 β see also the new StateStore Task component page.
Effective state snapshot in transition history (#793)β
Each completed transition record now captures the externally visible state of the instance at completion time: effectiveState, effectiveStateType, effectiveStateSubType, and the caller-set stage. The values are snapshotted when the transition pipeline finalizes, pairing them with toState, and are returned by the transition history endpoint:
GET /api/v1/{domain}/workflows/{workflow}/instances/{instance}/transitions
Failed or incomplete transitions keep the fields null, consistent with toState. Historical rows are not backfilled and stay null.
Reference: issue #793 β see also REST API β Instance Endpoints.
Fixesβ
Prevent sync parents getting stuck Busy in subflow chains (#794)β
A parent instance started with sync=true could remain stuck in Busy forever when its chain contained multiple blocking subflows. Two independent root causes were fixed: the subflow resume lock key is now scoped per completing sub-instance ({lockKey}:resume:{subInstanceId}), making self-collision across nesting levels structurally impossible, and the correlation revert path now reloads the parent with all correlations (including completed ones) instead of silently no-op'ing. A missing revert target now emits an explicit error log (SubFlowCorrelationRevertTargetMissing, EventId 40119).
Reference: issue #794
Propagate sync caller mode through subflow completion/fault resume (#791)β
A sync=true start/transition behaved like sync=false after the first subflow completed: the parent resume context was rebuilt with a hardcoded async caller mode, so subsequent subflow starts in the resumed chain were enqueued as background jobs and the API returned Busy before the chain settled. The completing pipeline's caller mode is now carried end-to-end through the subflow completion/fault callback chain, keeping sync chains inline. Retry paths deliberately force async so workers are never blocked.
Reference: issue #791
Fix deep-subflow stalls: job-name collision + fault on load failure (#787)β
Two root causes could strand deep subflow chains (6β8 levels). First, the Dapr job name for async/scheduled transitions only contained the instance ID and transition key β two same-named transitions on different states minted identical names, and Dapr's dedup silently dropped one. The source state is now part of the job name, and scheduled-job cancellation matches on source state + transition key (also fixing a latent over-cancellation bug). Second, when the parent workflow definition failed to load during subflow completion, the chain was stranded silently; the parent now faults with an incident so the error propagates upward.
Reference: issue #787
Keep readable dotted job names Dapr-safe (#789)β
Follow-up to #787: the source-state scoping is expressed as a plain dotted field β vnext.job.v1.{type}.{id}.{sourceState}.{transitionKey} β removing the ~ marker and U+001F composite separator that forced Base64Url encoding and broke Dapr routing. State/transition keys are validated to a Dapr-safe alphabet and fail fast with a clear exception otherwise. Legacy single-field names still parse.
Reference: issue #789
Pass workflow scripts to subflow input mapping compilation (#784)β
Helpers declared in workflow.scripts.helpers were unavailable inside a subflow/subprocess InputHandler because the parent workflow's flow-level script settings were not forwarded to input mapping compilation. Output mapping already passed them; input mapping is now at parity.
Reference: issue #784
Configuration Updatesβ
Configuration for v0.0.68:
{
"runtimeVersion": "0.0.68",
"schemaVersion": "0.0.49"
}
Note: Schema version advances to 0.0.49 (from
0.0.48). The bump adds the workflowattributes.outputdefinition (#785) and the StateStore task type"17"(#792). Update@burgan-tech/vnext-schemain your domain project before validating against this runtime.
Container images: published at tag 0.0.68 under ghcr.io/burgan-tech/vnext/*, Cosign-signed (keyless OIDC) with SBOM + provenance. Immutable digests are listed in the GitHub release.
Issues Referencedβ
- vnext #785 β Workflow
outputmodel for sync responses and free-form payload support. - vnext #790 β Return workflow output mapping directly as the sync HTTP response.
- vnext #788 β Bind camelCase payload keys in start/transition endpoints.
- vnext #792 β StateStore task type for Dapr state store caching.
- vnext #793 β Capture effective state snapshot in transition history.
- vnext #794 β Prevent
sync=trueparents getting stuck Busy: per-sub resume lock key + correlation revert fix. - vnext #791 β Propagate sync caller mode through subflow completion/fault resume.
- vnext #787 β Prevent deep-subflow stalls: job-name collision fix + fault on load failure.
- vnext #789 β Keep readable dotted job names Dapr-safe.
- vnext #784 β Pass workflow scripts to subflow input mapping compilation.
Summaryβ
- Workflow output mapping: declare
attributes.output(IOutputHandler) andsync=trueresponses return the mapped payload directly β body, status code, and headers β like Function endpoints; subflows keep the standard envelope. - Free-form payloads: start/transition bodies no longer need the
attributesenvelope; mode resolved automatically or viax-vnext-payload-mode: raw|standard. - StateStore task (Type 17):
get/set/deleteagainst a Dapr state store with TTL, ETag, concurrency/consistency modes; task keys namespaced undercustom:. - Transition history now returns
effectiveState,effectiveStateType,effectiveStateSubType, andstageper completed transition. - Subflow stability: five fixes remove stuck-
Busyscenarios in deep and synchronous subflow chains (resume lock scoping, sync mode propagation, job-name collisions, silent load-failure stranding, input-mapping helper parity). - Schema is 0.0.49.
vNext Runtime Platform Team Released July 2, 2026
