feat(#6347): add pre-computed matrix input to reusable-dispatch - #6455
Conversation
Enable custom pollers in external repos to invoke harness agents directly by providing a pre-computed matrix, bypassing the routing and dispatch steps. Changes: - Add optional `matrix` input to reusable-dispatch.yml - Skip route and harness-dispatch jobs when matrix is provided - Update harness-run to use either computed or provided matrix - Make event_action optional when matrix is provided - Add documentation and example workflow for custom pollers This approach maintains ADR 62's inlining decision while enabling workflow reuse for custom polling use cases. Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
PR Summary by QodoAdd optional pre-computed matrix input to reusable-dispatch harness flow
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
|
🤖 Finished Review · ✅ Success · Started 5:01 PM UTC · Completed 5:19 PM UTC Commit: |
Site previewPreview: https://3f930288-site.fullsend-ai.workers.dev Commit: |
Code Review by Qodo
1.
|
ReviewFindingsHigh
Medium
Low
Next steps:
Previous runReviewFindingsHigh
Medium
Low
Next steps:
Previous run (2)ReviewFindingsCritical
High
Medium
Low
Next steps:
Previous run (3)ReviewFindingsCritical
Medium
Low
Next steps:
Previous run (4)ReviewFindingsCritical
Medium
Low
Next steps:
|
|
🤖 Finished Fix · ❌ Failure · Started 5:21 PM UTC · Completed 5:28 PM UTC Commit: |
|
The fix agent completed, but the post-fix script failed before finishing. Workflow run: https://github.com/fullsend-ai/fullsend/actions/runs/32507571645 Details: Please check the workflow logs for full details and retry with |
Add optional JIRA_TOKEN, JIRA_USER_EMAIL secrets and jira_base_url input to reusable-dispatch.yml to support Jira-based harness agents. These are passed through to the harness-run job's environment, enabling Jira agents to authenticate and interact with Jira Cloud instances. JIRA_BASE_URL falls back to vars.JIRA_BASE_URL from the caller's context if not explicitly provided as an input, following the pattern used for OTEL variables. Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 5:31 PM UTC · Completed 6:13 PM UTC Commit: |
|
🤖 Finished Fix · ❌ Failure · Started 6:15 PM UTC · Completed 6:24 PM UTC Commit: |
|
The fix agent completed, but the post-fix script failed before finishing. Workflow run: https://github.com/fullsend-ai/fullsend/actions/runs/32512193758 Details: Please check the workflow logs for full details and retry with |
Update jira-integration.md to use the new reusable-dispatch.yml with pre-computed matrix input instead of the old manual gh workflow run approach. Update custom-poller-example.md to: - Use top-level permissions block (required for reusable workflow calls) - Include all required permissions (contents: write, packages: read) - Add jira_base_url input to harness job - Show complete poll job implementation with matrix building - Add permissions explanation section These docs now accurately reflect the new approach from PR #6455. Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Review · Commit: |
- Remove broken stage=='harness' checks from harness-dispatch and harness-run (route never outputs 'harness', breaking all existing callers) - Fix actionlint error by inlining if condition (remove block scalar) - Add event_action validation when matrix is not provided - Fix concurrency key to use matrix.status_repo instead of github.repository (prevents cross-repo cancellation in custom poller scenarios) Resolves critical review feedback from fullsend-ai-review and qodo-code-review. Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
- Add guide to docs/guides/README.md index (user guides section) - Rename "Required Configuration" to "Prerequisites" for consistency - Link jargon to glossary (harness, OTEL/OTLP) and external docs (matrix) - Add architectural references (architecture.md, mint-administration.md) - Define WIF inline (not in glossary yet) Addresses review feedback from qodo-code-review. Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 8:12 PM UTC · Completed 8:55 PM UTC Commit: |
waynesun09
left a comment
There was a problem hiding this comment.
Approving at head 9a497f92 — the design is sound and CI is fully green (behaviour, e2e, test, build, codecov/patch). One change requested below that I'd like to see before or shortly after merge; keeping it in the review body rather than an inline thread so it doesn't sit as a merge blocker.
Requested change — make the event_action validation actually gate
event_action went from required: true to required: false, default: "", which moved the contract from GitHub's own workflow_call validation (the call was refused before any job ran) to a runtime step inside route. That step currently gates nothing:
harness-dispatchhas noneeds: route— deliberately removed inf2adaa56because route never outputsstage.harness-rundeclaresneeds: [route, harness-dispatch]but guards withif: !cancelled() && .... A failed route is not a cancelled one, so it does not stop the job — andharness-runnever readsneeds.routeat all, so route is a pure ordering edge with no effect.fullsend dispatch --event-action ""does not fail either:internal/harnessdispatch/input/ghaevent.go:69-72silently falls back toraw["action"]from the event payload.
So if a caller omits both matrix and event_action, route red-Xes, harness-dispatch still computes a real matrix from the payload fallback, and the agents run anyway. The net effect is a decorative failed job plus the loss of a previously hard contract. Either validating in harness-dispatch (which is the job that actually consumes event_action), or requiring route success on the non-matrix branch, would restore it.
On the security surface — checked, and it holds
Recording the reasoning since caller-supplied matrices look alarming at first read. The matrix controls matrix.role and matrix.source_repo, and harness-run feeds the bare name of source_repo to the mint as repos. The mint is the real authority and it binds it: internal/mintcore/repos_scope.go:93-99 allows a per-repo caller only its own bare repo name, returning errPerRepoCrossRepo → 403 otherwise, with the foreign-grant path at handler.go:310 explicitly config-gated. A forged source_repo therefore either 403s at the mint or yields a token scoped to the caller's own repo that fails at target checkout. Worth saying explicitly in the workflow comments that the safety of this input rests entirely on mint enforcement — the workflow itself trusts matrix.source_repo completely. (Org-mode .fullsend callers are deliberately more permissive, but the documented custom-poller path is per-repo, so that's fine.)
Smaller notes, none blocking
- Malformed
matrixJSON errors theif:expression at the workflow level rather than failing cleanly — ugly, not unsafe. - The
'{"include":[]}'fallback added in9a497f92looks unreachable, since theif:guard rejects an empty/null include first. Harmless belt-and-braces. - The Jira secrets and
jira_base_url(61160a46) are unrelated to #6347 — fine to land together, just noting the bundling. - Verified there's no stale-output hazard from
!cancelled():harness-dispatch's matrix output is set by its last step, so a failed job cannot leave a usable matrix behind. - Concurrency group gaining
github.repository+matrix.status_repois right for external pollers targeting other repos.
Worth remembering on merge: the agents repo consumes this file at @main (fullsend-ai/agents#874), so this dogfoods immediately rather than at the next v0 cut. That's the intent, and it's why green behaviour/e2e on this PR carries more weight than usual.
|
🤖 Finished Fix · ❌ Failure · Started 8:57 PM UTC · Completed 9:07 PM UTC Commit: |
…route dependency - Add validation step to harness-dispatch that fails fast if event_action is empty when matrix is not provided - Remove route from harness-run needs since it never uses route outputs Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Review · ❌ Terminated · Started 9:07 PM UTC · Ended 9:26 PM UTC Commit: |
|
The fix agent completed, but the post-fix script failed before finishing. Workflow run: https://github.com/fullsend-ai/fullsend/actions/runs/32525978903 Details: |
There was a problem hiding this comment.
See the review comment for full details.
Note: The following inline comments could not be posted on the diff (GitHub returned 422) and are included here instead:
.github/workflows/reusable-dispatch.yml:1550: [medium] edge-case
When a caller provides the matrix input, fromJSON(inputs.matrix) is called in both the if condition and strategy.matrix expression without prior validation. Syntactically invalid JSON produces an opaque GHA expression evaluation error. No validation step exists for the matrix input's structure or required fields.
Suggested fix: Add a validation job or step that runs when inputs.matrix != '' to validate the JSON parses correctly and contains the expected include array with required fields (agent, role, source_repo, event_payload, status_repo, status_number).
docs/guides/user/jira-integration.md(file-level): Line 255 · [medium] stale-doc
The 'Dry-run tip' section references the removed 'Dispatch agent workflows' step and 'gh workflow run', which no longer exist after this PR replaces the per-dispatch loop with a matrix-based approach.
Suggested fix: Rewrite the Dry-run tip to reference the new flow (e.g., 'run the poll step locally and inspect dispatches.json').
docs/guides/user/jira-integration.md(file-level): Line 263 · [medium] stale-doc
The 'Dispatch record format' section describes records as 'execution refs compatible with the workflow_call shim' dispatched individually via gh workflow run. They are now consumed as matrix entries via the matrix input.
Suggested fix: Update the description to clarify records are matrix entries matching the fullsend dispatch --output-driver gha-matrix format.
.github/workflows/reusable-dispatch.yml:1550: [low] edge-case
!cancelled() in harness-run's if condition is more permissive than needed. !failure() would achieve the same result while gating out the failure case at the status-check level rather than relying on expression short-circuit behavior.
Suggested fix: Replace !cancelled() with !failure().
.github/workflows/reusable-dispatch.yml:1553: [low] api-contract
The concurrency group now includes matrix.status_repo. If fullsend dispatch --output-driver gha-matrix does not always populate status_repo, the concurrency key changes, potentially breaking cancel-in-progress for existing dispatches.
Suggested fix: Verify fullsend dispatch always includes status_repo, or use a fallback: matrix.status_repo || github.repository.
|
🤖 Finished Review · ✅ Success · Started 9:07 PM UTC · Completed 9:26 PM UTC Commit: |
|
🤖 Finished Fix · ❌ Failure · Started 9:28 PM UTC · Completed 9:38 PM UTC Commit: |
|
The fix agent completed, but the post-fix script failed before finishing.
Workflow run: https://github.com/fullsend-ai/fullsend/actions/runs/32528536737 Details: |
|
🤖 Finished Retro · ✅ Success · Started 4:37 PM UTC · Completed 4:52 PM UTC Commit: Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $4.78 |
Retro: PR #6455 — Add pre-computed matrix input to reusable-dispatchTimelineHuman-authored PR by
What went well
What didn't go well5 fix agent runs, all failed, zero value delivered. This is the headline finding. Failure breakdown:
Evidence for existing issues
Autonomy observationsThe review agent matched human review on detecting the critical dead-code bug. However, the human reviewer added irreplaceable depth on the security trust model — verifying mint service enforcement in Proposals filed
|
Summary
Adds an optional
matrixinput toreusable-dispatch.ymlthat allows custom pollers in external repos to invoke harness agents directly without going through the routing and dispatch steps.This approach solves #6347 while maintaining ADR 62's inlining decision - no version skew is introduced because we're not extracting workflows.
Changes
New input:
matrixfullsend dispatch --output-driver gha-matrixModified job flow:
routejob skips when matrix is providedharness-dispatchonly runs whenstage == 'harness'and no matrix providedharness-runuses either the computed or provided matrixevent_actionoptional when matrix is providedDocumentation:
docs/guides/user/custom-poller-example.mdwith complete exampleHow It Works
Normal flow (unchanged):
Custom poller flow (new):
Example Usage
ADR 62 Compliance
This does not conflict with ADR 62:
@v0references between workflowsThe new
matrixinput is an alternative entry point for external callers, not a reversal of the inlining decision.Test plan
Fixes #6347
🤖 Generated with Claude Code