Repeat

Repeat keeps re-applying the inner stage to the same input, following Status.Success transitions, until the stage signals completion. On an error-free Status.Complete the status is converted back to Success; if the Complete carries errors, those are preserved.

Only the status ends the cycle. An iteration that yields Yield.None with Success keeps Repeat spinning — deliberately so: unlike Loop, Repeat never feeds an output anywhere, so the absence of one says nothing about whether the work is done. A stage that has to stop the cycle without producing a value must say so with Complete.

As in Loop, the continuation of the inner stage is selected on the status the inner stage itself produced — never on the status Repeat reports to the enclosing pipeline (an error-free Complete is absorbed into a Success), and never on the status that pipeline later evolves Repeat with. A skipped Repeat skips its inner stage and selects the inner continuation on the neutral Success.

Unlike Loop, Repeat does not feed output back as input — the same original input is passed on every iteration. It is suited for stages like Countdown that batch a fixed number of runs and signal Complete at the end of each batch.

import h8io.stages.*
import h8io.stages.std.*
import h8io.stages.cycles.*
Repeat(Countdown[String](3))("x")
// res0: Yield[String, String, Nothing] = Some(
//   out = "x",
//   status = Success,
//   evolution = ConstEvolution(
//     stage = Repeat(alterand = Countdown(i = 3L, n = 3L)),
//     _dispose = h8io.stages.cycles.Repeat$$Lambda$19878/0x00007f58029acb68@2e771880
//   )
// )

Countdown(3) processes "x" three times: Success, Success, Complete. Repeat absorbs the Complete and returns Some("x", Success, Repeat(Countdown(3))), ready for the next invocation.