Skip to main content

record_permanent_refusal

Function record_permanent_refusal 

Source
pub async fn record_permanent_refusal(
    ctx: &mut RunCtx,
    error: &EngineError,
) -> Result<bool, RuntimeError>
Expand description

Records the terminal RunFailed a PERMANENT run_graph refusal deserves, so a dead run stops masquerading as a running one.

run_graph itself never writes a terminal for a refusal, and that is deliberate: refuse-before-record is what keeps the log free of events past a refusal, and the engine cannot know whether its caller intends to re-drive. The DRIVER does know, and it is the driver that owns the run’s disposition. So the drivers (the CLI’s graph run, resume, and graph fork paths, and the server’s drive_graph task) call this with the error they just received and THE SAME ctx that produced it. The same one matters: the append claims the position that ctx’s cursor stands on, which is the position after everything the refused drive replayed or wrote. A fresh RunCtx over the same log stands at position zero and would diverge rather than append, which is the machinery refusing to write a terminal onto a run it has not read.

Only a permanent error is recorded: one that EngineError::is_permanent calls a pure function of the frozen document and the recorded log, so re-driving reproduces it forever. A transient error is left exactly as it was, and the run stays recoverable. Returns whether a terminal was recorded, so a caller can say so in its own voice.

§Ordering, and the kill between the refusal and this append

The append goes through RunCtx::fail_run, which is the same persist discipline every other event uses: the cursor claims the next sequence and the envelope is durable before this returns. That is also the “only when the log holds no terminal” guard, and it needs no second read of the store. A log whose recorded next event is the identical RunFailed (a driver that already did this) REPLAYS it and appends nothing; a log holding a different terminal is a divergence the caller surfaces rather than overwrites.

A kill -9 landing between the refusal and this append therefore leaves a log with no terminal at all, ending at whatever the refusal was recorded past (for a fold, its last FoldIterationJoined). That log is not corrupt and not stuck: the next drive replays it, re-derives the SAME permanent refusal from the same recorded values, and this appends the RunFailed then. Nothing re-executes, because everything before the refusal is history. The window is a delay in the status an operator reads, never a divergence.

§Errors

RuntimeError when the append does not persist, or when the log already holds a different terminal. Callers report the ORIGINAL engine refusal in that case: it is the real news, and losing the terminal only means the run reads as recoverable when it is not.