brain/wiki/flows-execution/flow-runs.md
A Flow Run records one execution of a specific flow version, from trigger to terminal state. It stores compressed step-by-step logs, supports pause/resume for delay and webhook waits, offers retry strategies, and emits WebSocket + application events for real-time UI.
{name, displayName, message?}), timeline (JSONB), archivedAt (soft delete).type (DELAY|WEBHOOK), version (V0|V1), status (PENDING|COMPLETED), unique on (flow_run_id, step_name).GET / (cursor paginated by composite (created DESC, id DESC), filters incl. failedStepMessage ILIKE), GET /:id, POST /:id/retry, POST /retry|cancel|archive (bulk), waitpoint resume routes.FROM_FAILED_STEP (rebuild context from logs, re-run from failure, prior outputs kept) or ON_LATEST_VERSION (fresh run on current published version). Both resolve the trigger payload via resolveStepOutput. If the trigger itself failed, they switch to executeTrigger: true to reprocess the raw event.createWaitpoint + waitForWaitpoint. DELAY upserts a RESUME_DELAY_WAITPOINT BullMQ job; WEBHOOK resumes on an HTTP call to /:id/waitpoints/:waitpointId[/sync].flow-run-module.ts registers a BullMQ system job (cron 50 23 * * *, once daily at 23:50 UTC) that aggregates the day's run counts by (projectId, flowId, environment) in one transaction (5-minute statement timeout) and emits a FLOW_RUN_CREATED telemetry event per group. No-op when telemetry is disabled. The cron was 0/50 23 * * * until GIT-1632, which also fired at 23:00 with partial counts.UPDATE flow_run SET status = 'CANCELED', "finishTime" = NOW(), updated = NOW() WHERE id = '<run id>' AND status = 'RUNNING'; (run id = last path segment of the run URL), then "Retry on latest version" replays the original payload./confirm route serves an HTML Approve/Disapprove page on GET/HEAD (never consumes) and only resumes on POST — stops email security scanners (Safe Links, Mimecast, Proofpoint) prefetching approval links. The deprecated bare GET /:id/waitpoints/:waitpointId still resumes for old emails. Slack is unchanged (server-side POST from webhook).markParentRunAsFailed scopes its parent lookup to { id: parentRunId, projectId } using the child run's authenticated projectId. parentRunId/failParentOnFailure arrive from spoofable webhook headers (ap-parent-run-id/ap-fail-parent-on-failure) on the public webhook endpoint, so without the scope a failed child in project A could complete a paused parent's waitpoint and resume it in project B. A cross-project parent id now matches nothing and the fail is a no-op; legitimate subflows are always same-project (Call Flow only targets flows in the caller's project).WAITPOINT|RETRY) discriminates whether FAILED steps are restored on resume: waitpoint resumes preserve them, retry resumes drop them so the failed step re-executes.buildFailedTriggerContext writes it into the trigger step's output slot.payload field was tried and removed as redundant). FAILED means "output holds a raw event, re-run run() on it" (executeTrigger: true); SUCCEEDED means "output is already the trigger's result, replay as-is" (executeTrigger: false). So any code that fabricates a trigger step without the engine having run — the QUOTA_EXCEEDED admission gate is the first — must pick the status from where its payload came: raw for sync webhooks, extracted for anything sourced from the worker RPC submitPayloads (which passes post-TriggerHookType.RUN output). Get it wrong on a polling trigger and retry re-polls against an already-advanced lastPoll cursor, so the run gets undefined or an unrelated newer item and silently consumes those fresh items' own runs.LogSliceRef pointer to a FLOW_RUN_LOG_SLICE file (outputType === SLICE); missing backing file throws ENTITY_NOT_FOUND (loud retry failure). Step inputs over 2 KB (AP_FLOW_RUN_LOG_INPUT_TRUNCATE_THRESHOLD_KB) become a display-only truncation placeholder.EXECUTION_DATA_RETENTION_DAYS.onFinish does two tryCatch-wrapped billing steps that never break run completion. (1) A PRODUCTION run not in QUOTA_EXCEEDED charges +1 apCredit via billingProvider.trackCredits with idempotency key {runId}:run. (2) flowRunAiUsageTracker pre-scans the flow version for @activepieces/piece-ai steps, extracts per-provider/model usage from step outputs (flow-run-ai-usage-extractor — recurses into loops, fetches FLOW_RUN_LOG_SLICE files, falls back to flow-version settings on **REDACTED** models), meters Σ(messages × model credit weight) + toolCalls to Autumn ({runId}:ai, plus {runId}:appSumoAi for the managed-ACTIVEPIECES AppSumo cap), then emits the AI_USAGE_PER_RUN PostHog event — the license key is only the PostHog distinctId, no longer a gate on metering.submitPayloads checks shouldBlockOnCredits (blocks only when the platform is billingEnforced AND the cached balance is exhausted; CE default and Autumn-outage behavior is false). A blocked run is still admitted — as a QUOTA_EXCEEDED run with the trigger payload persisted in its log — so it stays retryable once credits return instead of being dropped. AP_EDITION=ee skips the gate entirely (shouldBlockRunOnCredits returns false before any provider call) so self-hosters pay no Redis/Autumn latency on admission — a temporary measure, see decision 000020.onFinish, so a long run can spend past the credit limit before anything lands; interim by design — see decision 000016.CE has full run tracking. Cloud may enforce retention windows; bulk-retry admin endpoint is Cloud-only.
Entry point: flowRunService, defined in flow-run-service.ts and wired through flow-run-module.ts.
packages/server/api/src/app/flows/flow-run/ — controller, service, entity, hooks, side effects, runs queue, AI usage extractor/trackerpackages/server/api/src/app/flows/flow-run/waitpoint/ — resume routes, the /confirm page, and its theme hookspackages/core/execution/src/lib/flow-run/ — FlowRun type, request dtos, execution types (StepOutput, FlowExecution), zstd log serializerpackages/server/engine/src/lib/helper/logging-utils.ts — produces the truncated-input placeholder the web run-details tab detectspackages/server/api/src/app/ee/billing-usage-report/ — daily EE job emitting per-platform run counts to PostHog (TOTAL_RUNS_PER_DAY, captured and flushed in platform batches)packages/web/src/features/flow-runs/ — flowRunsApi, run query/mutation hooks, runs table and its dialogspackages/web/src/app/routes/runs/ — runs list and run detail pagespackages/web/src/app/builder/run-details/ — step input/output inspector inside the builderpackages/web/src/app/builder/run-list/ — recent runs sidebar in the builderpackages/web/src/app/builder/state/ — run state and canvas state, including live-follow controlPaths verified 2026-07-26. An earlier version pointed at packages/core/shared/src/lib/automation/flow-run/ (moved to packages/core/execution/src/lib/flow-run/) and packages/server/api/src/app/ee/flow-run-tracking/ (renamed to packages/server/api/src/app/ee/billing-usage-report/).