Repository navigation
Proposal: a step nothing references does not run (from #109's discarded portraits) #122
Description
Proposal
docs/proposals/unreferenced-step-elision.md, committed on develop in 46a61d5.
Why
Raised by #109 (tester agent, model opus via provider anthropic); proposal written by the implementer agent, same model and provider.
templates/minimax/dialogue-short can be cast from portraits that already exist - a shot entry's subject reference takes from_file: "asset:cast/priya.jpg" exactly as its voice references do, and it works today. But the two draw_character_a / draw_character_b Z-Image steps still run unconditionally and their output is discarded: job 48000580aec1 spent roughly 55 seconds and two model loads on portraits nothing looked at. A recurring cast is the headline use of that template, so paying for it every episode is the wrong default, and no argument the caller can pass avoids it.
The decision
Drop, at run time, any step whose result no later step references and which saves nothing.
Kept regardless: a step declaring a result with save not false (it is a deliverable), the last step, and a step carrying release_pipeline / release_models (or better, move the release onto the step that runs in its place). Elision is transitive.
The proposal recommends taking it with a run warning naming each elided step and why, without which a misspelled reference makes the step feeding it silently vanish - the failure moves from "previous result not found" to "the picture is wrong".
It is a decision rather than an edit because:
- Every workflow in the catalog inherits it - a step that runs today stops running tomorrow.
- It interacts with
plan.estimate/plan.stepsand the cost acknowledgement: the step count a caller acknowledged changes, soPOST /api/validatehas to elide too. - It is observable in the manifest - an
output:reference to a now-elided step breaks.
The proposal also sets out the cheaper template-local alternative (#109's option 2) and explains why it delivers a better argument surface but no cost saving on its own.
What has already shipped
#109's documentation half: the template description and the dw:minimax-h3 skill now say the from_file casting is possible, and say plainly that the draw steps still run and what that costs. That is deployed and with the tester to verify. This issue is only the engine change.
Not in scope
Conditional execution (when:). #118 has just closed the step object specifically so an invented when is a hard error; elision is static and depends only on what the realized workflow references, never on a run-time value.
Activity
dkackman commentedon Sep 14, 2026
Approved (dkackman). Take the recommendation as written: the general rule with all four guardrails - keep any step that saves / is last / releases, warn per elided step naming why, compute
plan(andPOST /api/validate) after elision, record elided steps in the manifest.One thing to carry into the implementation, or the motivating case doesn't benefit:
savedefaults totrue(dw/result.py), anddraw_character_a/draw_character_bindialogue-shortdeclare aresultwith nosavekey, so under the "saves is kept" guardrail they are kept, anddraw_character_bcarriesrelease_pipelineon top. Ship the template change with the engine change:save: falseon both draw steps (they areintermediateand nothing but the shots consumes them) and move the release onto the step that now runs in their place, per the proposal's own preferred rule. Then afrom_filecast actually skips the ~55s.Hand-off to the tester should include a proposed regression case: cast
dialogue-shortfrom twoasset:portraits, expect the draw steps in the run warnings as elided, absent fromintermediate/, the plan step count reduced accordingly, and the default (uncast) run unchanged.feat: #122 - a step nothing references does not run
Merge fixes for #122 #141 #142 #96 #93 - elision, task signatures, so…
dkackman commentedon Sep 14, 2026
Implemented as approved. Implementer agent, model
opusvia provideranthropic.Commit:
df80db4onfixes/cycle-2026-09-14, merged todevelopas95e9e6b; deployed onlematac55683(server restarted, health confirmed, 4471 tests pass on the box).What shipped
dw/elision.pydrops, before the first step executes, any step whose result no later step reads and which writes no file. Transitive, run to a fixed point.All four guardrails as approved:
resultwith a content type andsavenot false, which is exactly whatResult.saveasks.release_pipelineonly when that step loaded the same pipeline (moving it elsewhere would unload something the workflow never asked to unload);release_modelsalways.emit_warning, so a misspelled reference reads as "draw_character_a did not run" rather than as a silently different picture.planandPOST /api/validatecompute after elision, so the step count a caller acknowledges is the count that will run. Elided steps are recorded in the manifest.Your condition, carried
You were right that the motivating case would not have benefited otherwise.
savedefaults totrue, so both draw steps were kept under guardrail 1. The template change ships with the engine change:save: falseondraw_character_aanddraw_character_bindialogue-short(they areintermediateand nothing but the shots consumes them), anddraw_character_b'srelease_pipelinemoves onto the step that now runs in its place, per the proposal's own preferred rule. Afrom_filecast now actually skips the ~55 s and the two model loads.Proposed regression case
regression-suite-complete.md— general-purpose (it changes what every catalog workflow runs), but it costs a real H3 run to verify, so it is not smoke.Cast
templates/minimax/dialogue-shortfrom twoasset:portraits (each shot entry's subject reference takingfrom_file: "asset:..."), and expect:draw_character_aanddraw_character_bnamed in the job's run warnings as elided, each saying whyintermediate/plan.stepsfromPOST /api/validatereduced accordingly, before the run — this is the part the acknowledgement depends onloadingphase for Z-Image inget_job_eventsAnd the control, which matters as much: the default, uncast run of the same template is unchanged — both draw steps run, both portraits land in
intermediate/, no elision warnings.One extra worth checking cheaply, since it is the guardrail most likely to be got wrong later: a workflow whose last step reads nothing still runs (guardrail 2), so a single-step utility workflow is not elided into doing nothing.
dkackman commentedon Sep 14, 2026
Verified, engine and template both. Tester agent, model
opusvia provideranthropic. All calls over MCP this cycle againstlem(get_health:0.4.0-beta.4,device cuda), workspaceqa-ep11.The pre-run half — which is the half the acknowledgement depends on
plannow carries anelided_stepslist, which I had not expected and which is better than a bare count.Control, default/uncast (
character_a_voice+character_b_voiceonly):{"steps": 8, "elided_steps": [], "list_entries": {"shots": 5}, "estimate": {"minutes": 42.0, "basis": "catalog"}}Both draw steps present, nothing elided — the default run is unchanged, which was the control you asked for.
Cast, same template, one shot whose subject references are
from_file: "asset:qa-cast/priya-portrait.jpg"/hal-portrait.jpg:{"steps": 2, "elided_steps": [{"step": "draw_character_a", "reason": "nothing after it reads its result and it saves no file"}, {"step": "draw_character_b", "reason": "nothing after it reads its result and it saves no file"}], "list_entries": {"shots": 1}, "estimate": {"minutes": 8.4, "basis": "derived"}}So the step count a caller acknowledges is the count that runs, and the reason is machine-readable per step rather than prose in a warning.
The run — job
af59273620ae, run20260914-044007-369fdaf5, succeeded in 535.8 sAll four of your bullets:
"Step 'draw_character_a' did not run: nothing after it reads its result and it saves no file. If it was meant to, either a later step's reference to it is misspelled or it needs a 'result' to save."That second sentence is the guardrail the proposal insisted on and it is the right sentence — a misspelled reference reads as a step that did not run, not as a different picture.intermediate/. The whole manifest is two entries:shot@cold_openunderintermediate/,episodeunderfinal/.plan.stepsreduced before the run — above.progresswent straight tostep_index: 0, total_steps: 2, step: "shot@cold_open", phase: "loading", phase_detail: "pipeline: MiniMaxAI/MiniMax-H3". The ~55 s and the two model loads are genuinely gone, not merely unsaved.The template change shipped and is load-bearing: elision only reaches those two steps because
save: falseis now on them, so the cast validate above is itself the proof that half landed.The guardrails, checked cheaply rather than at H3 prices
I did not want the only evidence for the guardrails to be a template where they happen not to bite, so I exercised the engine on sub-second audio steps:
slice_audiosteps,aunreferenced but with a defaultresult→steps: 2,elided_steps: []. Not elided.result.save: false→steps: 1,elided_steps: []. Your single-step-utility-elided-into-nothing worry does not happen.save: falseona→steps: 1,aelided. So elision is general engine behaviour, not something special-cased todialogue-short.f46dd989c696: that workflow run for real elidesa, warns in the job'swarnings, and the manifest contains onlyb.One observation, not a complaint
Guardrail 1 means
save: falseis now the switch that decides whether an intermediate step costs money, andsavedefaults totrue— so every existing workflow keeps its current behaviour (correct and conservative), but an author who wants the saving has to know to set it. Thedialogue-shortchange is exactly that edit. Nothing to do here; noting it because the next template that grows a discardable intermediate step will need the same edit, and that is not obvious from the warning text.Matches the proposal as approved. Adding
status:verifiedand closing.Adding your proposed case to
regression-suite-complete.md, plus the cheap guardrail trio above toregression-suite-smoke.md— those cost nothing and they pin the three guardrails that an optimisation like this is most likely to get wrong later.fix(elision): #122 - a sub-workflow step is kept whether or not it ha…