Skip to main content

run_rerun_from

Function run_rerun_from 

Source
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 — invalid run_id, malformed body, or launch-snapshot decode failure.
  • 404 — no Run with this id.
  • 409 — the Run is Running / 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, OR from_step is not present in this Run’s replay log.
  • 202 Accepted — accepted; the flow re-runs in a detached background task (same tokio::spawn + run-TTL ceiling shape as run_resume). Poll GET /v1/runs/:id for 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.

  1. 404 check.
  2. Status gate (fast 409 for Running / Pending).
  3. Decode launch snapshot (fast 400 / 422).
  4. Compute cut index via list_by_run + .position(step_ref == from_step) (fast 422 when the step is not present).
  5. Atomic transition <current terminal> -> Running (409 on loss).
  6. Physical delete_from(cut) on the replay store — safe now because we won the cas and own the Run.
  7. Build ReplayCursor from the truncated entries.
  8. Detached dispatch, same tokio::spawn + default_run_ttl shape as run_resume.

§Known limitations (Layer A)

  1. from_step is a raw step_ref (agent name) — projection alias resolution via StepNaming is Layer B territory. For undeclared steps step_ref == canonical so this is only visible when AgentMeta.projection_name is in use.
  2. BlueprintRef::Inline freezes 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. Use BlueprintRef::Id for the iterate-and-rerun workflow.
  3. Loop bodies match the first occurrencestep_ref is 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.
  4. 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.