Why "saved" isn"t "ran": designing an execution log
A workflow tool tells its users two different things every day, and most tools blur them into the same green checkmark: the configuration was saved and the run actually finished. They are not the same event. The space be
A workflow tool tells its users two different things every day, and most tools blur them into the same green checkmark: the configuration was saved and the run actually finished. They are not the same event. The space between them is where trust quietly disappears.
The complaint is familiar: "It said it worked, but it didn't." Usually the AI part is fine. What failed is the state model β the product reported a saved document as if it were a completed execution, so nobody could answer the only question that matters afterwards: what ran, in what order, with what input, and what came out?
Here is the set of decisions that helped us keep those two ideas apart.
1. Separate the two lifecycles
A workflow is a document. A run is an event. Saving validates structure: the graph is connected, required fields are filled, references resolve. None of that says anything about whether the thing will work at runtime, and a product that presents "saved" as the primary status is quietly promising runtime success it has not observed.
Keep a separate, timestamped last-run status next to the document. If there has never been a run, say so instead of showing nothing.
2. Record the run, not just the outcome
A final "success" is a summary, and summaries hide everything useful. For each run, store:
- run id, trigger source (manual, schedule, incoming event), start and end time, terminal status
- one entry per executed node: node id, attempt count, duration, status, error code
- a reference to the input and output payloads
For payloads, digests and sizes are a good default: they keep storage bounded and keep credentials out of the log. Keep full payloads opt-in, and redact known secret fields on the way in rather than on display.
3. Empty is a result, not a failure
"Zero rows matched" and "the node threw an exception" are different facts. If empty output is mapped to failure, retries pile up around a condition that was actually correct, and users learn to ignore the alerts.
4. Retries belong to the same run
Record attempts under one run id. If each retry opens a new run, one flaky HTTP call looks like three runs, durations become meaningless, and any dashboard built on top of the log is wrong by construction.
5. Skipped branches should be visible
In conditional workflows, a node that did not execute is still information. Record "skipped" with the reason. Otherwise the timeline looks truncated and people assume data was lost.
6. Make the log the first thing shown after a run
Not a settings tab, not a secondary page: the run view should open on completion, failures sorted first with their error code, then the rest. The log is the product's answer to "did it work", so it deserves the default slot.
7. State retention explicitly
Say how long runs are kept and offer an export. Silent truncation is worse than a short window, because it removes evidence exactly when someone goes looking for it.
A short checklist
- run id, trigger, start, end, terminal status
- per-node status including skipped and attempt count
- error code kept separate from error message text
- input/output digest by default, full payload on request
- a retention policy the user can read
None of this is specific to AI. It is ordinary execution modelling, applied to a class of tools that move fast enough to forget it.
If you want to see how this looks in practice, we build BeeAI, a desktop client where AI chat, a visual workflow canvas and tool connections share one workspace β including the execution log described above.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.