pub async fn run_rerun_from(
__arg0: State<AppState>,
__arg1: Path<String>,
__arg2: Json<RunRerunFromRequest>,
) -> Result<(StatusCode, Json<RunRerunFromResponse>), ApiError>Expand description
POST /v1/runs/:id/rerun-from — GH #71 Layer A. Re-executes a specific
step (and every downstream step) of a terminal Run under the SAME
run_id. Mirrors run_resume, with two deltas: it accepts any
terminal status (Done / Failed / Interrupted) rather than only
Interrupted, and it physically truncates the replay log at the cut
point (via crate::AppState::replay_store’s delete_from) so that
re-dispatch’s append does not collide with the pre-rerun row and so
list_by_run reflects the rerun’s real history rather than the
pre-rerun ghost.
§Status codes
400— invalidrun_id, malformed body, or launch-snapshot decode failure.404— no Run with this id.409— the Run isRunning/Pending(would race the in-flight driver), OR a concurrent transition won the compare-and-set.422— the Run has no recorded launch-input snapshot, ORfrom_stepis not present in this Run’s replay log, OR the run’s replay log is empty next to a non-emptyRunRecord.step_entriestrace (a priorrerun-fromreached the truncate stage and consumed the log), OR the current-head Blueprint fails to compile (unresolvedoperator_refetc.) — the deterministic pre-flight gate that keeps the replay log untouched on a compile-fail.202 Accepted— accepted; the flow re-runs in a detached background task (sametokio::spawn+ run-TTL ceiling shape asrun_resume). PollGET /v1/runs/:idfor the terminal status.
§Order of operations
The compare-and-set runs BEFORE the delete_from on purpose: a losing
cas returns 409 without ever touching the store, so a lost race can
never leave the store truncated while the status stayed at its old
terminal value. The compile pre-check runs BEFORE the compare-and-set
for the same reason: a deterministic compile failure fires a 422
that leaves both status and the replay log untouched, so the caller
can fix the Blueprint and retry against the same run.
- 404 check.
- Status gate (fast 409 for
Running/Pending). - Decode launch snapshot (fast 400 / 422).
- Compute cut index via
list_by_run+.position(step_ref == from_step)(fast 422 when the step is not present, with a distinct message when the log is empty butRunRecord.step_entriesshows the run did trace steps — a consumed log from a priorrerun-from). - Pre-flight compile check via
TaskApplication::precompileagainst the launch snapshot’s Blueprint (fast 422 on anyCompileError). Prevents compile-fail-inside-tokio::spawnfrom consuming the replay log via step 7’sdelete_from. - Atomic transition
<current terminal> -> Running(409 on loss). - Physical
delete_from(cut)on the replay store — safe now because we won the cas and own the Run. - Build
ReplayCursorfrom the truncated entries. - Detached dispatch, same
tokio::spawn+default_run_ttlshape asrun_resume.
§Known limitations (Layer A)
from_stepis a rawstep_ref(agent name) — projection alias resolution viaStepNamingis Layer B territory. For undeclared stepsstep_ref == canonicalso this is only visible whenAgentMeta.projection_nameis in use.BlueprintRef::Inlinefreezes the BP in the launch snapshot — the rerun re-decodes the same inline BP, so agent-definition edits landed on disk between the original dispatch and the rerun are NOT honored for inline runs. UseBlueprintRef::Idfor the iterate-and-rerun workflow.- Loop bodies match the first occurrence —
step_refis the agent name, so.position(|e| e.step_ref == from_step)finds the FIRST occurrence and truncates from there. Rerunning a specific loop iteration needs Layer B semantics. - Structural BP change is out of scope — if steps were added / removed / reordered between the original dispatch and the rerun, the flow-ir re-eval will naturally miss the step or dispatch a different downstream. Start a fresh run in that case.