Skip to content

feat(dispatch): synchronous workflow_call event dispatch (ADR 41)#1611

Open
ifireball wants to merge 3 commits into
mainfrom
feat/adr-41-sync-dispatch
Open

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

Conversation

@ifireball
Copy link
Copy Markdown
Contributor

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.
  • E2e smoke test polls dispatch.yml completion.

Review fixes (from #1586)

  • Checkout config.yaml from job.workflow_repository (.fullsend), not the enrolled repo.
  • secrets: inherit on the prioritize workflow_call job.
  • Updated architecture.md and retro-analysis skill for the dispatch.yml flow.

Note on secrets: Stage jobs pass ${{ secrets.FULLSEND_* }} from the .fullsend repo context (where dispatch.yml runs after workflow_call from the shim). Enrolled repos do not hold GCP secrets; the shim should not pass them.

Migration

Audience Action
Default orgs After merge, run fullsend admin install <org> to refresh .fullsend scaffold.
Custom # fullsend-stage: workflows Add explicit workflow_call job in dispatch.yml; remove markers.

Test plan

  • go test ./internal/scaffold/... ./internal/layers/...
  • CI including e2e (upstream branch — not a fork PR)

Supersedes closed #1586 (fork head could not run e2e).

Made with Cursor

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 27, 2026

Site preview

Preview: https://40a32e4d-site.fullsend-ai.workers.dev

Commit: bb094581df504a3b1b3c65da0e711db825fc6b00

@fullsend-ai-review
Copy link
Copy Markdown

fullsend-ai-review Bot commented May 27, 2026

Review

Findings

High

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — 7 protected files modified with no linked issue. The PR description explains the rationale (ADR 41 implementation) but protected-path changes require a linked issue for traceability. Human approval is required for all protected-path changes regardless of context.
    Remediation: Link a tracking issue to this PR.

Low

  • [correctness] internal/scaffold/fullsend-repo/skills/code-implementation/SKILL.md — Removed "Verify API contracts per code path" guidance (item 9 from the planning checklist). This advice helped code agents avoid breaking API calls when modifying parameters. Consider preserving this guidance or documenting why it was removed.

Info

  • [correctness] .github/workflows/reusable-dispatch.yml:52 — Good bug fix: the old stage output expression skipped == 'true' && '' || steps.route.outputs.stage always evaluated to stage regardless of skip status due to short-circuit evaluation semantics (true && '''', then '' || stagestage). The corrected expression skipped != 'true' && steps.route.outputs.stage || '' properly returns empty string when the role is skipped.
Previous run

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — Seven protected files are modified. The PR body explains the rationale (ADR 41 synchronous dispatch implementation, concurrency groups moved to reusable workflows, pre-commit ignore for prioritize.yml). Human approval is always required for protected-path changes, regardless of context.

Low

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md — References gh workflow run triage.yml / code.yml / review.yml and per-stage standalone workflows as the dispatch mechanism. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed.
    Remediation: Update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [intent-alignment] internal/scaffold/fullsend-repo/skills/code-implementation/SKILL.md — Step 9 ("Verify API contracts per code path") was removed from the planning checklist, and its corresponding test (TestCodeImplementationSkillAPIContractGuidance) was also removed, confirming this is intentional. If this guidance is now redundant with other checks, no action needed.

  • [prior-finding-resolved] internal/scaffold/fullsend-repo/agents/triage.md — Step 2d ("Review prior triage analysis") has been re-added with full guidance on accumulating findings across triage runs and incorporating human-identified problems. The prior info-level finding about its removal is resolved.

  • [prior-finding-resolved] .github/workflows/reusable-fix.yml — The bot-triggered fix path now fails closed on gh pr view failure (exit 1) instead of silently proceeding with empty defaults. This resolves the prior low-severity finding about fail-open behavior.

  • [prior-finding-resolved] internal/scaffold/fullsend-repo/scripts/pre-code-test.sh — The unquoted for kv in ${extra_env} expansion was reverted to while IFS= read -r kv (space-safe). A new test case (force-override-comment-body) covers the COMMENT_BODY=--force override path.

Previous run (2)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — Seven protected files are modified. The PR body explains the rationale (ADR 41 synchronous dispatch implementation, concurrency groups moved to reusable workflows, pre-commit ignore for prioritize.yml). Human approval is always required for protected-path changes, regardless of context.

Low

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md — References gh workflow run triage.yml / code.yml / review.yml and per-stage standalone workflows as the dispatch mechanism. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed.
    Remediation: Update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [intent-alignment] internal/scaffold/fullsend-repo/agents/triage.md — Step 2d ("Review prior triage analysis") was removed. This section guided the triage agent to accumulate findings across re-runs and incorporate human-identified problems. If this behavior is now handled elsewhere, no action needed; otherwise, triage re-runs may lose previously documented causes.

  • [intent-alignment] internal/scaffold/fullsend-repo/skills/code-implementation/SKILL.md — Step 9 ("Verify API contracts per code path") was removed from the planning checklist. This guidance helped catch issues when code changes affect parameters sent to external APIs. If this was removed intentionally (e.g., redundant with other guidance), no action needed.

  • [prior-finding-resolved] The prioritize.yml workflow_call trigger now correctly declares both FULLSEND_GCP_WIF_PROVIDER and FULLSEND_GCP_PROJECT_ID secrets, matching what dispatch.yml passes explicitly. No runtime failure.

  • [prior-finding-corrected] The low-severity [correctness] finding from the prior review about pre-code-test.sh unquoted expansion was inaccurate — the run_test_stdout function uses while IFS= read -r kv (line 91), which correctly handles values with spaces. No issue exists.

Previous run (3)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — Seven protected files are modified. The PR body explains the rationale (ADR 41 synchronous dispatch implementation, concurrency groups moved to reusable workflows, pre-commit ignore for prioritize.yml). Human approval is always required for protected-path changes, regardless of context.

Low

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md — References gh workflow run triage.yml / code.yml / review.yml and per-stage standalone workflows as the dispatch mechanism. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed.
    Remediation: Update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [intent-alignment] internal/scaffold/fullsend-repo/agents/triage.md — Step 2d ("Review prior triage analysis") was removed. This section guided the triage agent to accumulate findings across re-runs and incorporate human-identified problems. If this behavior is now handled elsewhere, no action needed; otherwise, triage re-runs may lose previously documented causes.

  • [intent-alignment] internal/scaffold/fullsend-repo/skills/code-implementation/SKILL.md — Step 9 ("Verify API contracts per code path") was removed from the planning checklist. This guidance helped catch issues when code changes affect parameters sent to external APIs. If this was removed intentionally (e.g., redundant with other guidance), no action needed.

  • [prior-finding-resolved] The high-severity [correctness] finding from the prior review (prioritize.yml workflow_call trigger missing secrets: declaration) is resolved — the workflow_call trigger now declares both FULLSEND_GCP_WIF_PROVIDER and FULLSEND_GCP_PROJECT_ID secrets.

  • [prior-finding-corrected] The low-severity [correctness] finding from the prior review about pre-code-test.sh unquoted expansion was inaccurate — the run_test_stdout function uses while IFS= read -r kv (line 91), which correctly handles values with spaces. No issue exists.

Previous run (4)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — Seven protected files are modified. The PR body explains the rationale (ADR 41 synchronous dispatch implementation, concurrency groups moved to reusable workflows, pre-commit ignore for prioritize.yml). Human approval is always required for protected-path changes, regardless of context.

Low

  • [correctness] internal/scaffold/fullsend-repo/scripts/pre-code-test.sh:89 — The while IFS= read -r kv loop was replaced with for kv in ${extra_env} (unquoted expansion). The old version preserved env values containing spaces; the new version word-splits on whitespace. Current test cases only use space-free values (CODE_FORCE=true), so this doesn't break existing tests, but it's a latent issue if a future test case adds a value with spaces.
    Remediation: Quote the expansion: for kv in "${extra_env[@]}" if it's an array, or keep the read loop if extra_env is a string.

  • [correctness] .github/workflows/reusable-fix.yml:262 — The bot-triggered fix path now silently proceeds with empty defaults ({"labels":[],"author":""}) when gh pr view fails, instead of hard-failing. Since the dispatch routing already checks the fullsend-no-fix label, this is a reasonable redundancy reduction, but it means the fullsend-no-fix guard in the reusable workflow is bypassed on API failures (fail-open for bot fixes).

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md — References gh workflow run triage.yml / code.yml / review.yml and per-stage standalone workflows as the dispatch mechanism. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed.
    Remediation: Update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [intent-alignment] internal/scaffold/fullsend-repo/agents/triage.md — Step 2d ("Review prior triage analysis") was removed. This section guided the triage agent to accumulate findings across re-runs and incorporate human-identified problems. If this behavior is now handled elsewhere, no action needed; otherwise, triage re-runs may lose previously documented causes.

  • [intent-alignment] internal/scaffold/fullsend-repo/skills/code-implementation/SKILL.md — Step 9 ("Verify API contracts per code path") was removed from the planning checklist. This guidance helped catch issues when code changes affect parameters sent to external APIs. If this was removed intentionally (e.g., redundant with other guidance), no action needed.

  • [prior-finding-resolved] The high-severity [correctness] finding from the prior review (prioritize.yml workflow_call trigger missing secrets: declaration) is resolved — the workflow_call trigger now declares both FULLSEND_GCP_WIF_PROVIDER and FULLSEND_GCP_PROJECT_ID secrets.

Previous run (5)

Review

Findings

High

  • [correctness] internal/scaffold/fullsend-repo/.github/workflows/prioritize.yml:4 — The workflow_call trigger declares inputs: but no secrets: section. However, the prioritize: job in dispatch.yml passes explicit named secrets (FULLSEND_GCP_WIF_PROVIDER, FULLSEND_GCP_PROJECT_ID). GitHub Actions requires called workflows to declare secrets when the caller passes them explicitly (as opposed to secrets: inherit). This will cause the prioritize stage to fail at runtime with an error like the called workflow does not define secret 'FULLSEND_GCP_WIF_PROVIDER'.
    Remediation: Either add a secrets: block to prioritize.yml's workflow_call trigger declaring both secrets, or change the prioritize: job in dispatch.yml to use secrets: inherit instead of explicit secret passing.

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — Seven protected files are modified. The PR body explains the rationale (ADR 41 synchronous dispatch implementation, concurrency groups moved to reusable workflows, pre-commit ignore for prioritize.yml). Human approval is always required for protected-path changes, regardless of context.

Low

  • [correctness] internal/scaffold/fullsend-repo/scripts/pre-code-test.sh:89 — The while IFS= read -r kv loop was replaced with for kv in ${extra_env} (unquoted expansion). The old version preserved env values containing spaces; the new version word-splits on whitespace. Current test cases only use space-free values (CODE_FORCE=true), so this doesn't break existing tests, but it's a latent issue if a future test case adds a value with spaces.
    Remediation: Quote the expansion: for kv in "${extra_env[@]}" if it's an array, or keep the read loop if extra_env is a string.

  • [correctness] .github/workflows/reusable-fix.yml:262 — The bot-triggered fix path now silently proceeds with empty defaults ({"labels":[],"author":""}) when gh pr view fails, instead of hard-failing. Since the dispatch routing already checks the fullsend-no-fix label, this is a reasonable redundancy reduction, but it means the fullsend-no-fix guard in the reusable workflow is bypassed on API failures (fail-open for bot fixes).

Info

  • [intent-alignment] internal/scaffold/fullsend-repo/agents/triage.md — Step 2d ("Review prior triage analysis") was removed. This section guided the triage agent to accumulate findings across re-runs and incorporate human-identified problems. If this behavior is now handled elsewhere, no action needed; otherwise, triage re-runs may lose previously documented causes.

  • [intent-alignment] internal/scaffold/fullsend-repo/skills/code-implementation/SKILL.md — Step 9 ("Verify API contracts per code path") was removed from the planning checklist. This guidance helped catch issues when code changes affect parameters sent to external APIs. If this was removed intentionally (e.g., redundant with other guidance), no action needed.

Previous run (6)

Review

Findings

Medium

  • [correctness] internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml / internal/scaffold/fullsend-repo/.github/workflows/prioritize.yml — The prioritize job in dispatch.yml passes secrets explicitly (FULLSEND_GCP_WIF_PROVIDER, FULLSEND_GCP_PROJECT_ID), but prioritize.yml's new workflow_call: trigger does not declare a secrets: block. GitHub Actions requires called workflows to declare secrets when callers pass them explicitly — this will cause a workflow parse error at runtime when the prioritize stage is triggered. The upstream reusable workflows (reusable-triage.yml, reusable-code.yml, etc.) correctly declare these secrets. The PR body mentions "secrets: inherit on the prioritize workflow_call job" as a review fix, suggesting the intent was to use secrets: inherit on the caller side instead of explicit mapping.
    Remediation: Either add a secrets: block to prioritize.yml's workflow_call: trigger declaring both secrets, or change the dispatch.yml prioritize job to use secrets: inherit instead of explicit secret mapping.

  • [protected-path] .github/workflows/reusable-{code,dispatch,fix,retro,review,triage}.yml, .pre-commit-config.yaml — This PR modifies 7 files under .github/ and .pre-commit-config.yaml. The changes add concurrency groups to reusable workflows (moved from deleted thin callers), update comments for ADR 0041 terminology, fix the role-skip output expression in reusable-dispatch.yml, and add a lint suppression for the prioritize.yml workflow_call reference. Human approval is always required for protected-path changes, regardless of context.

Low

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md:175 — References gh workflow run triage.yml and per-stage standalone workflows as the dispatch mechanism. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed.
    Remediation: Update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [expression-fix] .github/workflows/reusable-dispatch.yml:38 — The stage output expression was corrected from skipped == 'true' && '' || stage (which always evaluated to stage due to short-circuit on falsy empty string) to skipped != 'true' && stage || '' (correctly returns empty when the role is skipped). Good fix — the old expression silently ignored role-skip decisions.

  • [concurrency-parity] .github/workflows/reusable-*.yml — Concurrency groups in the reusable workflows exactly match the groups previously defined in the thin callers they replace (fullsend-{stage}-${{ inputs.source_repo }}-...). Verified all five stage workflows (triage, code, review, fix, retro) have correct group expressions. No behavioral change.

  • [e2e-timestamp-fix] e2e/admin/admin_test.go:253issueCreatedAt is now captured before issue creation rather than after. This is a correctness improvement — the previous placement could miss fast-starting dispatch runs due to the race between time.Now() and the GitHub API call.

Previous run (7)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — Seven protected files are modified. The PR body explains the rationale (ADR 41 synchronous dispatch implementation, concurrency groups moved to reusable workflows, pre-commit ignore for prioritize.yml). Human approval is always required for protected-path changes, regardless of context.

Low

  • [correctness] internal/scaffold/fullsend-repo/scripts/pre-code-test.sh:89 — The while IFS= read -r kv loop was replaced with for kv in ${extra_env} (unquoted expansion). The old version preserved env values containing spaces; the new version word-splits on whitespace. Current test cases only use space-free values (CODE_FORCE=true), so this doesn't break existing tests, but it's a latent issue if a future test case adds a value with spaces.
    Remediation: Quote the expansion: for kv in "${extra_env[@]}" if it's an array, or keep the read loop if extra_env is a string.

  • [correctness] .github/workflows/reusable-fix.yml:262 — The bot-triggered fix path now silently proceeds with empty defaults ({"labels":[],"author":""}) when gh pr view fails, instead of hard-failing. Since the dispatch routing already checks the fullsend-no-fix label, this is a reasonable redundancy reduction, but it means the fullsend-no-fix guard in the reusable workflow is bypassed on API failures (fail-open for bot fixes).

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md — References gh workflow run triage.yml / code.yml / review.yml and per-stage standalone workflows as the dispatch mechanism. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed.
    Remediation: Update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [intent-alignment] internal/scaffold/fullsend-repo/agents/triage.md — Step 2d ("Review prior triage analysis") was removed. This section guided the triage agent to accumulate findings across re-runs and incorporate human-identified problems. If this behavior is now handled elsewhere, no action needed; otherwise, triage re-runs may lose previously documented causes.

  • [intent-alignment] internal/scaffold/fullsend-repo/skills/code-implementation/SKILL.md — Step 9 ("Verify API contracts per code path") was removed from the planning checklist. This guidance helped catch issues when code changes affect parameters sent to external APIs. If this was removed intentionally (e.g., redundant with other guidance), no action needed.

  • [prior-finding-resolved] The high-severity [correctness] finding from the prior review (prioritize.yml workflow_call trigger missing secrets: declaration) is resolved — the workflow_call trigger now declares both FULLSEND_GCP_WIF_PROVIDER and FULLSEND_GCP_PROJECT_ID secrets.

Previous run (8)

Review

Findings

High

  • [correctness] internal/scaffold/fullsend-repo/.github/workflows/prioritize.yml:4 — The workflow_call trigger declares inputs: but no secrets: section. However, the prioritize: job in dispatch.yml passes explicit named secrets (FULLSEND_GCP_WIF_PROVIDER, FULLSEND_GCP_PROJECT_ID). GitHub Actions requires called workflows to declare secrets when the caller passes them explicitly (as opposed to secrets: inherit). This will cause the prioritize stage to fail at runtime with an error like the called workflow does not define secret 'FULLSEND_GCP_WIF_PROVIDER'.
    Remediation: Either add a secrets: block to prioritize.yml's workflow_call trigger declaring both secrets, or change the prioritize: job in dispatch.yml to use secrets: inherit instead of explicit secret passing.

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — Seven protected files are modified. The PR body explains the rationale (ADR 41 synchronous dispatch implementation, concurrency groups moved to reusable workflows, pre-commit ignore for prioritize.yml). Human approval is always required for protected-path changes, regardless of context.

Low

  • [correctness] internal/scaffold/fullsend-repo/scripts/pre-code-test.sh:89 — The while IFS= read -r kv loop was replaced with for kv in ${extra_env} (unquoted expansion). The old version preserved env values containing spaces; the new version word-splits on whitespace. Current test cases only use space-free values (CODE_FORCE=true), so this doesn't break existing tests, but it's a latent issue if a future test case adds a value with spaces.
    Remediation: Quote the expansion: for kv in "${extra_env[@]}" if it's an array, or keep the read loop if extra_env is a string.

  • [correctness] .github/workflows/reusable-fix.yml:262 — The bot-triggered fix path now silently proceeds with empty defaults ({"labels":[],"author":""}) when gh pr view fails, instead of hard-failing. Since the dispatch routing already checks the fullsend-no-fix label, this is a reasonable redundancy reduction, but it means the fullsend-no-fix guard in the reusable workflow is bypassed on API failures (fail-open for bot fixes).

Info

  • [intent-alignment] internal/scaffold/fullsend-repo/agents/triage.md — Step 2d ("Review prior triage analysis") was removed. This section guided the triage agent to accumulate findings across re-runs and incorporate human-identified problems. If this behavior is now handled elsewhere, no action needed; otherwise, triage re-runs may lose previously documented causes.

  • [intent-alignment] internal/scaffold/fullsend-repo/skills/code-implementation/SKILL.md — Step 9 ("Verify API contracts per code path") was removed from the planning checklist. This guidance helped catch issues when code changes affect parameters sent to external APIs. If this was removed intentionally (e.g., redundant with other guidance), no action needed.

Previous run (9)

Review

Findings

Medium

  • [correctness] internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml / internal/scaffold/fullsend-repo/.github/workflows/prioritize.yml — The prioritize job in dispatch.yml passes secrets explicitly (FULLSEND_GCP_WIF_PROVIDER, FULLSEND_GCP_PROJECT_ID), but prioritize.yml's new workflow_call: trigger does not declare a secrets: block. GitHub Actions requires called workflows to declare secrets when callers pass them explicitly — this will cause a workflow parse error at runtime when the prioritize stage is triggered. The upstream reusable workflows (reusable-triage.yml, reusable-code.yml, etc.) correctly declare these secrets. The PR body mentions "secrets: inherit on the prioritize workflow_call job" as a review fix, suggesting the intent was to use secrets: inherit on the caller side instead of explicit mapping.
    Remediation: Either add a secrets: block to prioritize.yml's workflow_call: trigger declaring both secrets, or change the dispatch.yml prioritize job to use secrets: inherit instead of explicit secret mapping.

  • [protected-path] .github/workflows/reusable-{code,dispatch,fix,retro,review,triage}.yml, .pre-commit-config.yaml — This PR modifies 7 files under .github/ and .pre-commit-config.yaml. The changes add concurrency groups to reusable workflows (moved from deleted thin callers), update comments for ADR 0041 terminology, fix the role-skip output expression in reusable-dispatch.yml, and add a lint suppression for the prioritize.yml workflow_call reference. Human approval is always required for protected-path changes, regardless of context.

Low

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md:175 — References gh workflow run triage.yml and per-stage standalone workflows as the dispatch mechanism. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed.
    Remediation: Update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [expression-fix] .github/workflows/reusable-dispatch.yml:38 — The stage output expression was corrected from skipped == 'true' && '' || stage (which always evaluated to stage due to short-circuit on falsy empty string) to skipped != 'true' && stage || '' (correctly returns empty when the role is skipped). Good fix — the old expression silently ignored role-skip decisions.

  • [concurrency-parity] .github/workflows/reusable-*.yml — Concurrency groups in the reusable workflows exactly match the groups previously defined in the thin callers they replace (fullsend-{stage}-${{ inputs.source_repo }}-...). Verified all five stage workflows (triage, code, review, fix, retro) have correct group expressions. No behavioral change.

  • [e2e-timestamp-fix] e2e/admin/admin_test.go:253issueCreatedAt is now captured before issue creation rather than after. This is a correctness improvement — the previous placement could miss fast-starting dispatch runs due to the race between time.Now() and the GitHub API call.

Previous run (10)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-{code,dispatch,fix,retro,review,triage}.yml, .pre-commit-config.yaml — This PR modifies 7 files under .github/ and .pre-commit-config.yaml. The changes add concurrency groups to reusable workflows (moved from deleted thin callers), update comments for ADR 0041 terminology, and add a lint suppression for the prioritize.yml workflow_call reference. Human approval is always required for protected-path changes, regardless of context.

Low

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md:175 — References gh workflow run triage.yml and per-stage dispatch-* jobs as the dispatch mechanism, describing standalone stage workflows as separate dispatch targets. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed. Remediation: update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [concurrency-parity] .github/workflows/reusable-*.yml — Concurrency groups in the reusable workflows exactly match the groups previously defined in the thin callers they replace (fullsend-{stage}-${{ inputs.source_repo }}-...). Verified all five stage workflows (triage, code, review, fix, retro) have identical group expressions. No behavioral change.

  • [e2e-timestamp-fix] e2e/admin/admin_test.go:253issueCreatedAt is now captured before issue creation rather than after. This is a correctness improvement — the previous placement could miss fast-starting dispatch runs due to the race between time.Now() and the GitHub API call. Good fix.

Previous run (11)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-{code,dispatch,fix,retro,review,triage}.yml, .pre-commit-config.yaml — This PR modifies 7 files under .github/ and .pre-commit-config.yaml. The changes add concurrency groups to reusable workflows (moved from deleted thin callers) and update comments and lint suppression rules. The PR links to ADR 41 and explains the rationale (synchronous workflow_call dispatch replacing gh workflow run). Human approval is always required for protected-path changes, regardless of context.

Info

  • [concurrency-parity] .github/workflows/reusable-*.yml — Concurrency groups in the reusable workflows exactly match the groups previously defined in the thin callers they replace (fullsend-{stage}-${{ inputs.source_repo }}-...). Verified all five stage workflows (triage, code, review, fix, retro) have identical group expressions. No behavioral change.

  • [e2e-timestamp-fix] e2e/admin/admin_test.go:253issueCreatedAt is now captured before issue creation rather than after. This is a correctness improvement — the previous placement could miss fast-starting dispatch runs due to the race between time.Now() and the GitHub API call. Good fix.

Previous run (12)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — This PR modifies protected governance/infrastructure files. The changes are well-justified by ADR 0041 (adding concurrency groups to reusable workflows, updating comments, adding lint-ignore for prioritize.yml workflow_call), but human approval is always required for protected-path changes regardless of context.

Low

  • [documentation-currency] docs/superpowers/specs/2026-04-17-installer-agent-content-design.md:175 — References gh workflow run triage.yml, gh workflow run code.yml, and gh workflow run review.yml as the dispatch mechanism, and describes standalone stage workflows as separate dispatch targets. After ADR 0041, dispatch.yml routes directly to upstream reusable workflows via synchronous workflow_call jobs; standalone stage workflows and gh workflow run are removed. Remediation: update the dispatch mechanism description and scaffold layout to reflect the new direct workflow_call pattern.

Info

  • [prior-findings-resolved] The four documentation-currency findings from the prior review (on docs/architecture.md:42, docs/architecture.md:46, internal/layers/workflows.go:32, .github/workflows/reusable-dispatch.yml:4) are all resolved by the latest commit — the stale "thin caller" and "dispatch workflow mints OIDC tokens" references have been updated to describe the new synchronous workflow_call pattern.
Previous run (13)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml, .pre-commit-config.yaml — This PR modifies protected governance/infrastructure files. The changes are well-justified (ADR 41 implementation: adding concurrency groups to reusable workflows, updating pre-commit ignore patterns), but human approval is always required for protected-path changes regardless of context.

Low

  • [documentation-currency] docs/architecture.md:42 — Line 42 still references "dispatch workflow mints OIDC tokens exchanged at a central token mint... for scoped GitHub App installation tokens per agent role." This description is now stale: the new dispatch.yml no longer mints OIDC tokens — token minting happens inside each reusable workflow's own mint-token action step.

  • [documentation-currency] docs/architecture.md:46 — Line 46 still describes agent workflows as "thin callers (~40-70 lines) that delegate infrastructure logic to upstream reusable workflows." After this PR, thin callers are removed; dispatch.yml calls upstream reusable workflows directly via workflow_call jobs. This line should reference the new dispatch-to-reusable pattern and cite ADR 0041.

  • [documentation-currency] internal/layers/workflows.go:32 — Comment says "It writes the thin caller workflows" but the layer no longer writes thin caller workflows (they were removed). The comment should reference the current scaffold contents (dispatch.yml, prioritize.yml, repo-maintenance.yml, etc.).

  • [documentation-currency] .github/workflows/reusable-dispatch.yml:4 — Comment describes itself as "the per-repo equivalent of the per-org dispatch.yml + thin caller pair." After this PR, per-org dispatch.yml also uses direct workflow_call jobs (same pattern as reusable-dispatch.yml), so the "thin caller pair" comparison is stale.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label May 27, 2026
@ifireball ifireball requested review from ggallen, ralphbean, rh-hemartin and waynesun09 and removed request for ralphbean and waynesun09 May 27, 2026 17:44
ifireball added a commit to ifireball/fullsend that referenced this pull request May 27, 2026
Update stale references to thin callers and per-org OIDC minting in
dispatch.yml; address review feedback on PR fullsend-ai#1611.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels May 27, 2026
@waynesun09
Copy link
Copy Markdown
Contributor

HIGH — Missing fixcoder role mapping in per-org dispatch.yml

internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml:235:

code) STAGE_ROLE="coder" ;;

Compare with reusable-dispatch.yml:265 which correctly maps both:

code|fix) STAGE_ROLE="coder" ;;

When a /fix command runs in per-org mode, STAGE_ROLE stays as "fix", which isn't a valid role in config.yaml. If roles are configured, the fix stage is incorrectly skipped with "role 'fix' not in defaults.roles".

(This line isn't in the PR diff — it's existing code that was carried forward without the fix that reusable-dispatch.yml has.)


HIGH — Same ternary kill-switch bug exists in reusable-dispatch.yml:52

stage: ${{ steps.role-check.outputs.skipped == 'true' && '' || steps.route.outputs.stage }}

Same && '' || issue as the per-org dispatch.yml:28 (see inline review comment there). Empty string is falsy in GHA expressions, so the role-check skip never takes effect. This affects per-repo mode as well.

Suggestion:

stage: ${{ steps.role-check.outputs.skipped != 'true' && steps.route.outputs.stage || '' }}

Copy link
Copy Markdown
Contributor

@waynesun09 waynesun09 left a comment

Choose a reason for hiding this comment

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

Review Squad — 10-agent deep-dive on mint/OIDC impact

1 CRITICAL, 3 HIGH, 3 MEDIUM findings (see inline comments + PR comment for items on unchanged lines).

The central issue: permissions: {} at workflow level in the per-org dispatch.yml scaffold blocks id-token: write from propagating to stage jobs, which breaks OIDC token minting in all reusable workflows. The old flow worked because thin callers were independent workflow runs with their own permission grants — this PR inlines them as jobs under dispatch.yml's permissions: {} umbrella.

Additional issues: ternary expression bug defeats the role-check kill switch (both per-org and per-repo), fix role mapping is missing in per-org, and secrets: inherit on prioritize is inconsistent with other stages.

Comment thread internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml
Comment thread internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml Outdated
Comment thread internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml Outdated
Comment thread .github/workflows/reusable-fix.yml
Comment thread e2e/admin/admin_test.go Outdated
ifireball added a commit to ifireball/fullsend that referenced this pull request May 28, 2026
Update stale references to thin callers and per-org OIDC minting in
dispatch.yml; address review feedback on PR fullsend-ai#1611.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 21e5e0f)
@ifireball ifireball force-pushed the feat/adr-41-sync-dispatch branch from 034b8cb to 3df8b3d Compare May 28, 2026 07:10
@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels May 28, 2026
@ifireball
Copy link
Copy Markdown
Contributor Author

Addressed review feedback from @waynesun09:

  • Caller permissions: stage jobs in per-org dispatch.yml now explicitly set permissions: { contents: read, id-token: write }, so reusable workflows can mint OIDC tokens.
  • Role-check kill switch: fixed the && '' || expression (empty string is falsy) in both per-org dispatch.yml and per-repo reusable-dispatch.yml.
  • Role mapping: per-org dispatch now maps fix stage to coder role (code|fix → coder) for defaults.roles gating.
  • Secrets: removed secrets: inherit from prioritize and pass explicit FULLSEND_GCP_* secrets for consistency.

Commit: 0c831c67

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels May 28, 2026
@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels May 28, 2026
@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label May 28, 2026
@ifireball
Copy link
Copy Markdown
Contributor Author

Rebased onto main with a 3-commit history (force-pushed to fullsend-ai/fullsend):

  1. feat(dispatch): synchronous workflow_call event dispatch (ADR 41) — scaffold dispatch, thin workflow removal, reusables concurrency, tests/skills (no ADR file edits).
  2. docs: align architecture and comments with ADR 41 dispatchdocs/architecture.md, workflow comments, retro skill.
  3. fix(dispatch): address review feedback on workflow_call dispatch — per-stage OIDC permissions, kill-switch ternary, explicit GCP secrets (incl. prioritize.yml workflow_call.secrets), e2e issueCreatedAt before issue create, fixcoder role mapping.

Resolved the review threads for permissions, ternary, secrets: inherit, and prioritize secret declarations.

e2e failed again on org-pool lock acquisition (422 Repository creation failed on halfsend-01/halfsend-02 for 10m) — test never reached the dispatch smoke. Other checks are green. Happy to re-run e2e once the pool is healthy; I did not change the harness per babysit scope.

@waynesun09 please take another look when you have a moment.

Copy link
Copy Markdown
Contributor

@waynesun09 waynesun09 left a comment

Choose a reason for hiding this comment

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

All CRITICAL/HIGH findings from the prior review are confirmed fixed in 1f26c872. LGTM — one minor doc cleanup remaining (see inline comment).

@waynesun09
Copy link
Copy Markdown
Contributor

[MEDIUM] Stale workflow references in finding-agent-runs/SKILL.md

internal/scaffold/fullsend-repo/skills/finding-agent-runs/SKILL.md lines 84 and 102 still reference review.yml and retro.yml as standalone workflows:

gh run list --repo "${DISPATCH_REPO}" --workflow=review.yml --limit 5 \
gh run list --repo "${DISPATCH_REPO}" --workflow=retro.yml --limit 5 \

The PR correctly removed triage.yml and code.yml references from this file but missed these two. Since the standalone stage workflows no longer exist (everything routes through dispatch.yml), these gh run list commands will return no results for agents using this skill.

Suggestion: Update both lines to query dispatch.yml with appropriate --jq filters for the review/retro stages, consistent with how the triage and code references were already updated earlier in the file.

@ifireball ifireball force-pushed the feat/adr-41-sync-dispatch branch from 1f26c87 to 1a31cc2 Compare May 28, 2026 18:10
@ifireball
Copy link
Copy Markdown
Contributor Author

Follow-up on the latest review comments (@waynesun09):

  • finding-agent-runs SKILL: review.yml / retro.ymldispatch.yml (thin workflows removed).
  • reusable-dispatch prioritize: added prioritize job calling ./.fullsend/.github/workflows/prioritize.yml (per-repo install path).
  • fix → coder mapping: already in per-org dispatch.yml (code|fix) STAGE_ROLE="coder").
  • reusable-fix bot eligibility: restored fail-closed on gh pr view errors (reverted accidental fail-open from concurrency port).
  • pre-code-test.sh: restored while read extra_env parsing in both helpers.

Rebased onto main (includes #1612 e2e org-pool fixes). Still 3 commits; HEAD 1a31cc2d.

Deferred without code change (mitigations documented in threads):

  • fromJSON in reusable concurrency groups — payload validated in route before dispatch.
  • e2e polls dispatch.yml + verifies triage comment (sync workflow_call makes dispatch failure surface stage errors).

Copy link
Copy Markdown
Contributor

@ralphbean ralphbean left a comment

Choose a reason for hiding this comment

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

A couple things to fix before merge. See inline comments.

Comment thread internal/scaffold/fullsend-repo/scripts/pre-code.sh
Comment thread internal/scaffold/fullsend-repo/agents/triage.md
@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels May 28, 2026
@ifireball
Copy link
Copy Markdown
Contributor Author

@ralphbean — addressed your inline comments in f7bf57e8:

e2e / @v0: latest run gets past org-pool and install, but the shim fails with startup_failure because scaffolded dispatch.yml calls reusable-*.yml@v0 while this PR’s reusable workflow changes are not on the v0 tag yet. Per #1075 and the in-flight #1278 (fullsend_ai_ref + docs/guides/dev/testing-workflows.md), the right fix is to pin e2e at the PR branch ref — not to duplicate that work here. Planning to re-run e2e after #1278 lands (or merge/rebase #1278 into this branch if you prefer stacking).

Other checks green on this push.

@ifireball ifireball force-pushed the feat/adr-41-sync-dispatch branch from 70b0280 to f7bf57e Compare May 28, 2026 20:16
@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels May 28, 2026
ifireball and others added 3 commits May 28, 2026 23:28
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. Update unit tests and e2e smoke test to poll dispatch.yml.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Update stale references to thin callers and per-org OIDC minting in
dispatch.yml; align retro-analysis skill and layer comments with the
synchronous workflow_call pattern.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
- Per-org stage jobs: explicit OIDC permissions; kill-switch ternary fix
- Role mapping: code|fix → coder; prioritize workflow_call secrets
- Per-repo reusable-dispatch: prioritize job via .fullsend/prioritize.yml
- finding-agent-runs skill: dispatch.yml instead of removed thin workflows
- reusable-fix: fail closed when gh pr view fails (bot eligibility)
- pre-code-test: restore line-by-line extra_env parsing
- e2e: capture issueCreatedAt before issue creation

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown

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

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.

pull-requests: read
outputs:
stage: ${{ steps.role-check.outputs.skipped == 'true' && '' || steps.route.outputs.stage }}
stage: ${{ steps.role-check.outputs.skipped != 'true' && steps.route.outputs.stage || '' }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[info] correctness

Good bug fix: the old stage output expression always evaluated to stage regardless of skip status. The corrected expression properly returns empty string when the role is skipped.

@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label May 28, 2026
Copy link
Copy Markdown
Contributor

@ralphbean ralphbean left a comment

Choose a reason for hiding this comment

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

A couple things to address. See inline comments.

--json databaseId,status,conclusion,createdAt

gh run list --repo "${DISPATCH_REPO}" --workflow=code.yml --limit 5 \
gh run list --repo "${DISPATCH_REPO}" --workflow=dispatch.yml --limit 5 \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[important] With synchronous workflow_call, there are no separate dispatch.yml runs in .fullsend -- the whole chain (shim -> dispatch -> stage) is one run in the enrolled repo. The triage and code sections above get this right (gh run view <RUN_ID> --json jobs on the shim run), but from here down -- "Find the actual agent run", review, retro, and "Logs and artifacts" -- we're still pointing agents at ${DISPATCH_REPO} for runs that won't exist there.

The e2e test in this PR was updated to poll fullsend.yaml in the enrolled repo, so we already know this is the right model. Could we update these sections to match? Same issue in retro-analysis/SKILL.md.

test each code path that uses the function. Different operations
(e.g., approve vs request-changes) often have different required fields.

When requirements are ambiguous, distinguish between "vague but actionable"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[moderate] This removes the "Verify API contracts per code path" checklist item, which doesn't seem related to ADR 41. Rebase artifact? It's caught real bugs before (different API operations having different required fields), so I think we should keep it.

@ralphbean
Copy link
Copy Markdown
Contributor

FWIW - I don't want to hold this up. If you can address those things feel free to merge when you're back at keyboard. You can dismiss my review via the API. :)

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.

3 participants