feat(central-ui): FlowDebugService relays Retry/Discard for a parked outbound step

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
This commit is contained in:
Joseph Doherty
2026-09-06 11:04:03 -04:00
parent 9c31f70105
commit 2025ec346f
3 changed files with 363 additions and 3 deletions
@@ -23,6 +23,16 @@ public sealed record FlowDebugOutcome(FlowGraph? Graph, FlowDebugRunResult? Raw,
public static FlowDebugOutcome Fail(string error, string errorCode) => new(null, null, error, errorCode);
}
/// <summary>
/// Outcome of a Retry / Discard relayed from a Flow Debugger node (follow-ups plan 2026-09-06 D4).
/// <see cref="Message"/> is operator-facing and uses the same wording as the Site Calls /
/// Notification report pages, whether the relay was refused before it left the page or the
/// owning site / outbox answered.
/// </summary>
/// <param name="Success">True when the relay was applied (site <c>Applied</c>, or outbox success).</param>
/// <param name="Message">What happened, in the report pages' words.</param>
public sealed record FlowOutboundActionResult(bool Success, string Message);
/// <summary>
/// CentralUI facade over the Flow Debugger (design 2026-09-05 §5.5/§7.1): static shape
/// prediction from script syntax, and the three management commands (Live run of a method,
@@ -66,4 +76,24 @@ public interface IFlowDebugService
/// <param name="executionId">Any execution id in the chain.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<FlowDebugOutcome> ReplayAsync(Guid executionId, CancellationToken cancellationToken = default);
/// <summary>
/// Relays a Retry of a parked outbound node to its owner — the Site Call Audit relay for an
/// <see cref="FlowStepKind.ApiCall"/> / <see cref="FlowStepKind.DbCall"/> (keyed by the step's
/// <see cref="FlowStep.CorrelationId"/> = <c>TrackedOperationId</c> and <see cref="FlowStep.SiteId"/>),
/// the Notification Outbox for a <see cref="FlowStepKind.Notify"/> (<c>CorrelationId</c> =
/// <c>NotificationId</c>). A step that is not outbound, not <see cref="FlowStepOutcome.Parked"/>,
/// has no correlation id, or (site kinds) no site id is refused with a message and never relayed.
/// </summary>
/// <param name="step">The outbound step to retry.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<FlowOutboundActionResult> RetryOutboundAsync(FlowStep step, CancellationToken cancellationToken = default);
/// <summary>
/// Relays a Discard of a parked outbound node to its owner. Same routing and refusals as
/// <see cref="RetryOutboundAsync"/>.
/// </summary>
/// <param name="step">The outbound step to discard.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<FlowOutboundActionResult> DiscardOutboundAsync(FlowStep step, CancellationToken cancellationToken = default);
}