Skip to content

[REA-6854] Report each finished step to the runtime with complete_step() - #234

Merged
Dere-Wah merged 1 commit into
mainfrom
dere/rea-6854-report-completed-steps
Oct 5, 2026
Merged

Dere-Wah merged 1 commit into
mainfrom
dere/rea-6854-report-completed-steps

Conversation

@Dere-Wah

@Dere-Wah Dere-Wah commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Why

The runtime has no idea when a model finishes a unit of work. It needs that to count a session's steps, which the next PR closes the session on, and later to keep each step's result. The default step loop knows where a step ends; a model with its own run() knows where its unit of work ends, such as a built clip. Both need one way to say so.

What Changed

A model reports a finished step with complete_step():

from reactor_runtime import ReactorApp, StepCompleted

class ClipModel(ReactorApp):
    async def run(self) -> None:
        while True:
            await self.connected.wait()
            clip = await self.build_next_clip()
            await self.emit(clip.output)
            await self.complete_step(StepCompleted(
                output=clip.output,
                files={"last_frame.png": clip.last_frame_png},
                elapsed=clip.seconds,
            ))

StepCompleted carries the step's output, extra files to keep with it, an error when it failed, and how long it took. File names must be one plain name, result.json and output.mp4 are reserved for the runtime, and contents must be bytes. complete_step() sits next to send() on ReactorCore.

The default step loop reports every step that runs, after it emits the step's media. That includes a step that produced nothing (output=None) and a step whose error process_output() recovered from (reported without an error, since the application handled it). A refused step and a crash report nothing. ReactorPipeline's generator driver reports nothing.

A ReactorApp that wants to write the report itself, to keep extra files with a step or to mark a step it recovered from, returns a StepCompleted from process_output() instead of the Output. The loop emits its output and reports it as given, filling in elapsed with the measured generate() time when it is unset:

async def process_output(self, outcome: StepOutcome) -> WaypointOutput | StepCompleted | None:
    if isinstance(outcome.error, NoReference):
        await self.send(CommandError(command="generate", reason="No reference image."))
        return StepCompleted(error="no reference image")
    if outcome.error is not None:
        raise outcome.error
    return StepCompleted(
        output=WaypointOutput(main_video=outcome.result.frames),
        files={"prompt.txt": self.state.prompt.encode()},
    )

Calling complete_step() from inside process_output() would report the step twice, so the return value is the one way to replace the loop's report.

The report crosses the bridge as a neutral CompletedStep, with the output turned into a media bundle, through a step sink bound beside the media sink, so the runner never sees a model class. The runner numbers each step within its session and journals a new step_completed fact, {"step": 1, "saved": false, "error": null}. saved stays false until step results land. The event-vocabulary tests that pin the journal event list gain it on purpose.

@Dere-Wah
Dere-Wah requested a review from a team as a code owner October 3, 2026 00:36
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

[codex-review] - [P1] src/reactor_runtime/runner/runner.py: Step limits are counted but never stop the session.

Scope: full (3061225..9af1f4c).

View workflow run.

Comment thread src/reactor_runtime/runner/runner.py

@tempusfrangit tempusfrangit left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed step reporting through the bridge and the default-loop coverage for refused, empty, recovered, and failed steps. The reporting contract looks sound.

@Dere-Wah
Dere-Wah force-pushed the dere/rea-6854-apply-the-starting-input branch from 3061225 to 2bb381b Compare October 4, 2026 16:39
@Dere-Wah
Dere-Wah force-pushed the dere/rea-6854-report-completed-steps branch 2 times, most recently from 2b9b4f5 to dc34d85 Compare October 4, 2026 18:28
@Dere-Wah
Dere-Wah force-pushed the dere/rea-6854-apply-the-starting-input branch from 0f92c35 to 63884e1 Compare October 4, 2026 23:47
@Dere-Wah
Dere-Wah force-pushed the dere/rea-6854-report-completed-steps branch from dc34d85 to c52f4ed Compare October 4, 2026 23:47
@Dere-Wah
Dere-Wah force-pushed the dere/rea-6854-report-completed-steps branch from c52f4ed to 91cdf36 Compare October 5, 2026 17:58

Dere-Wah commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Oct 5, 6:07 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Oct 5, 6:18 PM UTC: Graphite rebased this pull request as part of a merge.
  • Oct 5, 6:19 PM UTC: @Dere-Wah merged this pull request with Graphite.

@Dere-Wah
Dere-Wah changed the base branch from dere/rea-6854-apply-the-starting-input to graphite-base/234 October 5, 2026 18:14
@Dere-Wah
Dere-Wah changed the base branch from graphite-base/234 to main October 5, 2026 18:16
The runtime needs to know when a model finishes a unit of work, to count a
session's steps and later to save each step's result. A model reports one
with complete_step(StepCompleted(...)): the step's output, any extra files
to keep with it, an error when it failed, and how long it took.

The default step loop reports every step that runs, after it emits the
step's media, including a step that produced nothing and one whose error
process_output() recovered from; a refused step or a crash reports nothing.
process_output() writes the report itself by returning a StepCompleted
instead of an Output: the loop emits its output and reports it as given.
A model with its own run() calls complete_step() where it finishes a unit
of work, such as a built clip. The generator-driven ReactorPipeline reports
nothing.

The report crosses into the runner as a neutral CompletedStep, with the
output turned into a media bundle, through a step sink bound like the media
sink. The runner numbers each step within its session and journals it as a
step_completed fact with the step number, whether a step result follows
(not yet: saving is off), and the error.

Signed-off-by: Dere-Wah <derexcontact@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@Dere-Wah
Dere-Wah force-pushed the dere/rea-6854-report-completed-steps branch from 91cdf36 to 1eaa26a Compare October 5, 2026 18:17
@Dere-Wah
Dere-Wah merged commit 384d29a into main Oct 5, 2026
10 checks passed
@Dere-Wah
Dere-Wah deleted the dere/rea-6854-report-completed-steps branch October 5, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants