diff --git a/Docs/durable-execution-design.md b/Docs/durable-execution-design.md
index 6df424c5f..402d689af 100644
--- a/Docs/durable-execution-design.md
+++ b/Docs/durable-execution-design.md
@@ -1279,10 +1279,9 @@ public class CallbackConfig
///
public TimeSpan HeartbeatTimeout { get; set; } = TimeSpan.Zero;
- ///
- /// Custom serializer for callback result.
- ///
- public ICheckpointSerializer? Serializer { get; set; }
+ // Note: there is no Serializer property here. Custom serializers are
+ // supplied via the AOT-safe CreateCallbackAsync(..., ICheckpointSerializer, ...)
+ // overload, matching the pattern established by StepAsync.
}
///
@@ -1307,14 +1306,14 @@ public class InvokeConfig
public TimeSpan Timeout { get; set; } = TimeSpan.Zero;
///
- /// Custom serializer for the payload.
+ /// Optional tenant identifier propagated to the chained invocation.
+ /// Matches the tenantId field on Python/JS/Java InvokeConfig.
///
- public ICheckpointSerializer? PayloadSerializer { get; set; }
+ public string? TenantId { get; set; }
- ///
- /// Custom serializer for the result.
- ///
- public ICheckpointSerializer? ResultSerializer { get; set; }
+ // Note: payload and result serializers are supplied via the AOT-safe
+ // InvokeAsync(..., ICheckpointSerializer, ICheckpointSerializer, ...)
+ // overload, matching the pattern established by StepAsync.
}
///
@@ -1429,10 +1428,9 @@ public class CompletionConfig
///
public class ChildContextConfig
{
- ///
- /// Custom serializer for the child context's return value.
- ///
- public ICheckpointSerializer? Serializer { get; set; }
+ // Note: there is no Serializer property here. Custom serializers are
+ // supplied via the AOT-safe RunInChildContextAsync(..., ICheckpointSerializer, ...)
+ // overload, matching the pattern established by StepAsync.
///
/// Operation sub-type label for observability (e.g., in test runner output).
@@ -1473,34 +1471,54 @@ public class WaitForConditionConfig
public interface IBatchResult
{
///
- /// All items (succeeded and failed).
+ /// All items, in original index order.
///
IReadOnlyList> All { get; }
///
- /// Only successful items.
+ /// Items whose Status is Succeeded.
///
IReadOnlyList> Succeeded { get; }
///
- /// Only failed items.
+ /// Items whose Status is Failed.
///
IReadOnlyList> Failed { get; }
///
- /// Get all successful results. Throws if any failed.
+ /// Items still in flight when the batch resolved (CompletionConfig short-circuit).
+ ///
+ IReadOnlyList> Started { get; }
+
+ ///
+ /// Get all successful results in original index order. Throws if any failed.
///
IReadOnlyList GetResults();
///
- /// Throw an exception if any item failed.
+ /// Get all errors from failed items.
+ ///
+ IReadOnlyList GetErrors();
+
+ ///
+ /// Throw a single aggregated exception if any item failed.
///
void ThrowIfError();
///
- /// Why the operation completed.
+ /// True if any item is in the Failed state.
+ ///
+ bool HasFailure { get; }
+
+ ///
+ /// Why the batch resolved.
///
CompletionReason CompletionReason { get; }
+
+ int SuccessCount { get; }
+ int FailureCount { get; }
+ int StartedCount { get; }
+ int TotalCount { get; }
}
public interface IBatchItem
@@ -1511,7 +1529,29 @@ public interface IBatchItem
DurableExecutionException? Error { get; }
}
-public enum BatchItemStatus { Succeeded, Failed, Cancelled }
+///
+/// Status of an individual item in a batch result.
+/// Mirrors the wire-state observed at the time the batch resolved — items still
+/// running when a CompletionConfig short-circuits remain in .
+///
+public enum BatchItemStatus
+{
+ ///
+ /// The branch ran to completion and produced a result.
+ ///
+ Succeeded,
+
+ ///
+ /// The branch ran to completion and threw.
+ ///
+ Failed,
+
+ ///
+ /// The branch was still in flight when the batch's CompletionConfig
+ /// resolved (e.g., FirstSuccessful returned before this branch finished).
+ ///
+ Started
+}
public enum CompletionReason { AllCompleted, MinSuccessfulReached, FailureToleranceExceeded }
///
diff --git a/Libraries/src/Amazon.Lambda.DurableExecution/Internal/Operation.cs b/Libraries/src/Amazon.Lambda.DurableExecution/Internal/Operation.cs
index 473c7a3b2..3befbf7d8 100644
--- a/Libraries/src/Amazon.Lambda.DurableExecution/Internal/Operation.cs
+++ b/Libraries/src/Amazon.Lambda.DurableExecution/Internal/Operation.cs
@@ -137,4 +137,25 @@ internal static class OperationStatuses
public const string Cancelled = "CANCELLED";
public const string Ready = "READY";
public const string Stopped = "STOPPED";
+ public const string TimedOut = "TIMED_OUT";
+}
+
+///
+/// Wire-format string constants. Subtypes are
+/// observability labels mapped from the user-facing context method that
+/// produced the operation. The service does not interpret them; downstream
+/// consumers (test runner, traces, console) display them as-is.
+///
+internal static class OperationSubTypes
+{
+ public const string Step = "Step";
+ public const string Wait = "Wait";
+ public const string Callback = "Callback";
+ public const string WaitForCallback = "WaitForCallback";
+ public const string Invoke = "Invoke";
+ public const string WaitForCondition = "WaitForCondition";
+ public const string Parallel = "Parallel";
+ public const string ParallelBranch = "ParallelBranch";
+ public const string Map = "Map";
+ public const string MapIteration = "MapIteration";
}
diff --git a/Libraries/src/Amazon.Lambda.DurableExecution/Internal/StepOperation.cs b/Libraries/src/Amazon.Lambda.DurableExecution/Internal/StepOperation.cs
index 54e52005d..2a0182d7e 100644
--- a/Libraries/src/Amazon.Lambda.DurableExecution/Internal/StepOperation.cs
+++ b/Libraries/src/Amazon.Lambda.DurableExecution/Internal/StepOperation.cs
@@ -171,7 +171,7 @@ private async Task ExecuteFunc(int attemptNumber, CancellationToken cancellat
Id = OperationId,
Type = OperationTypes.Step,
Action = "START",
- SubType = "Step",
+ SubType = OperationSubTypes.Step,
Name = Name
};
@@ -196,7 +196,7 @@ await EnqueueAsync(new SdkOperationUpdate
Id = OperationId,
Type = OperationTypes.Step,
Action = "SUCCEED",
- SubType = "Step",
+ SubType = OperationSubTypes.Step,
Name = Name,
Payload = SerializeResult(result)
}, cancellationToken);
@@ -233,7 +233,7 @@ await EnqueueAsync(new SdkOperationUpdate
Id = OperationId,
Type = OperationTypes.Step,
Action = "RETRY",
- SubType = "Step",
+ SubType = OperationSubTypes.Step,
Name = Name,
Error = ToSdkError(ex),
StepOptions = new SdkStepOptions { NextAttemptDelaySeconds = delaySeconds }
@@ -248,7 +248,7 @@ await EnqueueAsync(new SdkOperationUpdate
Id = OperationId,
Type = OperationTypes.Step,
Action = "FAIL",
- SubType = "Step",
+ SubType = OperationSubTypes.Step,
Name = Name,
Error = ToSdkError(ex)
}, cancellationToken);
diff --git a/Libraries/src/Amazon.Lambda.DurableExecution/Internal/WaitOperation.cs b/Libraries/src/Amazon.Lambda.DurableExecution/Internal/WaitOperation.cs
index 59254827d..364ab05c3 100644
--- a/Libraries/src/Amazon.Lambda.DurableExecution/Internal/WaitOperation.cs
+++ b/Libraries/src/Amazon.Lambda.DurableExecution/Internal/WaitOperation.cs
@@ -48,7 +48,7 @@ await EnqueueAsync(new SdkOperationUpdate
Id = OperationId,
Type = OperationTypes.Wait,
Action = "START",
- SubType = "Wait",
+ SubType = OperationSubTypes.Wait,
Name = Name,
WaitOptions = new SdkWaitOptions { WaitSeconds = _waitSeconds }
}, cancellationToken);