Skip to content

feat(#8726): let a CEL trigger decide review routing - #8729

Closed
waynesun09 wants to merge 1 commit into
mainfrom
8726-cel-review-route
Closed

waynesun09 wants to merge 1 commit into
mainfrom
8726-cel-review-route

Conversation

@waynesun09

Copy link
Copy Markdown
Member

Summary

Lets the review harness trigger decide whether the Review job starts, behind the rollout variable FULLSEND_CEL_ROUTING_REVIEW (off default / shadow / on). The Review job still runs the review unchanged. With the variable off or unset, routing is unchanged.

Related Issue

Closes #8726. Part of #2888 (routing half of #2898).

Changes

  • fullsend dispatch --route review prints one JSON line {"agent","decision":"run|skip|bash","reason","harness"}. It resolves the review harness like fullsend run (config entry with source:, else the agents-repo fallback at the lockstep ref) and loads it with LoadWithBase. A resolved harness with no trigger → bash (compatibility guard). Otherwise the event goes through the dispatch auth gate, then the trigger.

  • AuthorizeEvent: the OWNERS-aware gate moved out of Dispatch so both paths share it. No behaviour change.

  • Route job: new cel-* steps, gated on the variable being shadow/on and the event being pull_request_target or issue_comment. They do a sparse checkout into cel-route/ (same trusted ref), install the CLI with the harness-dispatch cache key, and evaluate with continue-on-error. A guarded tail in "Determine stage" applies the decision:

    Mode Effect
    shadow Logs bash=… cel=…, warns on a mismatch.
    on run → STAGE=review, skip → STAGE="", bash keeps the bash stage. Never replaces another bash stage. A CLI error keeps the bash stage with ::error::.
  • Behaviour step the repository variable "<NAME>" is "<value>": restores the previous value at scenario cleanup.

  • Docs:

    • customizing-agents.md: new section "Choosing when review runs".
    • cel-triggers-reference.md: updated coexistence section.
    • Step reference, variable reference and workflow-contracts pointer.

Not in this PR

Gate for on Why
#8724 Triage-role users are denied on the CEL path today
#8725 Without it a review override with a trigger also runs via harness-run
#8329 The GitHub gha-event input does not run the ADR 0107 bot-role lookup yet, so bot-authored PRs are skipped

shadow has no dependency.

Known differences on the CEL path (from the parity test)

Case Bash CEL
Triage-role PR author or /fs-review commenter review skip until #8724
PR opened or pushed by a bot without a write collaborator role review skip until #8329: the gha-event input does not run the ADR 0107 bot-role lookup yet
Read-only author's PR synchronized by a write maintainer none run (CEL checks the sender, bash the PR author)
issues labeled ready-for-review on a PR review not evaluated (only pull_request_target and issue_comment run the CEL step), so the bash stage is kept

Testing

  • make lint passes (pre-commit run --from-ref origin/main --to-ref HEAD)
  • Tests added:
    • Unit tests for --route (each guard row, kill switch, disabled, auth denied, fallback unavailable, one-line stdout).
    • Parity golden: raw webhooks → gha-event → AuthorizeEvent → testdata/review-trigger.cel, compared with the bash decision.
    • "Determine stage" run under bash per mode, including a byte-for-byte check that off/unset match a run without the CEL env.
    • Stub-CLI test for the evaluate step.
    • A gating test that every cel-* step depends on the variable.
    • Repository-variable step tests.
  • Validation on a test repository (shadow → on, old-base override, /fs-review-only override, off, double-run check) follows once feat(dispatch): apply per-harness permission threshold on the CEL path #8724/fix(dispatch): don't fan out built-in agents from GitHub CEL dispatch #8725 merge.

Checklist

  • PR title follows Conventional Commits (correct type, ! for breaking changes)
  • Commits are signed off (DCO) — human and human-directed agent sessions only
  • I wrote this contribution myself and can explain all changes in it

🤖 Generated with Claude Code

Add `fullsend dispatch --route review`, which resolves the review
harness the way `fullsend run` does (a config entry with source:, else
the agents-repo fallback at the lockstep ref) and prints one JSON line:
run, skip, or bash when the resolved harness has no trigger.

The route job evaluates it when the repository or organization
variable FULLSEND_CEL_ROUTING_REVIEW is shadow or on, for pull request
and comment events. shadow logs the CEL decision next to the bash
stage; on lets it set or clear STAGE=review. The review job still runs
the review. With the variable off or unset every new step is skipped
and the bash stage is unchanged.

Move the OWNERS-aware authorization gate out of Dispatch into
AuthorizeEvent so both paths share it. Add a parity test of the
default review trigger against the bash router, a test that runs the
Determine stage script per mode, and a behaviour step that sets a
repository variable and restores it at cleanup.

Closes #8726

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Let review harness CEL triggers decide review routing

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add a rollout-gated CEL decision for starting the existing Review job.
• Preserve bash routing when disabled, when the harness lacks a trigger, or when evaluation fails.
• Share dispatch authorization, test routing parity, and document rollout limitations.
Diagram

graph TD
  EVENT["GitHub event"] --> BASH["Bash stage"] --> MODE{"Routing mode"} --> REVIEW["Review job"]
  EVENT --> CLI["Route CLI"] --> HARNESS["Review harness"] --> GATE["Auth and trigger"] --> MODE
  MODE --> SKIP["No review"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep review routing entirely in the workflow
  • ➕ Avoids installing the CLI in the route job.
  • ➕ Keeps the current routing path operationally simple.
  • ➖ Cannot use harness CEL triggers as the routing source of truth.
  • ➖ Would duplicate harness resolution and authorization if CEL were added in shell.
2. Route review through the harness-dispatch matrix
  • ➕ Uses the existing CEL dispatch pipeline without a separate route decision.
  • ➕ Could consolidate built-in and custom-agent routing longer term.
  • ➖ Changes where review runs instead of retaining the existing Review job.
  • ➖ Requires additional work to prevent duplicate review execution and align authorization.

Recommendation: The guarded CLI decision is the better incremental approach: it reuses harness resolution and authorization while preserving the Review job and an explicit bash fallback. Keep shadow as the rollout default until the documented triage, bot, and duplicate-execution prerequisites are addressed.

Files changed (20) +1614 / -25

Enhancement (3) +394 / -0
reusable-dispatch.ymlGate CEL review evaluation and apply its stage decision +196/-0

Gate CEL review evaluation and apply its stage decision

• Adds trusted sparse checkout, CLI installation and caching, and a failure-tolerant review-route evaluation for pull request and comment events. The route job compares decisions in shadow mode and, in on mode, changes only the review stage while retaining bash routing on fallback or error.

.github/workflows/reusable-dispatch.yml

dispatch.goExpose JSON review decisions through dispatch --route +32/-0

Expose JSON review decisions through dispatch --route

• Adds the review-only route flag and returns a single JSON decision instead of a dispatch matrix when selected. Existing matrix dispatch remains the default.

internal/cli/dispatch.go

dispatch_route.goResolve and evaluate the review harness for routing +166/-0

Resolve and evaluate the review harness for routing

• Resolves the configured review source or agents-repository fallback, loads inherited triggers, and returns run, skip, or bash with a reason. Kill switches, explicit disabling, and shared authorization are accounted for before a trigger can authorize a run.

internal/cli/dispatch_route.go

Refactor (2) +40 / -24
authorize.goExtract the shared OWNERS-aware authorization gate +39/-0

Extract the shared OWNERS-aware authorization gate

• Introduces AuthorizeEvent for both dispatch paths, applying OWNERS role upgrades to the authorization check without changing the event passed to CEL.

internal/harnessdispatch/authorize.go

core.goUse shared authorization in harness dispatch +1/-24

Use shared authorization in harness dispatch

• Replaces the inline OWNERS resolution and permission check with AuthorizeEvent, retaining the existing dispatch gate.

internal/harnessdispatch/core.go

Tests (10) +1090 / -0
dispatch_route_test.goCover review-route resolution and JSON decisions +376/-0

Cover review-route resolution and JSON decisions

• Tests fallback and override harnesses, inherited and missing triggers, disabled and unauthorized cases, resolution errors, unsupported agents, and single-line CLI output.

internal/cli/dispatch_route_test.go

review_route_parity_test.goCompare review trigger outcomes with bash routing +236/-0

Compare review trigger outcomes with bash routing

• Exercises raw GitHub PR and comment payloads through event normalization, authorization, and CEL evaluation. Records accepted differences for triage users, bot authors, and a maintainer synchronizing another author's PR.

internal/harnessdispatch/review_route_parity_test.go

review-trigger.celFixture for the default review trigger +15/-0

Fixture for the default review trigger

• Stores the review trigger expression used by parity tests across PR transitions, labels, and human /fs-review comments.

internal/harnessdispatch/testdata/review-trigger.cel

cel_review_route_test.goExercise workflow review-routing scripts +283/-0

Exercise workflow review-routing scripts

• Runs extracted route-job scripts to check off-mode equivalence, shadow and on decisions, error fallback, step gating, and parsing of CLI output.

internal/scaffold/cel_review_route_test.go

cleanup.goRestore scenario-modified repository variables +10/-0

Restore scenario-modified repository variables

• Adds retried repository-variable restoration to scenario cleanup before the leased repository is released.

pkg/behaviourtest/steps/cleanup.go

registry.goRegister the repository-variable behavior step +1/-0

Register the repository-variable behavior step

• Makes the new variable-setting step available to behavior scenarios.

pkg/behaviourtest/steps/registry.go

repo_variable.goSet repository variables with reversible scenario state +90/-0

Set repository variables with reversible scenario state

• Adds a GitHub-backed behavior step that records each variable's original value before changing it. Cleanup restores prior values or deletes previously absent variables, retaining failed restorations for retry.

pkg/behaviourtest/steps/repo_variable.go

repo_variable_test.goTest repository-variable restoration +73/-0

Test repository-variable restoration

• Covers absent and existing values, repository requirements, read failures, harmless deletion of missing variables, and retryable cleanup failures.

pkg/behaviourtest/steps/repo_variable_test.go

init.goReset recorded repository variables between scenarios +1/-0

Reset recorded repository variables between scenarios

• Clears the variable-restoration record when preparing a scenario world.

pkg/behaviourtest/suite/init.go

world.goTrack original repository-variable values +5/-0

Track original repository-variable values

• Adds scenario state for variables changed by behavior steps, distinguishing an absent variable from one with a previous value.

pkg/behaviourtest/world/world.go

Documentation (5) +90 / -1
workflow-contracts.mdIdentify the shared OWNERS authorization entry point +1/-1

Identify the shared OWNERS authorization entry point

• Updates the workflow contract to point to AuthorizeEvent and note its use by both dispatch modes.

docs/contributing/workflow-contracts.md

behaviour-testing.mdDocument the repository-variable behavior step +2/-0

Document the repository-variable behavior step

• Describes how scenarios set repository variables and restore their prior values at cleanup.

docs/guides/dev/behaviour-testing.md

infrastructure-reference.mdList the optional CEL review rollout variable +1/-0

List the optional CEL review rollout variable

• Documents FULLSEND_CEL_ROUTING_REVIEW, its three values, and that setup does not set it.

docs/guides/infrastructure/infrastructure-reference.md

cel-triggers-reference.mdExplain CEL and stage-routing coexistence for review +2/-0

Explain CEL and stage-routing coexistence for review

• Clarifies that review can opt into trigger-based routing and that a resolved harness without a trigger retains stage-based routing.

docs/guides/user/cel-triggers-reference.md

customizing-agents.mdGuide users through CEL review routing +84/-0

Guide users through CEL review routing

• Adds rollout modes, a narrower /fs-review trigger example, decision-log guidance, and current authorization limitations.

docs/guides/user/customizing-agents.md

@fullsend-ai-review

fullsend-ai-review Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:14 PM UTC · Completed 9:25 PM UTC

Commit: 26fd08d · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5-5 · Effort: high · Cost: $3.18

@waynesun09

Copy link
Copy Markdown
Member Author

Closing: this change will come through the code agent on #8726 instead, using this branch (26fd08d) as the reference implementation. Branch kept.

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (1) 📎 Requirement gaps (1) 🔗 Cross-repo conflicts (1) 📜 Skill insights (4)

Grey Divider


Action required

1. The guide starts without prerequisites 📜 Skill insight ✧ Quality
Description
The new review-routing procedure in customizing-agents.md adds setup commands without a labeled
prerequisites section. Readers reach the configuration steps without being told what access,
repository setup, or tools they need beforehand.
Code

docs/guides/user/customizing-agents.md[R732-740]

+## Choosing when review runs
+
+By default, the dispatch workflow decides when the review agent runs: when a
+pull request is opened, pushed to or marked ready, when the
+`ready-for-review` label is added, and on a `/fs-review` comment. To change
+that, set the repository or organization variable
+`FULLSEND_CEL_ROUTING_REVIEW` and give the review harness a `trigger`
+expression. The review still runs in the same `Review` job; the trigger only
+decides whether that job starts.
Relevance

●●● Strong

Recent guide reviews accepted adding clearly labeled prerequisites before procedural instructions.

PR-#2663
PR-#8499

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The modified guide adds a procedural section beginning with review-routing instructions, but the
guide has no Prerequisites section before that content. This violates the requirement that guides
state prerequisites before step 1.

docs/guides/user/customizing-agents.md[732-740]
Skill: writing-user-docs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The guide adds a review-routing procedure but does not provide a clearly labeled prerequisites section before the procedure begins.

## Fix Focus Areas
- docs/guides/user/customizing-agents.md[732-740]

## Recommended Fix
Add a `## Prerequisites` section before `## Choosing when review runs` that lists the required repository or organization access, an enrolled repository, and the GitHub CLI or equivalent variable-management capability needed to follow the example.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


2. Vendored installs stop review routing 🐞 Bug ≡ Correctness
Description
The vendored install step invokes ./cel-route/.defaults/.github/actions/install-fullsend-cli,
although the detected vendored marker and binary live under cel-route/.fullsend/. On a vendored
repository with a cache miss, the local action cannot be found, so the route job fails before it can
determine a stage.
Code

.github/workflows/reusable-dispatch.yml[R206-208]

+      - name: Install fullsend CLI for CEL review route (vendored defaults)
+        if: steps.cel-config.outcome == 'success' && steps.cel-cli-mode.outputs.mode == 'vendored' && steps.cel-cli-cache.outputs.cache-hit != 'true'
+        uses: ./cel-route/.defaults/.github/actions/install-fullsend-cli
Relevance

●●● Strong

The vendored action path contradicts the detected nested layout and is a deterministic install
failure.

PR-#3820

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new detection accepts the nested marker, but its action path points outside that layout;
repository vendoring tests confirm the nested marker and binary paths.

.github/workflows/reusable-dispatch.yml[165-172]
.github/workflows/reusable-dispatch.yml[180-212]
internal/scaffold/pathpresence_test.go[12-27]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CEL route detects the nested vendored layout but invokes an installer at a root path that is absent from that layout.
## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[165-172]
- .github/workflows/reusable-dispatch.yml[180-212]
## Recommended Fix
Use an installer action path that exists for the detected vendored layout, retaining the checked `.fullsend/bin/fullsend` as its binary input. Cover a vendored cache miss in the workflow tests.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


3. A broken CLI install in shadow mode stops all dispatch 🐞 Bug ☼ Reliability
Description
None of the new install steps in the Route job have continue-on-error: not the CEL config
checkout, the vendored guard (which runs exit 1 itself), either install step, the upstream action
checkout, or the cache-artifact cp. Only "Evaluate CEL review route" and the cache save do. If any
of those steps fails while the variable is shadow or on, every later step is skipped, including
"Determine stage" (it runs only when earlier steps succeeded). The Route job then fails, so no stage
runs (triage, code, fix, retro or review) for that PR or comment event, even though shadow is meant
to be risk-free.
Code

.github/workflows/reusable-dispatch.yml[R186-194]

+      - name: Guard vendored install for CEL review route
+        if: steps.cel-config.outcome == 'success' && steps.cel-cli-mode.outputs.mode == 'vendored'
+        shell: bash
+        run: |
+          set -euo pipefail
+          if [[ ! -f cel-route/.fullsend/bin/fullsend ]]; then
+            echo "::error::broken --vendor install: vendored marker present but .fullsend/bin/fullsend is missing"
+            exit 1
+          fi
Relevance

●●● Strong

Unprotected setup failures can skip Determine stage; recent workflow reviews accept reliability
fixes preventing silent dispatch loss.

PR-#8425
PR-#6455

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new steps at lines 155-260 have no continue-on-error, except the cache save at line 256. The
guard at 191-193 exits 1. "Determine stage" at line 298 has no if:, so it is skipped once an
earlier step fails, and the Route job's stage output stays empty. The ticket says shadow CLI
errors should be a warning only, and the in-file comment at 262-264 says a failure here never fails
the route job.

.github/workflows/reusable-dispatch.yml[155-260]
.github/workflows/reusable-dispatch.yml[262-300]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CEL review-route install steps in the Route job can fail the whole job. When that happens "Determine stage" is skipped and no agent stage is dispatched, even in shadow mode.

## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[155-260]

## Recommended Fix
Add `continue-on-error: true` to every cel-* step: checkout, mode detect, vendored guard, cache restore, both installs, the upstream action checkout, expose and prepare. Gate "Evaluate CEL review route" on the install having succeeded, for example by checking that `command -v fullsend` works inside the step, so that "Determine stage" always runs and sees a non-success outcome. That outcome keeps the bash stage with ::warning:: in shadow or ::error:: in on.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


View high (2)
4. Triage users lack trigger-route access 📜 Skill insight ≡ Correctness
Description
The guide states that triage-role users and some bot-authored events are not yet authorized on the
trigger path while routing is enabled. Because the text describes future authorization work only
through issue links and not the required planned-feature callout, readers can mistake the limitation
for an undocumented permanent behavior.
Code

docs/guides/user/customizing-agents.md[R809-814]

+Two cases are not yet authorized on the trigger path, so with `on` they do
+not start a review: pull requests and `/fs-review` comments from triage-role
+users ([#8724](https://github.com/fullsend-ai/fullsend/issues/8724)), and pull
+requests opened or pushed by a bot without a `write` collaborator role,
+including fullsend's own agent bots. Check both in `shadow` before you switch
+to `on`.
Relevance

●● Moderate

The limitation is linked and explicit, but the repository has mixed precedent on mandatory Planned
callout formatting.

PR-#8275
PR-#8496

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The added documentation says two cases are not yet authorized and links to follow-up issues, which
identifies not-yet-implemented functionality. The text is an ordinary paragraph rather than the
required > **Planned:** blockquote with issue link format.

docs/guides/user/customizing-agents.md[809-814]
Skill: writing-user-docs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The guide documents trigger-path authorization gaps as not-yet-authorized cases without using the required planned-feature callout format.

## Fix Focus Areas
- docs/guides/user/customizing-agents.md[809-814]

## Recommended Fix
Convert this limitation into a `> **Planned:**` callout that explicitly links to the relevant issue(s), and state that triage-role and bot-authored trigger routing is not currently supported rather than presenting the future work as ordinary guidance.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


5. Configured review runs twice 📎 Requirement gap ≡ Correctness
Description
When FULLSEND_CEL_ROUTING_REVIEW=on, a matching review trigger sets STAGE to review while
the independent harness-dispatch job can also return that configured review harness for execution.
The inline Review job and the resulting harness-run job then execute the same review event
separately.
Code

.github/workflows/reusable-dispatch.yml[R605-608]

+                  CEL_ROUTE_SOURCE="cel"
+                  case "${CEL_REVIEW_DECISION}" in
+                    run) STAGE="review" ;;
+                    skip) STAGE="" ;;
Relevance

●● Moderate

The duplicate execution is documented as a known dependency, but reviewers may still require
preventing duplicate review runs.

PR-#6455

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new on branch sets STAGE=review when the resolved review trigger matches. The workflow's
independent harness-dispatch job still dispatches matching configured harnesses, and harness-run
executes those refs, so a configured review override can run both through the built-in Review job
and harness fan-out.

Gate CEL review routing behind the rollout variable
.github/workflows/reusable-dispatch.yml[605-608]
.github/workflows/reusable-dispatch.yml[1777-1782]
internal/cli/dispatch_route.go[130-144]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A matching configured review harness causes the route job to start the built-in Review job while the independent harness-dispatch and harness-run jobs can execute the same review harness, resulting in duplicate review execution.

## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[605-608]
- .github/workflows/reusable-dispatch.yml[1698-1782]

## Recommended Fix
Ensure a review harness selected by the CEL route cannot also be emitted by harness-dispatch, or otherwise coordinate the jobs so each matching review event executes exactly once while preserving custom harness dispatch and the bash fallback.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗



Remediation recommended

6. Procedure prose hides the routing steps 📜 Skill insight ✧ Quality
Description
The review-routing example explains how to change behavior in prose and then places the commands in
an unnumbered code block. Readers cannot follow the setup as the required ordered procedure, and
later edits can obscure the intended sequence.
Code

docs/guides/user/customizing-agents.md[R755-758]

+### Example: review only on `/fs-review`
+
+To stop automatic reviews on every pull request but keep `/fs-review`,
+override the review harness with a narrower trigger:
Relevance

●●● Strong

Recent guide reviews accepted rewriting procedural prose as ordered, numbered steps.

PR-#2663
PR-#8496

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The added section contains procedural instructions such as stopping automatic reviews, configuring
the harness, and turning routing on, but presents them as prose followed by an unnumbered shell
block rather than numbered steps.

docs/guides/user/customizing-agents.md[755-783]
Skill: writing-user-docs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new review-routing procedure uses prose paragraphs and an unnumbered command block instead of numbered steps.

## Fix Focus Areas
- docs/guides/user/customizing-agents.md[755-783]

## Recommended Fix
Rewrite the example instructions as an ordered list, with each command or action at the start of its numbered step followed by any explanation. Keep the YAML examples as supporting configuration blocks under the relevant steps.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


7. The review guide leaves CEL undefined 📜 Skill insight ✧ Quality
Description
The new guide uses CEL in the routing variable and decision logs without expanding the acronym or
linking it to a glossary or reference on first use. A reader unfamiliar with the expression language
cannot tell what the routing mechanism means before following the configuration example.
Code

docs/guides/user/customizing-agents.md[R738-740]

+`FULLSEND_CEL_ROUTING_REVIEW` and give the review harness a `trigger`
+expression. The review still runs in the same `Review` job; the trigger only
+decides whether that job starts.
Relevance

●●● Strong

Recent documentation reviews accepted defining unfamiliar acronyms and technical terms on first use.

PR-#8496
PR-#8499

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The added guide introduces FULLSEND_CEL_ROUTING_REVIEW and later labels output as `CEL review
route`, but does not define CEL inline or link the first use to a glossary or reference.

docs/guides/user/customizing-agents.md[738-740]
docs/guides/user/customizing-agents.md[790-800]
Skill: writing-user-docs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The review-routing guide introduces CEL-based routing without defining `CEL` or linking the term to the trigger reference.

## Fix Focus Areas
- docs/guides/user/customizing-agents.md[738-740]
- docs/guides/user/customizing-agents.md[790-800]

## Recommended Fix
Expand CEL as Common Expression Language on its first occurrence and link it to `cel-triggers-reference.md` or the existing CEL specification reference. Use the same linked or defined terminology in the decision-log example.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


8. Users cannot find the new route flag 📘 Rule violation ⚙ Maintainability
Description
newDispatchCmd adds --route and introduces FULLSEND_CEL_ROUTING_REVIEW, but the general CLI
references and repository-variable table are not updated, and the PR does not state that
docs/contributing/documentation.md was consulted. Users consulting those references lack the
flag’s usage and the variable’s behavior and defaults, while later maintainers lack a record that
the documentation checklist was followed.
Code

internal/cli/dispatch.go[59]

+	cmd.Flags().StringVar(&route, "route", "", "Decide routing for one built-in agent (review) and print one JSON line with decision run, skip or bash; --output-driver is ignored")
Relevance

●●● Strong

Recent precedents accept keeping CLI help and user documentation synchronized with changed flags and
configuration behavior.

PR-#5763
PR-#5976

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed CLI definition adds --route at internal/cli/dispatch.go:59, and the workflow and
feature-specific guides introduce FULLSEND_CEL_ROUTING_REVIEW. The documentation guide requires
CLI reference and repository-variable table updates for these changes, but the general CLI and
operations references are unchanged and the PR description contains no consultation note.

Rule 2748504: Keep CLI and config documentation in sync with behavior changes
Rule 2806787: Consult documentation guide when modifying cross-referenced docs or CLI/config surfaces
internal/cli/dispatch.go[59-59]
docs/guides/user/customizing-agents.md[732-746]
docs/contributing/documentation.md[11-14]
.github/workflows/reusable-dispatch.yml[155-157]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `fullsend dispatch --route review` flag and `FULLSEND_CEL_ROUTING_REVIEW` variable are missing from the required general documentation references, and the PR does not record consultation of `docs/contributing/documentation.md`.

## Fix Focus Areas
- internal/cli/dispatch.go[59-59]
- docs/guides/getting-started/operations.md[1-1]
- docs/guides/dev/cli-internals.md[1-1]
- docs/cli/README.md[1-1]
- docs/guides/infrastructure/infrastructure-reference.md[352-352]

## Recommended Fix
Document `--route review`, its output format, and its ignored output-driver semantics in the applicable CLI reference and CLI internals documentation. Add `FULLSEND_CEL_ROUTING_REVIEW` to the repository-variable table with its `off`, `shadow`, and `on` values, default behavior, and a link to the review-routing guide. Follow the documentation guide’s discovery and cross-reference requirements, and note in the PR description that the guide was consulted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


View medium (5)
9. Denied events still fetch review harnesses 🐞 Bug ➹ Performance
Description
routeBuiltinAgent resolves and loads the harness before calling AuthorizeEvent, so authorization
does not protect those fetches. An unauthorized PR or comment event can repeatedly fetch a
configured URL source or remote base before receiving a skip decision, unlike ordinary dispatch,
which authorizes before harness enumeration.
Code

internal/cli/dispatch_route.go[R117-119]

+	harnessPath, deps, err := resolveAgentSource(ctx, absConfigDir, o.agent, forgeClient, cfg, composeOpts, printer)
+	if err != nil {
+		return d, err
Relevance

●●● Strong

Authorization is expected before harness enumeration or remote resolution; the existing dispatch
precedent explicitly enforces that ordering.

PR-#3820
PR-#8088

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Source resolution and base loading precede the gate in route mode, whereas normal dispatch applies
the same gate before it lists triggered harnesses.

internal/cli/dispatch_route.go[117-137]
internal/cli/run.go[7223-7246]
internal/harnessdispatch/core.go[28-48]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The route path performs potentially remote harness resolution before applying its event authorization gate.
## Fix Focus Areas
- internal/cli/dispatch_route.go[117-137]
## Recommended Fix
Apply event authorization before resolving or loading remote harness content where a denied event needs no harness. Preserve the no-trigger compatibility decision explicitly when reorganizing this flow.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


10. Configured forge can block CEL routing 🐞 Bug ≡ Correctness
Description
routeBuiltinAgent chooses the harness forge platform from the event source instead of using
config.forge precedence as fullsend run does. A repository configured for a different forge can
therefore load a different overlay or fail a forge-specific harness load, making route mode fall
back to bash rather than deciding against the harness that review execution uses.
Code

internal/cli/dispatch_route.go[R103-107]

+	// Resolve forge: blocks for the event's forge, as `fullsend run` does.
+	switch o.event.Source.System {
+	case normevent.SystemGitHub, normevent.SystemGitLab:
+		composeOpts.ForgePlatform = string(o.event.Source.System)
+	}
Relevance

●●● Strong

Forge selection changes harness resolution semantics; similar dispatch and forge-resolution
correctness findings were accepted.

PR-#3820
PR-#8015

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Run mode honors config.forge before environment detection, whereas the new route assignment
ignores it; harness composition uses the selected platform to resolve forge-specific configuration.

internal/cli/dispatch_route.go[96-107]
internal/cli/run.go[6338-6365]
internal/harness/compose.go[205-208]
internal/harness/forge.go[336-350]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Route mode derives the harness forge platform from the event even when repository configuration specifies a different platform for run mode.
## Fix Focus Areas
- internal/cli/dispatch_route.go[96-107]
- internal/cli/run.go[6338-6365]
## Recommended Fix
Select `ForgePlatform` with the same configuration and environment precedence used by `fullsend run`, then test route mode with `config.forge` and a forge-specific harness block.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


11. A trigger can start Review on a plain issue comment 🐞 Bug ≡ Correctness
Description
In on mode, the run branch sets STAGE=review for any issue_comment without checking
ISSUE_IS_PR, and the documented /fs-review trigger checks the command and actor but not whether
the comment is on a pull request. A /fs-review comment on an ordinary issue can therefore reach
the Review job with the issue’s URL and number as PR context, without a PR-head lookup or
pull_request payload.
Code

.github/workflows/reusable-dispatch.yml[R605-610]

+                  CEL_ROUTE_SOURCE="cel"
+                  case "${CEL_REVIEW_DECISION}" in
+                    run) STAGE="review" ;;
+                    skip) STAGE="" ;;
+                    *) CEL_ROUTE_SOURCE="bash" ;;
+                  esac
Relevance

●●● Strong

The documentation trigger omits the PR guard implemented in parity tests, enabling review routing
for ordinary issues.

PR-#8496

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The bash path permits /fs-review only when ISSUE_IS_PR == true, and the PR-head resolution step
runs only when github.event.issue.pull_request is set. The default testdata trigger guards on
event.entity.kind == "change_proposal" || has(event.entity.linked_change_proposal), but the
documented example omits that guard; the CEL step evaluates issue comments, and the workflow applies
its run decision without the corresponding PR check.

.github/workflows/reusable-dispatch.yml[459-465]
.github/workflows/reusable-dispatch.yml[784-787]
docs/guides/user/customizing-agents.md[760-769]
internal/harnessdispatch/testdata/review-trigger.cel[10-15]
.github/workflows/reusable-dispatch.yml[155-157]
.github/workflows/reusable-dispatch.yml[788-842]
.github/workflows/reusable-dispatch.yml[1190-1200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
In `on` mode, a CEL `run` decision can select the PR-only Review job for a comment on an ordinary issue. The documented `/fs-review` example trigger also permits those comments.

## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[593-610]
- docs/guides/user/customizing-agents.md[760-769]

## Recommended Fix
In the `on` branch, map `run` to `STAGE=review` only for `pull_request_target` events or `issue_comment` events with `ISSUE_IS_PR == true`. Otherwise, log a warning and leave `STAGE` empty. Add `&& (event.entity.kind == "change_proposal" || has(event.entity.linked_change_proposal))` to the documented example trigger.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


12. A maintainer push can review a blocked PR 🐞 Bug ≡ Correctness
Description
The CEL run branch starts review for a synchronized PR based on authorization of the event sender,
whereas the bash rule checks the PR author. When a write-authorized maintainer synchronizes a PR
whose author has read-only access, on replaces bash’s empty stage with review; the parity
fixture records this mismatch.
Code

.github/workflows/reusable-dispatch.yml[R605-607]

+                  CEL_ROUTE_SOURCE="cel"
+                  case "${CEL_REVIEW_DECISION}" in
+                    run) STAGE="review" ;;
Relevance

●● Moderate

Parity tests explicitly document this authorization mismatch, making intentional rollout behavior
plausible despite the correctness risk.

PR-#8141

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The bash rule gates on the PR author, the shared CEL gate uses the event actor, and the new branch
turns their differing decisions into a Review job.

.github/workflows/reusable-dispatch.yml[514-519]
internal/harnessdispatch/auth.go[42-58]
internal/harnessdispatch/review_route_parity_test.go[89-95]
.github/workflows/reusable-dispatch.yml[1103-1106]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
For PR synchronization, CEL authorizes the sender while the existing review router authorizes the PR author, allowing a review the bash router blocks.
## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[605-608]
- .github/workflows/reusable-dispatch.yml[514-519]
## Recommended Fix
Preserve the existing PR-author authorization constraint before applying a CEL `run` decision for PR events, and add a workflow-stage test for a read-only author whose PR is synchronized by a write-authorized sender.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


13. Reviews can use a different trigger 🔗 Cross-repo conflict ≡ Correctness
Description
The CEL route installs and caches the CLI at job.workflow_sha, while the Review job uses
inputs.fullsend_version || job.workflow_sha; because the CLI build determines the agents ref, they
can resolve different review-harness triggers. When a caller overrides fullsend_version, CEL can
return run or skip for a trigger the executed harness does not have, return run where bash
is appropriate, or fall back to bash if the workflow-SHA CLI does not support --route.
Code

.github/workflows/reusable-dispatch.yml[232]

+          workflow_sha: ${{ job.workflow_sha }}
Relevance

●● Moderate

Version alignment affects cross-repository harness semantics, but no closely matching historical
decision confirms acceptance.

PR-#6611

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The upstream route installer uses job.workflow_sha for both installation and caching, whereas the
Review action uses the explicit fullsend_version override when present. resolveAgentsRef derives
the agents ref from the installed CLI's build tag, falling back to main for a source build, and
the review trigger is defined in the versioned agents harness. Thus an override can make routing
evaluate a different harness from the one Review executes; a workflow-SHA CLI without --route can
also leave routing on bash.

fullsend -> agents
.github/workflows/reusable-dispatch.yml[198-204]
.github/workflows/reusable-dispatch.yml[226-233]
.github/workflows/reusable-dispatch.yml[1216-1223]
internal/cli/dispatch_route.go[117-137]
.github/workflows/reusable-dispatch.yml[1092-1092]
internal/cli/run.go[7262-7268]
.github/workflows/reusable-dispatch.yml[1218-1223]
.github/actions/install-fullsend-cli/action.yml[5-20]
External repo: fullsend-ai/agents, .github/workflows/release.yml [1-35]
External repo: fullsend-ai/agents, harness/review.yaml [19-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An explicit `fullsend_version` changes the release used by Review but not the CLI used for CEL routing, so routing can evaluate a different review harness or use a CLI without `--route`.

## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[198-260]
- .github/workflows/reusable-dispatch.yml[1216-1223]

## Recommended Fix
Install the route CLI using the same effective version as Review, `inputs.fullsend_version || job.workflow_sha`, and include that value in the route CLI cache key so it cannot reuse a binary built for another version. Test routing with a caller-supplied `fullsend_version`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


Grey Divider

Context sources
✅ Compliance rules (platform): 95 rules
✅ Skills: 5 invoked
  writing-user-docs
  writing-adrs
  check-patch-coverage
  cutting-releases
  adr-corner
✅ Cross-repo context — repo relationships
  Explored: repo: fullsend-ai/.fullsend (sha: 000962f3) — View relationship
  Explored: repo: fullsend-ai/agents (branch: review-cel-trigger, sha: 58a00b74) — View relationship
Review mode: Auto: 🧠 Deep: Broad routing, authorization, workflow, CLI, and behavior-test changes create dense independent risks.

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +732 to +740
## Choosing when review runs

By default, the dispatch workflow decides when the review agent runs: when a
pull request is opened, pushed to or marked ready, when the
`ready-for-review` label is added, and on a `/fs-review` comment. To change
that, set the repository or organization variable
`FULLSEND_CEL_ROUTING_REVIEW` and give the review harness a `trigger`
expression. The review still runs in the same `Review` job; the trigger only
decides whether that job starts.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. The guide starts without prerequisites 📜 Skill insight ✧ Quality

The new review-routing procedure in customizing-agents.md adds setup commands without a labeled
prerequisites section. Readers reach the configuration steps without being told what access,
repository setup, or tools they need beforehand.
Agent Prompt
## Issue description
The guide adds a review-routing procedure but does not provide a clearly labeled prerequisites section before the procedure begins.

## Fix Focus Areas
- docs/guides/user/customizing-agents.md[732-740]

## Recommended Fix
Add a `## Prerequisites` section before `## Choosing when review runs` that lists the required repository or organization access, an enrolled repository, and the GitHub CLI or equivalent variable-management capability needed to follow the example.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment on lines +755 to +758
### Example: review only on `/fs-review`

To stop automatic reviews on every pull request but keep `/fs-review`,
override the review harness with a narrower trigger:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

6. Procedure prose hides the routing steps 📜 Skill insight ✧ Quality

The review-routing example explains how to change behavior in prose and then places the commands in
an unnumbered code block. Readers cannot follow the setup as the required ordered procedure, and
later edits can obscure the intended sequence.
Agent Prompt
## Issue description
The new review-routing procedure uses prose paragraphs and an unnumbered command block instead of numbered steps.

## Fix Focus Areas
- docs/guides/user/customizing-agents.md[755-783]

## Recommended Fix
Rewrite the example instructions as an ordered list, with each command or action at the start of its numbered step followed by any explanation. Keep the YAML examples as supporting configuration blocks under the relevant steps.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment on lines +809 to +814
Two cases are not yet authorized on the trigger path, so with `on` they do
not start a review: pull requests and `/fs-review` comments from triage-role
users ([#8724](https://github.com/fullsend-ai/fullsend/issues/8724)), and pull
requests opened or pushed by a bot without a `write` collaborator role,
including fullsend's own agent bots. Check both in `shadow` before you switch
to `on`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Triage users lack trigger-route access 📜 Skill insight ≡ Correctness

The guide states that triage-role users and some bot-authored events are not yet authorized on the
trigger path while routing is enabled. Because the text describes future authorization work only
through issue links and not the required planned-feature callout, readers can mistake the limitation
for an undocumented permanent behavior.
Agent Prompt
## Issue description
The guide documents trigger-path authorization gaps as not-yet-authorized cases without using the required planned-feature callout format.

## Fix Focus Areas
- docs/guides/user/customizing-agents.md[809-814]

## Recommended Fix
Convert this limitation into a `> **Planned:**` callout that explicitly links to the relevant issue(s), and state that triage-role and bot-authored trigger routing is not currently supported rather than presenting the future work as ordinary guidance.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment on lines +738 to +740
`FULLSEND_CEL_ROUTING_REVIEW` and give the review harness a `trigger`
expression. The review still runs in the same `Review` job; the trigger only
decides whether that job starts.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

7. The review guide leaves cel undefined 📜 Skill insight ✧ Quality

The new guide uses CEL in the routing variable and decision logs without expanding the acronym or
linking it to a glossary or reference on first use. A reader unfamiliar with the expression language
cannot tell what the routing mechanism means before following the configuration example.
Agent Prompt
## Issue description
The review-routing guide introduces CEL-based routing without defining `CEL` or linking the term to the trigger reference.

## Fix Focus Areas
- docs/guides/user/customizing-agents.md[738-740]
- docs/guides/user/customizing-agents.md[790-800]

## Recommended Fix
Expand CEL as Common Expression Language on its first occurrence and link it to `cel-triggers-reference.md` or the existing CEL specification reference. Use the same linked or defined terminology in the decision-log example.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread internal/cli/dispatch.go
cmd.Flags().StringVar(&eventName, "event-name", "", "GitHub event name (default: GITHUB_EVENT_NAME)")
cmd.Flags().StringVar(&eventAction, "event-action", "", "GitHub event action")
cmd.Flags().StringVar(&forgeToken, "forge-token", "", "Forge API token (default: GH_TOKEN, GITHUB_TOKEN, or gh auth token)")
cmd.Flags().StringVar(&route, "route", "", "Decide routing for one built-in agent (review) and print one JSON line with decision run, skip or bash; --output-driver is ignored")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

8. Users cannot find the new route flag 📘 Rule violation ⚙ Maintainability

newDispatchCmd adds --route and introduces FULLSEND_CEL_ROUTING_REVIEW, but the general CLI
references and repository-variable table are not updated, and the PR does not state that
docs/contributing/documentation.md was consulted. Users consulting those references lack the
flag’s usage and the variable’s behavior and defaults, while later maintainers lack a record that
the documentation checklist was followed.
Agent Prompt
## Issue description
The new `fullsend dispatch --route review` flag and `FULLSEND_CEL_ROUTING_REVIEW` variable are missing from the required general documentation references, and the PR does not record consultation of `docs/contributing/documentation.md`.

## Fix Focus Areas
- internal/cli/dispatch.go[59-59]
- docs/guides/getting-started/operations.md[1-1]
- docs/guides/dev/cli-internals.md[1-1]
- docs/cli/README.md[1-1]
- docs/guides/infrastructure/infrastructure-reference.md[352-352]

## Recommended Fix
Document `--route review`, its output format, and its ignored output-driver semantics in the applicable CLI reference and CLI internals documentation. Add `FULLSEND_CEL_ROUTING_REVIEW` to the repository-variable table with its `off`, `shadow`, and `on` values, default behavior, and a link to the review-routing guide. Follow the documentation guide’s discovery and cross-reference requirements, and note in the PR description that the guide was consulted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment on lines +117 to +119
harnessPath, deps, err := resolveAgentSource(ctx, absConfigDir, o.agent, forgeClient, cfg, composeOpts, printer)
if err != nil {
return d, err

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

9. Denied events still fetch review harnesses 🐞 Bug ➹ Performance

routeBuiltinAgent resolves and loads the harness before calling AuthorizeEvent, so authorization
does not protect those fetches. An unauthorized PR or comment event can repeatedly fetch a
configured URL source or remote base before receiving a skip decision, unlike ordinary dispatch,
which authorizes before harness enumeration.
Agent Prompt
## Issue description
The route path performs potentially remote harness resolution before applying its event authorization gate.
## Fix Focus Areas
- internal/cli/dispatch_route.go[117-137]
## Recommended Fix
Apply event authorization before resolving or loading remote harness content where a denied event needs no harness. Preserve the no-trigger compatibility decision explicitly when reorganizing this flow.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment on lines +103 to +107
// Resolve forge: blocks for the event's forge, as `fullsend run` does.
switch o.event.Source.System {
case normevent.SystemGitHub, normevent.SystemGitLab:
composeOpts.ForgePlatform = string(o.event.Source.System)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

10. Configured forge can block cel routing 🐞 Bug ≡ Correctness

routeBuiltinAgent chooses the harness forge platform from the event source instead of using
config.forge precedence as fullsend run does. A repository configured for a different forge can
therefore load a different overlay or fail a forge-specific harness load, making route mode fall
back to bash rather than deciding against the harness that review execution uses.
Agent Prompt
## Issue description
Route mode derives the harness forge platform from the event even when repository configuration specifies a different platform for run mode.
## Fix Focus Areas
- internal/cli/dispatch_route.go[96-107]
- internal/cli/run.go[6338-6365]
## Recommended Fix
Select `ForgePlatform` with the same configuration and environment precedence used by `fullsend run`, then test route mode with `config.forge` and a forge-specific harness block.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment on lines +186 to +194
- name: Guard vendored install for CEL review route
if: steps.cel-config.outcome == 'success' && steps.cel-cli-mode.outputs.mode == 'vendored'
shell: bash
run: |
set -euo pipefail
if [[ ! -f cel-route/.fullsend/bin/fullsend ]]; then
echo "::error::broken --vendor install: vendored marker present but .fullsend/bin/fullsend is missing"
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. A broken cli install in shadow mode stops all dispatch 🐞 Bug ☼ Reliability

None of the new install steps in the Route job have continue-on-error: not the CEL config
checkout, the vendored guard (which runs exit 1 itself), either install step, the upstream action
checkout, or the cache-artifact cp. Only "Evaluate CEL review route" and the cache save do. If any
of those steps fails while the variable is shadow or on, every later step is skipped, including
"Determine stage" (it runs only when earlier steps succeeded). The Route job then fails, so no stage
runs (triage, code, fix, retro or review) for that PR or comment event, even though shadow is meant
to be risk-free.
Agent Prompt
## Issue description
The CEL review-route install steps in the Route job can fail the whole job. When that happens "Determine stage" is skipped and no agent stage is dispatched, even in shadow mode.

## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[155-260]

## Recommended Fix
Add `continue-on-error: true` to every cel-* step: checkout, mode detect, vendored guard, cache restore, both installs, the upstream action checkout, expose and prepare. Gate "Evaluate CEL review route" on the install having succeeded, for example by checking that `command -v fullsend` works inside the step, so that "Determine stage" always runs and sees a non-success outcome. That outcome keeps the bash stage with ::warning:: in shadow or ::error:: in on.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment on lines +605 to +610
CEL_ROUTE_SOURCE="cel"
case "${CEL_REVIEW_DECISION}" in
run) STAGE="review" ;;
skip) STAGE="" ;;
*) CEL_ROUTE_SOURCE="bash" ;;
esac

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

11. A trigger can start review on a plain issue comment 🐞 Bug ≡ Correctness

In on mode, the run branch sets STAGE=review for any issue_comment without checking
ISSUE_IS_PR, and the documented /fs-review trigger checks the command and actor but not whether
the comment is on a pull request. A /fs-review comment on an ordinary issue can therefore reach
the Review job with the issue’s URL and number as PR context, without a PR-head lookup or
pull_request payload.
Agent Prompt
## Issue description
In `on` mode, a CEL `run` decision can select the PR-only Review job for a comment on an ordinary issue. The documented `/fs-review` example trigger also permits those comments.

## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[593-610]
- docs/guides/user/customizing-agents.md[760-769]

## Recommended Fix
In the `on` branch, map `run` to `STAGE=review` only for `pull_request_target` events or `issue_comment` events with `ISSUE_IS_PR == true`. Otherwise, log a warning and leave `STAGE` empty. Add `&& (event.entity.kind == "change_proposal" || has(event.entity.linked_change_proposal))` to the documented example trigger.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

with:
mode: upstream
workflow_repository: ${{ job.workflow_repository }}
workflow_sha: ${{ job.workflow_sha }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

13. Reviews can use a different trigger 🔗 Cross-repo conflict ≡ Correctness

The CEL route installs and caches the CLI at job.workflow_sha, while the Review job uses
inputs.fullsend_version || job.workflow_sha; because the CLI build determines the agents ref, they
can resolve different review-harness triggers. When a caller overrides fullsend_version, CEL can
return run or skip for a trigger the executed harness does not have, return run where bash
is appropriate, or fall back to bash if the workflow-SHA CLI does not support --route.
Agent Prompt
## Issue description
An explicit `fullsend_version` changes the release used by Review but not the CLI used for CEL routing, so routing can evaluate a different review harness or use a CLI without `--route`.

## Fix Focus Areas
- .github/workflows/reusable-dispatch.yml[198-260]
- .github/workflows/reusable-dispatch.yml[1216-1223]

## Recommended Fix
Install the route CLI using the same effective version as Review, `inputs.fullsend_version || job.workflow_sha`, and include that value in the route CLI cache key so it cannot reuse a binary built for another version. Test routing with a caller-supplied `fullsend_version`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

@codecov

codecov Bot commented Oct 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.22936% with 27 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/cli/dispatch_route.go 75.71% 9 Missing and 8 partials ⚠️
internal/cli/dispatch.go 76.19% 3 Missing and 2 partials ⚠️
internal/harnessdispatch/authorize.go 70.58% 2 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

@fullsend-ai-review

Copy link
Copy Markdown

Review skipped — this PR is already closed.

The /fs-review command only reviews open PRs/MRs.

Posted by fullsend post-review check

This branch was successfully deployed

1 active deployment
dev — 26fd08d9 Deployed Oct 22, 2026 by waynesun09 via behaviour #17686
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.

feat(dispatch): let a config.yaml CEL trigger decide when review runs

1 participant