dispatch: run resolve unconditionally so a skipped resolve can't block the run #13

Merged
ellen merged 1 commit from fix/dispatch-resolve-always-run into main 2026-07-22 21:30:16 +00:00
Member

Problem

On any non-labeled event that reaches dispatch (a schedule tick, a merged-PR reflect, an issue comment, …), the resolve job is skipped by its if:. But forgejo-runner (now v12.10.1, so reusable workflows finally evaluate) eagerly evaluates the route jobs' with: needs.resolve.outputs.* while building the job graph — before applying each job's if:. A skipped resolve exposes no outputs, so the runner aborts the whole run:

Workflow was not executed due to an error that blocked the execution attempt.
Unable to evaluate with of job dispatch.plan: job dispatch.resolve is missing output model.

Every job shows 0s — including tick, which should have run. reflect's ${{ … || 'opus' }} fallback can't save it, because the block happens before the expression is evaluated (proven: reflect has if: always() + the || and was still blocked).

This is why the every-15-min schedule ticks (and merged-PR reflects) all fail.

Fix

resolve now runs unconditionally (if: ${{ always() }}) so its declared model/base_url outputs always exist and the route jobs' with: is always evaluable. For non-command events the step early-exits with empty outputs (before any label API lookup), so:

  • route jobs (plan, implement, dev-bounce, test, coordinate) still skip via their own if:;
  • reflect's merged-PR path gets an empty model → its || 'opus' fallback applies exactly as before;
  • command-label events (agent/plan, plan/approved, agent/dev, agent/test, agent/coordinate, agent/reflect) resolve the tier→model matrix unchanged.

Only .forgejo/workflows/dispatch.yaml changes (+22/-3).

Validation to run after merge/preview

  1. Schedule tick / workflow_dispatch on a repo whose caller subscribes → run completes, tick executes, no "blocked execution" banner.
  2. Label a throwaway issue agent/plan → resolve runs and plan fires with the correct --model.

🤖 Generated with Claude Code

## Problem On any **non-labeled** event that reaches `dispatch` (a schedule `tick`, a merged-PR `reflect`, an issue comment, …), the `resolve` job is skipped by its `if:`. But forgejo-runner (now v12.10.1, so reusable workflows finally evaluate) **eagerly evaluates the route jobs' `with: needs.resolve.outputs.*` while building the job graph — before applying each job's `if:`**. A skipped `resolve` exposes no outputs, so the runner aborts the whole run: > Workflow was not executed due to an error that blocked the execution attempt. > Unable to evaluate `with` of job `dispatch.plan`: job `dispatch.resolve` is missing output `model`. Every job shows 0s — including `tick`, which should have run. `reflect`'s `${{ … || 'opus' }}` fallback can't save it, because the block happens *before* the expression is evaluated (proven: `reflect` has `if: always()` + the `||` and was still blocked). This is why the every-15-min schedule ticks (and merged-PR reflects) all fail. ## Fix `resolve` now runs **unconditionally** (`if: ${{ always() }}`) so its declared `model`/`base_url` outputs always exist and the route jobs' `with:` is always evaluable. For non-command events the step **early-exits with empty outputs** (before any label API lookup), so: - route jobs (`plan`, `implement`, `dev-bounce`, `test`, `coordinate`) still skip via their own `if:`; - `reflect`'s merged-PR path gets an empty model → its `|| 'opus'` fallback applies exactly as before; - command-label events (`agent/plan`, `plan/approved`, `agent/dev`, `agent/test`, `agent/coordinate`, `agent/reflect`) resolve the tier→model matrix unchanged. Only `.forgejo/workflows/dispatch.yaml` changes (+22/-3). ## Validation to run after merge/preview 1. **Schedule tick / `workflow_dispatch`** on a repo whose caller subscribes → run completes, `tick` executes, **no "blocked execution" banner**. 2. Label a throwaway issue **`agent/plan`** → `resolve` runs and `plan` fires with the correct `--model`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
dispatch: run resolve unconditionally so route jobs' with: never blocks the run
Some checks failed
coordinate.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (push) Failing after 0s
dev.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (push) Failing after 0s
plan.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (push) Failing after 0s
reflect.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (push) Failing after 0s
test.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (push) Failing after 0s
coordinate.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (pull_request) Failing after 0s
dev.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (pull_request) Failing after 0s
plan.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (pull_request) Failing after 0s
reflect.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (pull_request) Failing after 0s
test.yaml / dispatch: run resolve unconditionally so route jobs' with: never blocks the run (pull_request) Failing after 0s
coordinate.yaml / Merge pull request 'dispatch: run resolve unconditionally so a skipped resolve can't block the run' (#13) from fix/dispatch-resolve-always-run into main (pull_request) Failing after 0s
dev.yaml / Merge pull request 'dispatch: run resolve unconditionally so a skipped resolve can't block the run' (#13) from fix/dispatch-resolve-always-run into main (pull_request) Failing after 0s
plan.yaml / Merge pull request 'dispatch: run resolve unconditionally so a skipped resolve can't block the run' (#13) from fix/dispatch-resolve-always-run into main (pull_request) Failing after 0s
reflect.yaml / Merge pull request 'dispatch: run resolve unconditionally so a skipped resolve can't block the run' (#13) from fix/dispatch-resolve-always-run into main (pull_request) Failing after 0s
test.yaml / Merge pull request 'dispatch: run resolve unconditionally so a skipped resolve can't block the run' (#13) from fix/dispatch-resolve-always-run into main (pull_request) Failing after 0s
655daf001c
On any non-labeled event that reaches dispatch (schedule tick, merged-PR,
comment, ...), resolve was skipped. forgejo-runner eagerly evaluates the route
jobs' `with: needs.resolve.outputs.*` while building the graph — before applying
their `if:` — so a skipped resolve exposes no outputs and the runner blocks the
ENTIRE run: "Unable to evaluate `with` of job dispatch.plan: job dispatch.resolve
is missing output model" (all jobs 0s, including tick). reflect's `|| 'opus'`
fallback can't help because the block happens before the expression evaluates.

Fix: resolve now runs unconditionally (`if: always()`) and emits EMPTY
model/base_url outputs for non-command events (early-exit before the label
lookup). Route jobs still skip via their own `if:`; reflect's merged-PR path
keeps its `|| 'opus'` fallback. Command-label events are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ellen merged commit 9ae5c826a6 into main 2026-07-22 21:30:16 +00:00
ellen deleted branch fix/dispatch-resolve-always-run 2026-07-22 21:30:16 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
valssi-public/agent-workflows!13
No description provided.