Skip to content

feat(dispatch): synchronous workflow_call event dispatch (ADR 41) - #1586

Closed
ifireball wants to merge 3 commits into
fullsend-ai:mainfrom
ifireball:feat/adr-41-sync-dispatch
Closed

feat(dispatch): synchronous workflow_call event dispatch (ADR 41)#1586
ifireball wants to merge 3 commits into
fullsend-ai:mainfrom
ifireball:feat/adr-41-sync-dispatch

Conversation

@ifireball

Copy link
Copy Markdown
Member

Summary

  • Implements ADR 41: per-org event path is shim → dispatch.ymlreusable-*.yml@v0 (synchronous workflow_call), replacing # fullsend-stage: scanning and gh workflow run.
  • Removes thin stage workflows from scaffold; prioritize.yml gains workflow_call.
  • Ports per-stage concurrency into upstream reusable workflows (per-org parity + per-repo improvement).
  • E2e smoke test polls dispatch.yml completion.

Migration

Audience Action
Default orgs After merge, run fullsend admin install <org> to refresh .fullsend scaffold. No enrolled-repo shim changes.
Custom # fullsend-stage: workflows Add explicit workflow_call job in dispatch.yml; remove markers.
Fan-out (multiple workflows per stage) Consolidate to one job per stage.

Test plan

  • go test ./internal/scaffold/... ./internal/layers/...
  • CI on this PR

Closes the mistaken fork-only PR: ifireball#14

Made with Cursor

@github-actions

Copy link
Copy Markdown

Site preview

Preview: https://793c5b0d-site.fullsend-ai.workers.dev

Commit: 10b23eac0fb907a20eda8a379d7d5c5020c3cd3f

@ifireball

ifireball commented May 27, 2026

Copy link
Copy Markdown
Member Author

@ralphbean @waynesun09 is there some trick to getting the e2e tests to run for the PR, I think we probably want them running for this

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

High

  • [correctness] internal/scaffold/fullsend-repo/.github/workflows/dispatch.ymlSecrets chain broken in workflow_call transition. The shim template (shim-workflow-call.yaml) calls dispatch.yml without passing secrets or using secrets: inherit. In the old async model, dispatch.yml minted its own OIDC token and the thin stage workflows ran as separate workflow_dispatch runs with their own secrets context from .fullsend. In the new synchronous model, dispatch.yml passes ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }} and ${{ secrets.FULLSEND_GCP_PROJECT_ID }} to the reusable workflows — but dispatch.yml itself has no secrets (the shim doesn't pass them, and dispatch.yml's on.workflow_call doesn't declare a secrets: section). These expressions resolve to empty strings. Since the reusable workflows declare these as required: true, agent dispatch would fail after scaffold refresh.
    Remediation: Either (a) add secrets: inherit to the shim's dispatch job and to dispatch.yml's workflow_call jobs, or (b) declare the secrets in dispatch.yml's on.workflow_call.secrets section and have the shim pass them explicitly. Option (a) is simpler but passes all org secrets through the chain; option (b) is explicit.

  • [correctness] internal/scaffold/fullsend-repo/.github/workflows/dispatch.ymlRoute job checkout targets wrong repository. The new Checkout config repository step uses actions/checkout@v6 without specifying repository:. In a workflow_call context, actions/checkout defaults to github.repository, which is the enrolled repo (the top-level caller). The config.yaml file is in the .fullsend repo. The old code used repository: ${{ job.workflow_repository }} with the minted token. Without this, yq '.kill_switch // false' config.yaml would fail (file not found under set -euo pipefail), breaking all dispatch. Additionally, github.token may not have contents: read on the .fullsend repo — the old code used the OIDC-minted token for cross-repo checkout.
    Remediation: Add repository: ${{ job.workflow_repository }} to the checkout step. For the token, either keep a lightweight OIDC mint in the route job for config checkout, or investigate whether github.token has cross-repo read access in this workflow_call chain (test empirically — the docs are ambiguous on this edge case).

  • [correctness] internal/scaffold/fullsend-repo/.github/workflows/dispatch.ymlPrioritize job missing secrets: block. The prioritize job calls ./.github/workflows/prioritize.yml via workflow_call but doesn't pass secrets: or use secrets: inherit. The prioritize.yml workflow directly references secrets.FULLSEND_GCP_WIF_PROVIDER and secrets.FULLSEND_GCP_PROJECT_ID for GCP authentication. Without secrets propagation, these resolve to empty strings and the prioritize agent cannot mint tokens.
    Remediation: Add secrets: inherit to the prioritize job, or explicitly pass the required secrets.

Medium

  • [protected-path] .github/workflows/reusable-*.yml, .pre-commit-config.yaml — This PR modifies 6 protected-path files (5 reusable workflow files and .pre-commit-config.yaml). The PR references ADR 41 which provides architectural justification for the changes. Human approval is always required for protected-path changes regardless of context.

Low

  • [docs-currency] internal/scaffold/fullsend-repo/skills/retro-analysis/SKILL.md — Still references old thin stage workflow names (triage.yml, code.yml, review.yml, fix.yml) for gh run list commands. After this PR, all agent runs go through dispatch.yml. These commands would return no results.
    Remediation: Update the gh run list commands to use --workflow=dispatch.yml, similar to the update already made in finding-agent-runs/SKILL.md.

  • [docs-currency] docs/architecture.md — References the old dispatch model: "Dispatches per-role agent workflows (code.yml, triage.yml)" and "AGENT WORKFLOW (.fullsend repo, e.g. code.yml)". These descriptions are stale with the new synchronous workflow_call model where dispatch.yml is the single workflow.
    Remediation: Update the architecture diagram text to reflect the new dispatch.yml → reusable-*.yml flow.

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

@waynesun09

Copy link
Copy Markdown
Member

@ifireball fork PR not supported for the e2e, create a new PR from the repo branch to trigger it

ifireball and others added 3 commits May 27, 2026 20:30
Replace per-org dispatch marker scan and gh workflow run with static
workflow_call jobs to upstream reusable workflows. Remove thin stage
workflows from scaffold; add workflow_call to prioritize.yml.

Port per-stage concurrency from removed thin callers into reusable
workflows so per-org behavior is preserved and per-repo mode gains
cancel-in-progress per stage.

Update unit tests and e2e smoke test to poll dispatch.yml completion.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…_call

actionlint resolves ./.github/workflows/prioritize.yml from repo root;
the file exists only under internal/scaffold after install to .fullsend.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…e secrets

- Checkout config.yaml from job.workflow_repository (not enrolled repo).
- Pass secrets: inherit into prioritize workflow_call job.
- Update architecture.md and retro-analysis skill for dispatch.yml flow.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@ifireball
ifireball force-pushed the feat/adr-41-sync-dispatch branch from 10b23ea to 5b1aeed Compare May 27, 2026 17:30
@ifireball

Copy link
Copy Markdown
Member Author

Closing in favor of an upstream-branch PR so E2E can run (fork PRs skip e2e secrets). Follow-up: will open a new PR from fullsend-ai/fullsend:feat/adr-41-sync-dispatch.

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.

2 participants