What a schedule's row keeps of its last run: the moment the firing that started
it came due, one of four outcomes, the runner's own message, and how long the
run took. Nothing before it — there is no run history, and a skipped firing
leaves no trace — because the node is a script runner, not a reliable
scheduler. What a script produces goes where the script puts it; anything it
wants kept beyond one line, it writes to the notebook. A watch's firing is the
one whose answer is kept, and the cache keeps it
(YmerNode.References.Cache), not this row.
The outcome answers "did it work, and whose move is it" in one word, grouping
the reasons YmerNode.Scripts.Runner tabulates:
| outcome | reasons | whose move |
|---|---|---|
ok | — | nobody's |
refused | :not_found, :not_accepted, :not_loaded, :unknown_action, :invalid_schema, :invalid_args, :no_recipe, :reference_changed | the run never started, or its answer was not kept: fix the schedule, or accept the script |
error | :script_error, :script_raised, :script_exited, :bad_return, :result_not_encodable, :not_cache_contract, :not_text | the script ran and failed: fix the script |
timeout | :timeout | the run passed its deadline and was killed |
:not_found is not the runner's: the script's row gone between a firing and
its run, or a watch's reference gone the same way. A script's schedules and a
reference's watch are deleted with them, so only that window can see it.
:no_recipe is a watch's firing that found no script to fetch its reference,
:reference_changed one whose reference was moved or removed while its run
was in flight, so the answer was not kept, and :not_cache_contract and
:not_text are the cache refusing what a watch's script answered.
The message is the runner's rendered text, cut short at a fixed length: it is a line to read in a listing, not a log.
Summary
Functions
The row's last-run fields for one run's answer.
The outcome one run's answer is recorded as.
Functions
The row's last-run fields for one run's answer.
Examples
iex> YmerNode.Schedules.LastRun.attrs({:ok, %{"pong" => true}}, ~U[2026-09-26 07:00:00Z], 12)
%{last_fired_at: ~U[2026-09-26 07:00:00Z], last_outcome: "ok", last_message: nil, last_run_ms: 12}
iex> YmerNode.Schedules.LastRun.attrs({:error, {:timeout, "hex fetch: no answer in 30000 ms, run killed"}}, ~U[2026-09-26 07:00:00Z], 30_001)
%{last_fired_at: ~U[2026-09-26 07:00:00Z], last_outcome: "timeout", last_message: "hex fetch: no answer in 30000 ms, run killed", last_run_ms: 30_001}
The outcome one run's answer is recorded as.
Examples
iex> YmerNode.Schedules.LastRun.outcome({:error, {:not_accepted, "hex is not accepted"}})
"refused"
iex> YmerNode.Schedules.LastRun.outcome({:error, {:script_raised, "hex fetch: boom"}})
"error"