ghostAPIv1 beta
Guides

Finish a run whose delivery failed

When every analysis card in a failed full run completed and only a delivery card did not, finish the run from its recorded result instead of running it again.

A delivery card is a notify card or an action card whose output no analysis card reads. Its failure no longer fails a full run: the completed analysis can still update the tracker and proceed through the usual sync, quality-check and delivery steps. The Output tab shows the unfinished card amber with its reason. workflows.state shows it with status error, and its deliveries include a line with channel card naming it. An action required by later analysis can still fail the run. A run may also remain failed from before this change, or because it was stopped while a delivery card was running. A failed run does not update the tracker, sync the sheet or send the standing delivery, even when its result is already recorded and readable through workflows.artifact. workflows.finalize_run completes a qualifying failed run from that result without rerunning analysis. A run stopped before its result was recorded has nothing to finalize and is refused; use workflows.resume instead.

Workflow agents run unattended and cannot use external write tools that need approval. Open delivery cards that need those tools are marked as not run. Ghost delivers eligible email notify cards and configured standing copies itself. Email cards may mail the stored email.addresses from workflows.set_delivery, even while email.enabled is false, and the author's own address while they remain a workspace member. Named unapproved addresses are refused, never replaced with someone else. A card naming nobody uses enabled standing recipients when there are any, otherwise the author. Approval is rechecked before sending, and standing and card recipients are deduplicated without regard to case. Turning standing email off does not revoke saved-list approval; remove an address from the list to revoke that approval. Report review holds email and Slack copies, including email-card recipients; sheet and context-document updates are not held for review.

When a run qualifies

  • It is a full run at full fidelity and its status is failed.
  • Every analysis card it ran completed. Only delivery cards (notify cards, and action cards no analysis card reads) did not finish.
  • It has a recorded, non-empty result.
  • It is the workflow's latest finished full run. Finishing an older one would write its rows and report over newer ones.
  • You are the workflow's author or a workspace admin, and the key has workflows:run.

A run that does not qualify is refused with 400 before anything is queued, and the message says why. A run with an unfinished analysis card needs workflows.resume or a new run instead.

Preview, then confirm

Submit workflows.finalize_run through POST /operations without confirm. Nothing is written or sent. The receipt finishes as needs_review; its result lists the delivery cards that will be set aside, whether the tracker and sheet will update, and who receives the standing delivery. An email card that did not finish is set aside too, and the addresses it was going to mail are added to that delivery, one email per address. An address the workflow's author never approved is not mailed.

{
  "operation": "workflows.finalize_run",
  "arguments": {
    "workflowId": "11111111-1111-4111-8111-111111111111",
    "runId": "22222222-2222-4222-8222-222222222222"
  },
  "reason": "Check whether Monday's failed run can be finished from its recorded result."
}

Show that preview to the user. After they approve, submit again with confirm set to true, a fresh Idempotency-Key, and their approving words quoted verbatim in user_said and included in reason. The words must name the send or the delivery; a bare go-ahead is not enough, because this call delivers outward. Finalizing cannot exclude any listed recipient, so a go-ahead that narrows the audience is refused.

{
  "operation": "workflows.finalize_run",
  "arguments": {
    "workflowId": "11111111-1111-4111-8111-111111111111",
    "runId": "22222222-2222-4222-8222-222222222222",
    "confirm": true,
    "user_said": "Yes, finalize it and send the delivery"
  },
  "reason": "Yes, finalize it and send the delivery"
}

Poll the receipt. A newly finalized result has status finalized, the delivery cards that were set aside, the tracker change when recorded, and delivered entries for standing copies and recorded sync outcomes. Check error on each sync entry. The run reads complete and its log records finalization from the saved result. A set-aside email card's sent true means at least one approved recipient was mailed, not that every recipient was mailed; inspect failedSends for partial failures. That card reads complete. An email card held for review also stays complete, and its finalization result reports sent false; Accept delivers it later. Other set-aside cards remain error, drawn amber with the reason they did not finish.

Respect holds first, even when deliveryFailed is also true. heldForReview means the report and its email-card recipients wait for a reviewer. heldByQa means the pre-send check held the report for the reason in the run log. Do not send the report another way under either hold. Otherwise, deliveryFailed means some finalization or delivery work did not finish, including artifact preparation or recipient checks; it does not establish that a particular email was unsent. Read delivered, failedSends and the run log before retrying any destination. Finalizing again does nothing. Retry only a destination confirmed not sent, and respect any review or QA hold.

Finalizing is safe to repeat. Only one call can move a run from failed to complete and attempt its finalization work; a later call returns already_complete and sends nothing. If a receipt ends outcome_unknown, read workflows.state for the run's status and deliveries before submitting again.