Vetrix Docs

Single-step retry

Vetrix re-runs one failed step or one matrix cell without re-running the whole pipeline. The current release ships the backend foundation: the YAML schema, retry-policy validator, engine decision point, audit discriminators, and the fork MR guardrail. The end-to-end HTTP wiring, UI tile, and downstream DAG re-evaluation execution loop are not yet available; the engine-side contracts described below are stable and will be imported unchanged when those surfaces ship.

YAML syntax

steps:
  - name: flaky-test
    run: go test ./flaky/...
    retry:
      max_attempts: 3
      on: [failure, timeout]   # optional; defaults to [failure]
      backoff_seconds: 30      # optional; defaults to 0 (immediate)

Parse-time guarantees (internal/automations/retry_parse_test.go):

  • max_attempts must be ≥ 1 and ≤ 100 (sanity cap).
  • on: entries must be one of failure or timeout.
  • backoff_seconds must be ≥ 0.
  • Omitting the block entirely leaves legacy workflows unchanged.

Decision surface

internal/cicd/retry.go ships PlanRetry(req RetryRequest) RetryDecision:

type RetryRequest struct {
    StepID          uuid.UUID
    CurrentAttempt  int          // retry_count on the row before this call
    MaxAttempts     int          // retry_max on the row
    Trigger         RetryTrigger // failure | timeout
    OnPolicy        []RetryTrigger
    IsForkPR        bool
}

type RetryDecision struct {
    Allowed       bool
    NextAttempt   int
    Reason        string // retry_exhausted | retry_trigger_not_in_on_list
    RetryableFromCheckpoint bool
}

Reason strings are the stable audit-trail discriminators — tests and downstream filters assert them verbatim.

Fork-MR guardrail

Before handing a RetryContext to the executor the engine calls GuardForkPRRetry(req, wantsEnvSecrets). The function returns ErrForkPRSecretMaterialisationBlocked when a fork-MR retry would materialise environment-scoped secrets — retries must never elevate a fork-MR's token scope; the invariant lives at the engine layer rather than in a YAML opt-in.

Downstream re-evaluation helper

ShouldReexecute(prev, current map[string]string) is the pure input comparator downstream jobs consume when deciding whether a needs: edge has changed on retry. It returns true when at least one declared output differs, covering adds / removes / value changes.

Not yet available

The following surfaces are planned but not part of the current release:

  • HTTP endpoints: POST /runs/{run_id}/jobs/{jid}/steps/{sid}/retry and POST /runs/{run_id}/jobs/{jid}/retry?cell=<matrix_key>.
  • Engine wiring for workspace + upstream-output restore + retry-attempt env var (VETRIX_RETRY_ATTEMPT) injection into the executor context.
  • Frontend Retry button + retry #N chip on the run detail page.
  • Audit retry event writer.

The pure PlanRetry + GuardForkPRRetry + ShouldReexecute

  • ValidateRetryPolicy surface is the contract the HTTP handler and engine executor layer will import unchanged.