fix: Forgejo Actions event semantics so label-driven dispatch fires #14

Merged
ellen merged 1 commit from fix/forgejo-event-semantics into main 2026-07-23 11:32:37 +00:00
Member

Why

First end-to-end test of the agent pipeline (throwaway Forgejo 15.0.5 + runner, claude stubbed) showed the dispatch never fires — it was written with GitHub event semantics Forgejo does not share. Four issues, all reproduced on Forgejo 15.0.5 (same version as prod) and fixed + re-validated on the test instance (full loop ran: agent/plan → plan → plan/approved → dev + PR → test FAIL → loop/1 + agent/dev bounce → dev → test PASS → needs/review).

Full write-up: valssi/docs → plans/agent-orchestration-test-findings.md.

Fixes (all in dispatch.yaml)

  1. Label add is label_updated, not labeled (remove is label_cleared). Every route guard tested action == 'labeled' ⇒ nothing fired. Swapped 6 guards. (Bonus: removal fires the distinct label_cleared, so the ack-removal of a one-shot agent/* label does not re-trigger the route — safe.)
  2. Nested reusable workflow loses github.event_name — inside dispatch.yaml it is workflow_call, not issues/pull_request, so those guards were always false even after #1. Now key issue-vs-PR off payload shape: github.event.issue.number / github.event.pull_request.number. (.action, .label.name, .sender, .issue.* do propagate.)
  3. PR label changes emit NO event ⇒ the agent/test hand-off to the tester never fired (loop stalled at state/testing). PR content events do fire (opened, pull_request_sync / action synchronized — not GitHub's synchronize). The test route now triggers on PR open/sync for agent/issue-* branches, and resolve computes the model for these label-less PR events (recovers the issue from the head ref).
  4. schedule/tick was dead (same root as #2: event_name is workflow_call) ⇒ queue-drain + daily digest never ran. Added a workflow_call input event_name that the caller forwards, and tick keys off it.

Companion PR (caller)

The caller change lives in the template repo (single source of truth), not here: valssi-public/template PR — "fix: forward event_name from the canonical caller". It adds with: { event_name: ${{ github.event_name }} }. Merge this PR (#14) first so the event_name input exists, then the template PR. Existing repos need the same one-line addition to their .forgejo/workflows/agent.yaml.

Scope / safety

  • No model, routing-intent, or F_URL changes. F_URL stays git.valssi.eu.
  • #4's dispatch change is non-regressive: if a caller doesn't yet forward event_name, the input defaults to "" and tick simply stays off (current behaviour) — no other route depends on it.

Not covered / untested

loop/3 escalate-or-park, no-progress guard, blocked/* defer→tick resume (needs the caller edit), coordinate, and reflect (its agent/reflect PR-label path is dead per #3; the merged-PR path is untested). All model runs used the stub.

🤖 Generated with Claude Code

## Why First **end-to-end** test of the agent pipeline (throwaway Forgejo 15.0.5 + runner, `claude` stubbed) showed the dispatch **never fires** — it was written with GitHub event semantics Forgejo does not share. Four issues, all reproduced on Forgejo 15.0.5 (same version as prod) and fixed + re-validated on the test instance (full loop ran: `agent/plan → plan → plan/approved → dev + PR → test FAIL → loop/1 + agent/dev bounce → dev → test PASS → needs/review`). Full write-up: `valssi/docs` → `plans/agent-orchestration-test-findings.md`. ## Fixes (all in `dispatch.yaml`) 1. **Label add is `label_updated`, not `labeled`** (remove is `label_cleared`). Every route guard tested `action == 'labeled'` ⇒ nothing fired. Swapped 6 guards. (Bonus: removal fires the distinct `label_cleared`, so the ack-removal of a one-shot `agent/*` label does **not** re-trigger the route — safe.) 2. **Nested reusable workflow loses `github.event_name`** — inside `dispatch.yaml` it is `workflow_call`, not `issues`/`pull_request`, so those guards were always false even after #1. Now key issue-vs-PR off payload shape: `github.event.issue.number` / `github.event.pull_request.number`. (`.action`, `.label.name`, `.sender`, `.issue.*` do propagate.) 3. **PR label changes emit NO event** ⇒ the `agent/test` hand-off to the tester never fired (loop stalled at `state/testing`). PR *content* events do fire (`opened`, `pull_request_sync` / action **`synchronized`** — not GitHub's `synchronize`). The `test` route now triggers on PR open/sync for `agent/issue-*` branches, and `resolve` computes the model for these label-less PR events (recovers the issue from the head ref). 4. **`schedule`/`tick` was dead** (same root as #2: `event_name` is `workflow_call`) ⇒ queue-drain + daily digest never ran. Added a `workflow_call` input `event_name` that the caller forwards, and `tick` keys off it. ## Companion PR (caller) The caller change lives in the template repo (single source of truth), **not** here: **`valssi-public/template` PR — "fix: forward event_name from the canonical caller"**. It adds `with: { event_name: ${{ github.event_name }} }`. **Merge this PR (#14) first** so the `event_name` input exists, then the template PR. Existing repos need the same one-line addition to their `.forgejo/workflows/agent.yaml`. ## Scope / safety - No model, routing-intent, or `F_URL` changes. `F_URL` stays `git.valssi.eu`. - #4's dispatch change is **non-regressive**: if a caller doesn't yet forward `event_name`, the input defaults to `""` and `tick` simply stays off (current behaviour) — no other route depends on it. ## Not covered / untested `loop/3` escalate-or-park, no-progress guard, `blocked/*` defer→tick resume (needs the caller edit), `coordinate`, and `reflect` (its `agent/reflect` PR-label path is dead per #3; the merged-PR path is untested). All model runs used the stub. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix: Forgejo Actions event semantics so label-driven dispatch fires
Some checks failed
coordinate.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (push) Failing after 0s
dev.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (push) Failing after 0s
plan.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (push) Failing after 0s
reflect.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (push) Failing after 0s
test.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (push) Failing after 0s
coordinate.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (pull_request) Failing after 0s
dev.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (pull_request) Failing after 0s
plan.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (pull_request) Failing after 0s
reflect.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (pull_request) Failing after 0s
test.yaml / fix: Forgejo Actions event semantics so label-driven dispatch fires (pull_request) Failing after 0s
coordinate.yaml / Merge pull request 'fix: Forgejo Actions event semantics so label-driven dispatch fires' (#14) from fix/forgejo-event-semantics into main (pull_request) Failing after 0s
dev.yaml / Merge pull request 'fix: Forgejo Actions event semantics so label-driven dispatch fires' (#14) from fix/forgejo-event-semantics into main (pull_request) Failing after 0s
plan.yaml / Merge pull request 'fix: Forgejo Actions event semantics so label-driven dispatch fires' (#14) from fix/forgejo-event-semantics into main (pull_request) Failing after 0s
reflect.yaml / Merge pull request 'fix: Forgejo Actions event semantics so label-driven dispatch fires' (#14) from fix/forgejo-event-semantics into main (pull_request) Failing after 0s
test.yaml / Merge pull request 'fix: Forgejo Actions event semantics so label-driven dispatch fires' (#14) from fix/forgejo-event-semantics into main (pull_request) Failing after 0s
cc7fcd49b5
Forgejo (15.0.5) does not share GitHub's event semantics; none of the routes
fire as written. Found in the first end-to-end test (see valssi/docs
plans/agent-orchestration-test-findings.md).

- Label add is action 'label_updated' (remove is 'label_cleared'), never
  GitHub's 'labeled'/'unlabeled'. (6 guards)
- Inside a called reusable workflow Forgejo sets github.event_name to
  'workflow_call', not the original 'issues'/'pull_request'. Key routes off
  payload shape (github.event.issue.number / .pull_request.number) instead.
- PR label changes emit NO workflow event, so the agent/test hand-off never
  fires. PR content events do (opened / pull_request_sync action
  'synchronized'); trigger the tester on those for agent/issue-* branches.
  resolve now also computes the model for these label-less PR events.
- schedule/tick was dead (event_name is workflow_call): forward the caller's
  real github.event_name via a new workflow_call input, and add the canonical
  caller-agent.yaml template that passes it (the one required caller edit).

No functional/model changes; F_URL and all routing intent unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ellen merged commit 8c8e0db36c into main 2026-07-23 11:32:37 +00:00
ellen deleted branch fix/forgejo-event-semantics 2026-07-23 11:32:38 +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!14
No description provided.