Skip to content

feat: add workflow dispatch and run inspection - #1031

Open
mariusvniekerk wants to merge 44 commits into
mainfrom
kenn-forge/issue-1003-add-workflow-dispatch-and-run-inspection-to-forge
Open

feat: add workflow dispatch and run inspection#1031
mariusvniekerk wants to merge 44 commits into
mainfrom
kenn-forge/issue-1003-add-workflow-dispatch-and-run-inspection-to-forge

Conversation

@mariusvniekerk

@mariusvniekerk mariusvniekerk commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Brings the contributed workflow Actions implementation from #1003 into the repository so maintainers can trigger provider workflows and inspect recent runs without leaving Forge, which matters most when the provider web UI is slow or unavailable.

  • Adds an opt-in Actions workspace that lists manual workflows, recent runs, jobs, and steps.
  • Dispatch supports typed inputs, environments, pull request head-ref defaults, and recovery when a workflow definition goes stale.
  • Adds a Run workflow entry on pull requests for both desktop and phone layouts. It renders only when the repository has at least one manual workflow.
  • Manual dispatch is never retried. After the provider accepts, the server locates the created run, watches it until it completes, and pushes workflow_dispatch_progress events over the existing SSE stream. The browser does no workflow polling.

Two things changed from the contributed branch during review:

Screenshot from the contributor's implementation:

Actions workspace

Closes #1003

🤖 Generated with Claude Code

luck0r and others added 30 commits August 28, 2026 15:29
Workflow discovery, run reads, and dispatch are independent optional provider contracts so GitHub support does not leak into server or frontend boundaries.
A bounded node parser preserves GitHub workflow input types and declaration order while rejecting ambiguous schemas before they reach dispatch forms.
Require a single YAML document and reject unknown workflow_dispatch or input-definition fields so malformed schemas cannot be silently normalized.
GitHub workflow discovery, runs, jobs, environments, and dispatch now normalize through the provider boundary and preserve personal-credential attribution for writes.
Huma routes validate live workflow definitions and dispatch inputs behind repository identity, capability, credential, and rate-limit gates.
Actions stays disabled by default and one persisted mode switch controls every workflow surface and polling owner while leaving provider APIs available.
Task 4 made read_workflows, read_workflow_runs, and workflow_dispatch required
members of the generated ProviderCapabilitiesResponse type. Add fail-closed
local defaults (false) to each of the four defaultProviderCapabilities
objects so the front-end sources compile before provider data loads. No
runtime, markup, generated code, or behavior change.
Effect services now deduplicate reads, bound polling and reconciliation, and retain non-idempotent dispatch outcomes across component navigation without replaying writes.
Install cleanup and admitted dispatch handoffs without interruption gaps, restart missed shared demand exactly once, and clear interrupted loading projections when Actions is disabled.
One accessible form renders provider-normalized inputs and one compact run surface reveals jobs while keeping logs and artifacts on the provider.
Preserve definition-scoped drafts, fence duplicate commands, expose accessible validation, and allow only safe provider run links.
Refresh typed drafts on definition changes, release acknowledged submissions for a fresh idle cycle, and keep input and reload ownership collision-free.
Keep reload admission fenced across same-kind controlled updates while resetting only after a real conflict exit or dialog remount.
Enabled users can select a provider repository, dispatch manual workflows, and follow current runs without exposing any Actions demand while the mode is off.
Keep provider read failures visible beside retained data and preserve full-height medium layouts when the repository rail is absent.
The existing responsive Actions menu now survives merged PRs and opens the same explicit workflow confirmation used by the Actions page.
The default-off Actions mode is now covered by a stateful provider fixture, full browser workflow, user guidance, and durable provider, error, polling, and PR interaction contracts.
Failed visible catalog reads now wait for the existing idle cadence instead of restarting the repository loop without delay.
luck0r and others added 10 commits August 29, 2026 00:42
Apply gofmt to the remaining feature-touched server and e2e files so repository formatting hooks accept the completed workflow Actions branch.
Keep pull request lifecycle decisions in the primary action row and group workflow dispatch with workspace utilities. Preserve a single measured Actions overflow for constrained widths while anchoring the wide workflow menu directly to its trigger.
Preserve the workflow dispatch feature while adopting current phone action layouts, provider route ownership, and the pinned lint policy. Keep optional fixture capabilities visible in full-stack e2e coverage.
Maintainers had to leave Forge to trigger provider workflows or look at
recent runs, which hurts most when the provider web UI is slow or down.
This brings the contributed implementation from issue #1003 into the
repository: an opt-in Actions workspace listing manual workflows, recent
runs, jobs, and steps; typed dispatch inputs, environments, pull request
head-ref defaults, and stale-definition recovery; and a Run workflow entry
on pull requests for desktop and phone layouts.

The contributed branch was merged from a fork rather than replayed so the
original authorship stays intact. Main had since added two fields to the
pull detail settings type, so one test fixture in the workflow actions
pull detail browser test now spreads the store defaults instead of
building the settings object by hand.

Closes #1003

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KuhHYTTk1QzpastWi4zD7T
@roborev-ci

roborev-ci Bot commented Sep 3, 2026

Copy link
Copy Markdown

roborev: Combined Review (3d51eb1)

Verdict: Three medium-severity issues require attention; no concrete security issues were identified.

Medium

  • frontend/src/lib/components/detail/PullDetail.svelte:1347-1413 — After refreshing the catalog following a workflow-definition conflict, workflowDialogWorkflow still references the stale workflow object. Retrying resubmits the old definition SHA and inputs, causing another conflict. Rebind it to the refreshed catalog entry by ID and update the form before retry.

  • frontend/src/lib/components/detail/PullDetail.svelte:2952-3031 — The broadened action-surface condition unintentionally restores the workspace action for merged or stale pull requests, where it remains enabled. Independently gate workspace actions on the pull request being neither merged nor stale in both phone and desktop surfaces.

  • internal/github/sync.go:2298-2362; internal/server/httpapi/problems.go:529-590 — GitHub workflow API rate-limit and abuse-limit errors are returned as raw go-github errors, so ProviderCallProblem exposes them as generic 502 responses instead of the expected 429/rate-limited problem. Normalize these errors to platform.Error and add HTTP coverage.


Reviewers: 2 done | Synthesis: codex, 11s | Total: 29m29s

mariusvniekerk and others added 2 commits September 3, 2026 13:00
…-add-workflow-dispatch-and-run-inspection-to-forge
CI could not build the internal/server test package for the workflow
Actions branch, which failed the Go, race, and lint jobs at once. Main
had moved the package-local doJSON test helper into the shared testutil
package in the same window that the branch added two new callers, and
the merge kept both without a compile error until they met in CI.

This merges current main and points the two workflow Actions call sites
at the shared helper. Local Go, lint, and guardrail checks now pass; the
remaining local-only failures are tmux and pty timing tests that pass
when run without competing load.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KuhHYTTk1QzpastWi4zD7T
@roborev-ci

roborev-ci Bot commented Sep 3, 2026

Copy link
Copy Markdown

roborev: Combined Review (9c21349)

Verdict: Medium-severity issue found in workflow catalog error handling.

  • Mediuminternal/github/sync.go:2291: Ordinary HTTP 403 permission failures are treated as per-definition unavailability, producing a misleading partial workflow catalog instead of aborting as documented. Treat non-rate-limit 403 responses as fatal and add a focused catalog test for a 403 gh.ErrorResponse.

Reviewers: 2 done | Synthesis: codex, 6s | Total: 24m22s

…lker

The contributed branch shipped a 400-line hand-written walker over the
YAML node tree to find workflow_dispatch inputs. The maintainer does not
want to own a GitHub Actions grammar in this repository, so this replaces
it with actionlint, which already models the workflow file including
typed dispatch inputs, choice options, defaults, and required flags.

Forge keeps only the projection onto the provider-neutral definition and
the conversion of string defaults into their declared type. actionlint
validates the whole file, so fixtures now carry a jobs section like any
real workflow, and cases the old walker rejected but GitHub accepts (a
boolean-looking string default, a numeric description) are dropped.

go.mod pins actionlint to the fork commit behind rhysd/actionlint#730.
The released v1.7.12 compiles against yaml/v4 rc.3 and fails to build
with the rc.6 already required here; that PR is the upstream fix and the
replace directive should be removed once it lands in a release.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@roborev-ci

roborev-ci Bot commented Sep 3, 2026

Copy link
Copy Markdown

roborev: Combined Review (1fa5282)

Verdict: Changes requested

Medium

  • internal/server/workflowapi/handler.go:17 — Admission allows up to 25 workflow inputs, but GitHub Actions supports at most 10 workflow_dispatch inputs. Requests with 11–25 inputs pass local validation and fail upstream. Enforce the provider limit or expose provider-specific limits through the capability contract, with boundary tests.

  • frontend/src/lib/stores/workflow-actions-workflow.ts:1007-1013 — The cache guard prevents job and step status from refreshing after initial load, leaving expanded active runs stale despite five-second polling. Refresh jobs for expanded active runs or invalidate their cache when the run changes.


Reviewers: 2 done | Synthesis: codex, 7s | Total: 16m28s

The contributed frontend carried a 1,200-line Effect service that polled
workflow runs, queued dispatches per repository, and matched a dispatched
run by actor and time window in the browser. That logic depends on
provider state the server already owns, and a browser tab is the wrong
place to keep it alive.

The dispatch route now returns a dispatch_id and, after the provider
accepts, a server goroutine locates the created run, watches it until it
completes, and publishes workflow_dispatch_progress events over the
existing SSE hub. The browser store shrinks to fetch-on-demand reads plus
an event handler that updates the dispatch cycle and the run list in
place. No workflow polling remains in the frontend.

The workflowapi handler takes a small Runtime interface for publishing
events and running background work instead of function fields. The
"uncertain" outcome no longer shows candidate runs, since the browser
no longer scans runs itself; it tells the user to check the provider.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@roborev-ci

roborev-ci Bot commented Sep 4, 2026

Copy link
Copy Markdown

roborev: Combined Review (d0ae4b0)

Verdict: 1 high-severity and 2 medium-severity findings require attention.

High

  • Repository identity is not stable across workflow state and async progress. Workflow state and progress are correlated only by mutable provider/host/owner/name routes, so route reuse or stale events can apply the wrong repository’s catalog, runs, or dispatch status. Propagate stable repository identity and route-fence/generation data through cache keys, progress events, and follow-up reads, discarding stale follow-through.
    Locations: frontend/src/lib/stores/workflow-actions.svelte.ts:103-109,465-490; internal/server/workflowapi/dispatch_follow.go:91-224

Medium

  • Reloading workflows after a definition conflict does not refresh the dialog workflow. Retrying submits the stale definition SHA and input schema, causing the conflict to repeat. Re-derive or replace workflowDialogWorkflow from the refreshed catalog, or close the dialog if the workflow was removed.
    Location: frontend/src/lib/components/detail/PullDetail.svelte:1345,1407-1410

  • Removed workflows remain selected after a successful catalog refresh. This leaves a dispatch form for a nonexistent workflow visible and submit-able. Clear selectedWorkflow and dependent state when no matching workflow remains.
    Location: frontend/src/lib/stores/workflow-actions.svelte.ts:246-252


Reviewers: 2 done | Synthesis: codex, 10s | Total: 17m20s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Add workflow dispatch and run inspection to Forge

2 participants