using System.Globalization; namespace w4c_workflows.Services.Execution; /// /// A task.result event as consumed by the run lifecycle engine. The /// worker publishes these via ; this /// record is the control-plane parse of the same flat field names. /// public sealed record TaskResult( string RunId, string TaskId, int Attempt, string TenantId, bool Success, int ExitCode, string? Output, string? Error, long DurationMs) { /// Parses a stream message into a result, throwing if a required field is missing. public static TaskResult FromFields(IReadOnlyDictionary fields) { static string Get(IReadOnlyDictionary fields, string key) => fields.TryGetValue(key, out var value) && !string.IsNullOrEmpty(value) ? value : throw new InvalidOperationException($"missing required result field '{key}'"); static int GetInt(IReadOnlyDictionary fields, string key, int fallback) => fields.TryGetValue(key, out var raw) && int.TryParse(raw, out var n) ? n : fallback; static long GetLong(IReadOnlyDictionary fields, string key, long fallback) => fields.TryGetValue(key, out var raw) && long.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out var n) ? n : fallback; var status = Get(fields, "status"); return new TaskResult( Get(fields, "run_id"), Get(fields, "task_id"), GetInt(fields, "attempt", 1), Get(fields, "tenant_id"), string.Equals(status, "succeeded", StringComparison.Ordinal), GetInt(fields, "exit_code", -1), fields.GetValueOrDefault("output"), fields.GetValueOrDefault("error"), GetLong(fields, "duration_ms", 0)); } }