Skip to content

ci: dynamically select eval agents from changed files - #145

Closed
ralphbean wants to merge 3 commits into
mainfrom
ci/dynamic-eval-agent-selection
Closed

ci: dynamically select eval agents from changed files#145
ralphbean wants to merge 3 commits into
mainfrom
ci/dynamic-eval-agent-selection

Conversation

@ralphbean

Copy link
Copy Markdown
Member

Summary

  • Adds .github/scripts/select-eval-agents.sh which parses harness/*.yaml to determine which agents need functional testing based on changed files in a PR
  • Replaces hardcoded run-functional.sh triage / run-functional.sh review steps with a loop over dynamically selected agents
  • Removes the redundant relevant files grep check — agent selection subsumes it
  • Adds missing paths to the push filter (env/**, common/**, policies/**, skills/**, plugins/**, docs/**)

This solves the pull_request_target chicken-and-egg problem: new agents can be added with their eval configs in a single PR without also needing to modify the workflow YAML.

Test plan

  • 15 unit tests in select-eval-agents-test.sh covering direct harness changes, transitive references, multi-agent selection, exclusion of agents without eval configs, and variable path filtering
  • Verified against real repo harness files
  • Workflow YAML validates cleanly
  • CI runs on this PR

🤖 Generated with Claude Code

ralphbean and others added 3 commits July 10, 2026 15:27
Adds eval/review/ with a single case (001-clean-approve) that creates
a PR adding multiply/divide functions to a simple Python calc module.
The PR is clean and well-tested — the review agent should approve it
and produce a ready-for-merge label.

Also extends eval/scripts/run-fullsend.sh to export PR_NUMBER and
REPO_FULL_NAME for pull_request fixtures, which the review agent's
pre-review.sh requires.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
The workflow was hardcoded to only run triage evals. Add a step
to also run the review eval cases.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
Replace hardcoded agent names in the functional-tests workflow with a
script that parses harness/*.yaml to determine which agents' tests to
run based on the changed files in a PR. This allows new agents to be
added (with their eval configs) in a single PR without also needing to
modify the workflow file — solving the pull_request_target chicken-and-egg
problem.

The select-eval-agents.sh script reads changed files on stdin, extracts
all file path references from each harness YAML (agent prompt, doc,
policy, scripts, host_files, skills, plugins, schemas, forge scripts),
and outputs agent names whose referenced files were touched. Only agents
with an eval/<agent>/eval.yaml config are candidates.

Includes 15 test cases covering direct harness changes, transitive
references (env files, shared scripts, skill/plugin subdirectories),
multi-agent selection, exclusion of agents without eval configs, and
variable host_file path filtering.

Signed-off-by: Ryan Beans <rbean@redhat.com>
Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
@ralphbean
ralphbean requested a review from a team as a code owner July 13, 2026 10:46
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 13, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:47 AM UTC · Completed 11:00 AM UTC
Commit: 7b39f3f · View workflow run →

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

CI: dynamically select eval agents and add review functional eval

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Dynamically select which eval agents to run based on PR file changes and harness references.
• Add a first review-agent functional eval case and its eval configuration.
• Expand workflow path filters and remove redundant “relevant changes” gating.
Diagram

graph TD
  evt(["Workflow trigger"]) --> gh["Fetch changed files (gh api)"] --> files["Changed file list"] --> selector["select-eval-agents.sh"] --> agents["Selected agent names"] --> run["run-functional.sh (per agent)"]
  selector --> harness[("harness/*.yaml")]
  selector --> evalcfg[("eval/*/eval.yaml")]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Static agent matrix in workflow
  • ➕ Very simple and transparent in YAML
  • ➕ No dependency on yq parsing harness structure
  • ➖ Reintroduces the chicken-and-egg problem for new agents
  • ➖ Requires workflow edits for every agent addition/removal
2. Central manifest (e.g., eval/agents.json) listing refs
  • ➕ Single explicit source of truth; easier to validate and lint
  • ➕ Decouples selection logic from harness YAML schema drift
  • ➖ Duplicates information already present in harness YAML
  • ➖ Requires maintaining the manifest alongside harness changes
3. Use paths-filter action + per-agent rules
  • ➕ Standard GitHub Actions pattern; avoids custom parsing
  • ➕ Rules can be reviewed/edited directly in workflow
  • ➖ Still requires updating workflow when adding agents or references
  • ➖ Harder to model transitive references (skills/plugins/scripts) without duplication

Recommendation: The PR’s approach (derive affected agents from harness YAML and require eval//eval.yaml to exist) is the best fit for the stated goal: it lets new agents land in a single PR without workflow edits, while still correctly selecting transitive dependencies like skills/plugins/scripts. If harness schema evolves, consider adding a lightweight validation step (or yq query unit tests) to keep selection robust.

Files changed (10) +815 / -36

Enhancement (1) +90 / -0
select-eval-agents.shSelect functional eval agents by parsing harness YAML references +90/-0

Select functional eval agents by parsing harness YAML references

• Adds a script that reads changed file paths from stdin and emits agent names whose functional evals should run. It parses each harness/*.yaml with yq, matches changes against referenced paths (including directory-prefix matches), and only selects agents that have eval/<agent>/eval.yaml.

.github/scripts/select-eval-agents.sh

Bug fix (1) +5 / -1
run-fullsend.shExport PR context variables for pull_request fixtures +5/-1

Export PR context variables for pull_request fixtures

• Extends the pull_request fixture env file generation to include PR_NUMBER and REPO_FULL_NAME alongside GITHUB_PR_URL, enabling downstream scripts that require explicit PR context.

eval/scripts/run-fullsend.sh

Tests (6) +476 / -0
select-eval-agents-test.shAdd bash unit tests for eval-agent selection logic +310/-0

Add bash unit tests for eval-agent selection logic

• Introduces a fixture-based bash test suite covering direct harness changes, referenced file changes, multi-agent selection, and exclusion of agents without eval configs. Validates edge cases like variable-expanded host_files entries being ignored.

.github/scripts/select-eval-agents-test.sh

annotations.yamlDefine expected outcomes for first review-agent functional case +33/-0

Define expected outcomes for first review-agent functional case

• Adds label expectations and judging guidance for a clean PR scenario where the review agent should approve and apply ready-for-merge. Sets turn and cost budgets to bound the evaluation run.

eval/review/cases/001-clean-approve/annotations.yaml

input.yamlAdd PR fixture input for review-agent clean-approve case +85/-0

Add PR fixture input for review-agent clean-approve case

• Defines a GitHub PR fixture that adds multiply/divide to a small Python module with corresponding tests. Encodes PR title/body and file contents used during the functional evaluation.

eval/review/cases/001-clean-approve/input.yaml

README.mdSeed base repo README for review fixture repository +18/-0

Seed base repo README for review fixture repository

• Adds minimal documentation for the python-calc fixture repository used as the PR base state in evaluation.

eval/review/cases/001-clean-approve/repo/README.md

calc.pySeed base calc module for review fixture repository +11/-0

Seed base calc module for review fixture repository

• Adds the initial calculator module with add/subtract functions as the baseline that the PR fixture modifies.

eval/review/cases/001-clean-approve/repo/src/calc.py

test_calc.pySeed base tests for calc module in review fixture repository +19/-0

Seed base tests for calc module in review fixture repository

• Adds baseline pytest coverage for add/subtract in the fixture repo, ensuring the PR’s new tests extend an existing suite.

eval/review/cases/001-clean-approve/repo/tests/test_calc.py

Other (2) +244 / -35
functional-tests.ymlRun functional tests for dynamically selected agents +61/-35

Run functional tests for dynamically selected agents

• Expands push path filters to include additional referenced directories and replaces the prior “relevant changes” grep gate with a changed-files output. Adds an agent-selection step and updates downstream steps to run only when at least one agent is selected, looping run-functional.sh across the selected set.

.github/workflows/functional-tests.yml

eval.yamlAdd review agent eval configuration and judges +183/-0

Add review agent eval configuration and judges

• Introduces the review agent’s functional eval definition, including runner command, environment wiring, dataset layout, and judges for review quality, required/forbidden labels, and resource budgets.

eval/review/eval.yaml

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (0) 📜 Skill insights (2)

Context used
✅ Compliance rules (platform): 55 rules
✅ Skills: 4 invoked
  code-review
  code-implementation
  pr-review
  docs-review

Grey Divider


Action required

1. ::warning:: echoes $FILE_COUNT 📜 Skill insight ⛨ Security
Description
The workflow emits GitHub Actions workflow commands with an interpolated variable ($FILE_COUNT)
that is not sanitized. This can allow workflow-command injection if the value contains control
characters, ::, or encoded newlines, violating the requirement to sanitize every interpolated
value individually.
Code

.github/workflows/functional-tests.yml[104]

+              echo "::warning::Compare API returned $FILE_COUNT files (possible truncation at 300) — running all functional tests as a precaution"
Relevance

⭐⭐⭐ High

Workflow-command injection sanitization has been explicitly accepted for interpolated variables in
::error:: messages.

PR-#90

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance requires sanitizing every interpolated variable used inside GitHub Actions workflow
commands. The workflow currently emits ::warning::... while interpolating $FILE_COUNT directly
in the command string.

.github/workflows/functional-tests.yml[104-104]
Skill: pr-review

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 GitHub Actions workflow command (`::warning::...`) interpolates `$FILE_COUNT` without sanitization. Per the checklist, every interpolated value in a workflow command must be sanitized individually (for `::`, `%0A/%0D`, ANSI escapes, and control characters).

## Issue Context
This occurs in the `functional-tests.yml` workflow in the step that warns about Compare API truncation. Even if `$FILE_COUNT` is expected to be numeric, the compliance requirement is explicit that each interpolated value must be sanitized.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[104-104]

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


2. Protected .github/ paths modified 📜 Skill insight § Compliance
Description
This PR modifies protected governance/infrastructure paths under .github/ (workflows and scripts).
Per policy, such changes require explicit human review and must not be auto-approved.
Code

.github/workflows/functional-tests.yml[R18-23]

+      - 'env/**'
+      - 'common/**'
+      - 'policies/**'
+      - 'skills/**'
+      - 'plugins/**'
+      - 'docs/**'
Relevance

⭐⭐ Medium

Only prior mention of “protected governance paths” review requirement was undetermined; no clear
enforcement history.

PR-#29

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The diff shows modifications under .github/workflows/ and new scripts under .github/scripts/,
which are listed as protected paths requiring a compliance finding and human approval.

.github/workflows/functional-tests.yml[18-23]
Skill: pr-review

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

## Issue description
Protected governance/infrastructure paths are modified in this PR (e.g., `.github/workflows/...`, `.github/scripts/...`). These changes must not be auto-approved and should receive explicit human review.

## Issue Context
The compliance requirement triggers on *any* modification to protected paths.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[18-23]
- .github/scripts/select-eval-agents.sh[1-90]
- .github/scripts/select-eval-agents-test.sh[1-310]

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


3. GITHUB_OUTPUT injection risk 🐞 Bug ⛨ Security
Description
The workflow writes the PR file list to $GITHUB_OUTPUT using a fixed heredoc delimiter (GHEOF), so a
crafted filename containing a line equal to that delimiter can terminate the value early and inject
additional output records. In pull_request_target this lets an untrusted PR manipulate step outputs
(e.g., selected agents / whether later steps run).
Code

.github/workflows/functional-tests.yml[R113-117]

+          {
+            echo 'files<<GHEOF'
+            echo "$FILES"
+            echo 'GHEOF'
+          } >> "$GITHUB_OUTPUT"
Relevance

⭐⭐ Medium

No clear historical acceptance/rejection for fixed-delimiter $GITHUB_OUTPUT multiline injection
concerns in workflows.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The workflow is triggered by pull_request_target and writes the GitHub API-derived filenames into a
fixed-delimiter multiline output, which is the documented injection primitive for output
corruption/injection.

.github/workflows/functional-tests.yml[27-31]
.github/workflows/functional-tests.yml[86-117]
.github/workflows/functional-tests.yml[141-161]

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 workflow writes untrusted, PR-controlled file paths into `$GITHUB_OUTPUT` using a constant delimiter (`GHEOF`). If any filename includes a newline-delimited `GHEOF` line, it can break the multiline output format and inject additional outputs.

## Issue Context
This output comes from GitHub API (`gh api .../pulls/.../files`) and is attacker-controlled in `pull_request_target` runs.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[86-117]
- .github/workflows/functional-tests.yml[141-161]

## Suggested fix
- Generate a per-step random delimiter (e.g., `DELIM=$(uuidgen)` or `openssl rand -hex 16`) and use it for the multiline output blocks.
- Prefer `printf '%s\n' "$FILES"`/`printf '%s\n' "$AGENTS"` over `echo` to avoid implementation-defined behavior.
- Apply the same hardening to both `files<<...` and `agents<<...` blocks.

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



Remediation recommended

4. New tests not in CI 🐞 Bug ⚙ Maintainability
Description
The PR adds .github/scripts/select-eval-agents-test.sh but it is not invoked by the repo’s existing
make script-test target used in CI. As a result, regressions in select-eval-agents.sh can merge
without the stated unit tests running.
Code

.github/scripts/select-eval-agents-test.sh[R1-22]

+#!/usr/bin/env bash
+# Tests for select-eval-agents.sh
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+SELECT_SCRIPT="${SCRIPT_DIR}/select-eval-agents.sh"
+FAILURES=0
+TESTS=0
+
+fail() {
+  echo "FAIL: $1"
+  FAILURES=$((FAILURES + 1))
+}
+
+pass() {
+  echo "PASS: $1"
+}
+
+run_test() {
+  TESTS=$((TESTS + 1))
+}
+
Relevance

⭐⭐⭐ High

Team previously added script tests and wired them into Makefile/CI; expects new test scripts
included.

PR-#37
PR-#89

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new test file exists, but the CI entrypoint (make script-test) doesn’t include it, and the
script-test workflow uses that target.

.github/scripts/select-eval-agents-test.sh[1-40]
Makefile[18-28]
.github/workflows/script-test.yml[26-35]

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 new unit test script was added but is not wired into the standard script-test target, so CI will not execute it.

## Issue Context
`.github/workflows/script-test.yml` runs `make script-test`; the Makefile target currently doesn’t include the new test.

## Fix Focus Areas
- Makefile[18-28]
- .github/workflows/script-test.yml[35-35]

## Suggested fix
- Add a line to `script-test:`:
 - `$(call run-timed,bash .github/scripts/select-eval-agents-test.sh)`
- Ensure any dependencies the test needs (notably `yq`) are already installed in the script-test workflow (they are today).

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


5. YQ failures skip agents 🐞 Bug ☼ Reliability
Description
select-eval-agents.sh suppresses yq parse errors (2>/dev/null) and consumes the extraction via
process substitution without checking exit status. If yq fails to parse a harness YAML, REFS becomes
empty and referenced-file changes can fail to select the correct agent, skipping functional tests.
Code

.github/scripts/select-eval-agents.sh[R33-57]

+extract_refs() {
+  local harness_file="$1"
+  yq -r '
+    [
+      .agent, .doc, .policy, .pre_script, .post_script,
+      .validation_loop.script, .validation_loop.schema,
+      (.host_files[]?.src),
+      (.skills[]?),
+      (.plugins[]?),
+      .forge.github.pre_script, .forge.github.post_script
+    ] | .[] | select(. != null)
+  ' "$harness_file" 2>/dev/null | grep -v '^\$' | sort -u
+}
+
+# For each harness file with an eval config, check if any changed file is relevant.
+for harness_file in "$REPO_ROOT"/harness/*.yaml; do
+  [[ -f "$harness_file" ]] || continue
+  agent="$(basename "$harness_file" .yaml)"
+
+  # Only consider agents that have eval configs
+  [[ -f "$REPO_ROOT/eval/$agent/eval.yaml" ]] || continue
+
+  # Collect all paths this agent cares about
+  mapfile -t REFS < <(extract_refs "$harness_file")
+
Relevance

⭐⭐ Medium

No prior reviews found about failing yq/mapfile exit-status handling in bash scripts.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The script redirects yq errors to /dev/null and reads its output via process substitution into
mapfile, which does not enforce the producer’s exit status; this can yield empty REFS with no error
surfaced to the caller.

.github/scripts/select-eval-agents.sh[31-57]

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

## Issue description
`extract_refs()` hides `yq` errors and its failure status is not checked (it is consumed via process substitution into `mapfile`). This can silently produce an empty reference set and cause incorrect agent selection (missing required functional tests).

## Issue Context
This script is used to decide which functional tests to run; under-selection means CI coverage gaps.

## Fix Focus Areas
- .github/scripts/select-eval-agents.sh[33-57]

## Suggested fix
- Stop discarding yq stderr (`2>/dev/null`) so failures are diagnosable.
- Capture and check exit status explicitly (e.g., run `refs=$(extract_refs ...)` and check `$?`), or write refs to a temp file and check the producing command.
- Decide a fail-safe policy on parse failure (recommended: select the agent or all agents, or fail the step so CI doesn’t silently skip tests).

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



Informational

6. Eval glob can yield '*' 🐞 Bug ☼ Reliability
Description
The workflow’s fallback agent enumeration uses for d in eval/*/eval.yaml without nullglob, so if
no eval configs match it can emit a literal * agent name. This can make the job attempt
./eval/run-functional.sh '*' and fail unexpectedly.
Code

.github/workflows/functional-tests.yml[R146-151]

+          if [ -n "$CHANGED_FILES" ]; then
+            AGENTS=$(echo "$CHANGED_FILES" | .github/scripts/select-eval-agents.sh)
+          else
+            # push/workflow_dispatch: run all agents with eval configs
+            AGENTS=$(for d in eval/*/eval.yaml; do basename "$(dirname "$d")"; done)
+          fi
Relevance

⭐⭐ Medium

No historical evidence found for nullglob/unmatched-glob hardening in GitHub Actions bash snippets.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The fallback branch enumerates eval/*/eval.yaml directly with no no-match guard, which is the
classic Bash unmatched-glob pitfall.

.github/workflows/functional-tests.yml[141-151]

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 fallback agent enumeration assumes `eval/*/eval.yaml` matches at least one file; without `nullglob`, an empty match produces a literal pattern and yields `*` as an agent name.

## Issue Context
This happens when the workflow is in the “no changed-files list” branch and the repo has no eval configs matching that layout.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[146-151]

## Suggested fix
- Use `shopt -s nullglob` with an array:
 - `shopt -s nullglob; configs=(eval/*/eval.yaml)`
 - If `${#configs[@]}==0`, set `AGENTS=""` (or emit a notice) and skip.
- Or use `find eval -mindepth 2 -maxdepth 2 -name eval.yaml` and extract the parent directory names.

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


7. Setup runs before selection 🐞 Bug ➹ Performance
Description
The workflow installs Python, uv, and agent-eval-harness before determining whether any agents are
selected for testing. When no agents are selected, these setup steps still run and increase CI
time/cost unnecessarily.
Code

.github/workflows/functional-tests.yml[R119-162]

      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
-        if: steps.changes.outputs.relevant != 'false'
        with:
          ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }}
          persist-credentials: false
          allow-unsafe-pr-checkout: ${{ github.event_name == 'pull_request_target' }}
          submodules: true

      - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
-        if: steps.changes.outputs.relevant != 'false'
        with:
          python-version: "3.12"

      - name: Install uv
-        if: steps.changes.outputs.relevant != 'false'
        uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0

      - name: Install agent-eval-harness
-        if: steps.changes.outputs.relevant != 'false'
        run: uv pip install --system -e 'eval/.agent-eval-harness[anthropic]'

      - name: Install yq
-        if: steps.changes.outputs.relevant != 'false'
        run: |
          curl -sSfL "https://github.com/mikefarah/yq/releases/download/v4.47.1/yq_linux_amd64" -o /usr/local/bin/yq
          chmod +x /usr/local/bin/yq

+      - name: Select eval agents
+        id: agents
+        env:
+          CHANGED_FILES: ${{ steps.changes.outputs.files }}
+        run: |
+          if [ -n "$CHANGED_FILES" ]; then
+            AGENTS=$(echo "$CHANGED_FILES" | .github/scripts/select-eval-agents.sh)
+          else
+            # push/workflow_dispatch: run all agents with eval configs
+            AGENTS=$(for d in eval/*/eval.yaml; do basename "$(dirname "$d")"; done)
+          fi
+          if [ -z "$AGENTS" ]; then
+            echo "::notice::No agents need functional testing for these changes"
+          else
+            echo "Selected agents: $(echo "$AGENTS" | tr '\n' ' ')"
+          fi
+          {
+            echo 'agents<<GHEOF'
+            echo "$AGENTS"
+            echo 'GHEOF'
+          } >> "$GITHUB_OUTPUT"
+
Relevance

⭐⭐ Medium

No historical evidence found about reordering/gating setup steps to save CI time before selection.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The dependency installs occur before the selection step, while the first `if:
steps.agents.outputs.agents != ''` gating appears only after selection; therefore the job can do
substantial work even when no agents are selected.

.github/workflows/functional-tests.yml[119-171]

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

## Issue description
Several expensive setup steps run unconditionally even when `Select eval agents` would produce an empty list and the job would otherwise skip running tests.

## Issue Context
Selection requires checkout and `yq`, but not Python/uv/harness installation.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[119-162]
- .github/workflows/functional-tests.yml[163-171]

## Suggested fix
- Reorder steps to: checkout → install yq (or use a preinstalled yq) → select agents → conditionally install Python/uv/agent-eval-harness/fullsend/etc only when agents are non-empty.
- This keeps behavior the same while reducing runtime for PRs that select no agents.

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


Grey Divider

Qodo Logo

if [ "$FILE_COUNT" -ge 300 ]; then
echo "::warning::Compare API returned $FILE_COUNT files (possible truncation at 300) — running functional tests as a precaution"
echo "relevant=true" >> "$GITHUB_OUTPUT"
echo "::warning::Compare API returned $FILE_COUNT files (possible truncation at 300) — running all functional tests as a precaution"

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. ::warning:: echoes $file_count 📜 Skill insight ⛨ Security

The workflow emits GitHub Actions workflow commands with an interpolated variable ($FILE_COUNT)
that is not sanitized. This can allow workflow-command injection if the value contains control
characters, ::, or encoded newlines, violating the requirement to sanitize every interpolated
value individually.
Agent Prompt
## Issue description
A GitHub Actions workflow command (`::warning::...`) interpolates `$FILE_COUNT` without sanitization. Per the checklist, every interpolated value in a workflow command must be sanitized individually (for `::`, `%0A/%0D`, ANSI escapes, and control characters).

## Issue Context
This occurs in the `functional-tests.yml` workflow in the step that warns about Compare API truncation. Even if `$FILE_COUNT` is expected to be numeric, the compliance requirement is explicit that each interpolated value must be sanitized.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[104-104]

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

Comment on lines +18 to +23
- 'env/**'
- 'common/**'
- 'policies/**'
- 'skills/**'
- 'plugins/**'
- 'docs/**'

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

2. Protected .github/ paths modified 📜 Skill insight § Compliance

This PR modifies protected governance/infrastructure paths under .github/ (workflows and scripts).
Per policy, such changes require explicit human review and must not be auto-approved.
Agent Prompt
## Issue description
Protected governance/infrastructure paths are modified in this PR (e.g., `.github/workflows/...`, `.github/scripts/...`). These changes must not be auto-approved and should receive explicit human review.

## Issue Context
The compliance requirement triggers on *any* modification to protected paths.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[18-23]
- .github/scripts/select-eval-agents.sh[1-90]
- .github/scripts/select-eval-agents-test.sh[1-310]

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

Comment on lines +113 to +117
{
echo 'files<<GHEOF'
echo "$FILES"
echo 'GHEOF'
} >> "$GITHUB_OUTPUT"

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. Github_output injection risk 🐞 Bug ⛨ Security

The workflow writes the PR file list to $GITHUB_OUTPUT using a fixed heredoc delimiter (GHEOF), so a
crafted filename containing a line equal to that delimiter can terminate the value early and inject
additional output records. In pull_request_target this lets an untrusted PR manipulate step outputs
(e.g., selected agents / whether later steps run).
Agent Prompt
## Issue description
The workflow writes untrusted, PR-controlled file paths into `$GITHUB_OUTPUT` using a constant delimiter (`GHEOF`). If any filename includes a newline-delimited `GHEOF` line, it can break the multiline output format and inject additional outputs.

## Issue Context
This output comes from GitHub API (`gh api .../pulls/.../files`) and is attacker-controlled in `pull_request_target` runs.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[86-117]
- .github/workflows/functional-tests.yml[141-161]

## Suggested fix
- Generate a per-step random delimiter (e.g., `DELIM=$(uuidgen)` or `openssl rand -hex 16`) and use it for the multiline output blocks.
- Prefer `printf '%s\n' "$FILES"`/`printf '%s\n' "$AGENTS"` over `echo` to avoid implementation-defined behavior.
- Apply the same hardening to both `files<<...` and `agents<<...` blocks.

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

Comment on lines +33 to +57
extract_refs() {
local harness_file="$1"
yq -r '
[
.agent, .doc, .policy, .pre_script, .post_script,
.validation_loop.script, .validation_loop.schema,
(.host_files[]?.src),
(.skills[]?),
(.plugins[]?),
.forge.github.pre_script, .forge.github.post_script
] | .[] | select(. != null)
' "$harness_file" 2>/dev/null | grep -v '^\$' | sort -u
}

# For each harness file with an eval config, check if any changed file is relevant.
for harness_file in "$REPO_ROOT"/harness/*.yaml; do
[[ -f "$harness_file" ]] || continue
agent="$(basename "$harness_file" .yaml)"

# Only consider agents that have eval configs
[[ -f "$REPO_ROOT/eval/$agent/eval.yaml" ]] || continue

# Collect all paths this agent cares about
mapfile -t REFS < <(extract_refs "$harness_file")

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

4. Yq failures skip agents 🐞 Bug ☼ Reliability

select-eval-agents.sh suppresses yq parse errors (2>/dev/null) and consumes the extraction via
process substitution without checking exit status. If yq fails to parse a harness YAML, REFS becomes
empty and referenced-file changes can fail to select the correct agent, skipping functional tests.
Agent Prompt
## Issue description
`extract_refs()` hides `yq` errors and its failure status is not checked (it is consumed via process substitution into `mapfile`). This can silently produce an empty reference set and cause incorrect agent selection (missing required functional tests).

## Issue Context
This script is used to decide which functional tests to run; under-selection means CI coverage gaps.

## Fix Focus Areas
- .github/scripts/select-eval-agents.sh[33-57]

## Suggested fix
- Stop discarding yq stderr (`2>/dev/null`) so failures are diagnosable.
- Capture and check exit status explicitly (e.g., run `refs=$(extract_refs ...)` and check `$?`), or write refs to a temp file and check the producing command.
- Decide a fail-safe policy on parse failure (recommended: select the agent or all agents, or fail the step so CI doesn’t silently skip tests).

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

Comment on lines +146 to +151
if [ -n "$CHANGED_FILES" ]; then
AGENTS=$(echo "$CHANGED_FILES" | .github/scripts/select-eval-agents.sh)
else
# push/workflow_dispatch: run all agents with eval configs
AGENTS=$(for d in eval/*/eval.yaml; do basename "$(dirname "$d")"; done)
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.

Informational

5. Eval glob can yield '*' 🐞 Bug ☼ Reliability

The workflow’s fallback agent enumeration uses for d in eval/*/eval.yaml without nullglob, so if
no eval configs match it can emit a literal * agent name. This can make the job attempt
./eval/run-functional.sh '*' and fail unexpectedly.
Agent Prompt
## Issue description
The fallback agent enumeration assumes `eval/*/eval.yaml` matches at least one file; without `nullglob`, an empty match produces a literal pattern and yields `*` as an agent name.

## Issue Context
This happens when the workflow is in the “no changed-files list” branch and the repo has no eval configs matching that layout.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[146-151]

## Suggested fix
- Use `shopt -s nullglob` with an array:
  - `shopt -s nullglob; configs=(eval/*/eval.yaml)`
  - If `${#configs[@]}==0`, set `AGENTS=""` (or emit a notice) and skip.
- Or use `find eval -mindepth 2 -maxdepth 2 -name eval.yaml` and extract the parent directory names.

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

Comment on lines +1 to +22
#!/usr/bin/env bash
# Tests for select-eval-agents.sh
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SELECT_SCRIPT="${SCRIPT_DIR}/select-eval-agents.sh"
FAILURES=0
TESTS=0

fail() {
echo "FAIL: $1"
FAILURES=$((FAILURES + 1))
}

pass() {
echo "PASS: $1"
}

run_test() {
TESTS=$((TESTS + 1))
}

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. New tests not in ci 🐞 Bug ⚙ Maintainability

The PR adds .github/scripts/select-eval-agents-test.sh but it is not invoked by the repo’s existing
make script-test target used in CI. As a result, regressions in select-eval-agents.sh can merge
without the stated unit tests running.
Agent Prompt
## Issue description
A new unit test script was added but is not wired into the standard script-test target, so CI will not execute it.

## Issue Context
`.github/workflows/script-test.yml` runs `make script-test`; the Makefile target currently doesn’t include the new test.

## Fix Focus Areas
- Makefile[18-28]
- .github/workflows/script-test.yml[35-35]

## Suggested fix
- Add a line to `script-test:`:
  - `$(call run-timed,bash .github/scripts/select-eval-agents-test.sh)`
- Ensure any dependencies the test needs (notably `yq`) are already installed in the script-test workflow (they are today).

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

Comment on lines 119 to +162
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
if: steps.changes.outputs.relevant != 'false'
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
allow-unsafe-pr-checkout: ${{ github.event_name == 'pull_request_target' }}
submodules: true

- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
if: steps.changes.outputs.relevant != 'false'
with:
python-version: "3.12"

- name: Install uv
if: steps.changes.outputs.relevant != 'false'
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0

- name: Install agent-eval-harness
if: steps.changes.outputs.relevant != 'false'
run: uv pip install --system -e 'eval/.agent-eval-harness[anthropic]'

- name: Install yq
if: steps.changes.outputs.relevant != 'false'
run: |
curl -sSfL "https://github.com/mikefarah/yq/releases/download/v4.47.1/yq_linux_amd64" -o /usr/local/bin/yq
chmod +x /usr/local/bin/yq

- name: Select eval agents
id: agents
env:
CHANGED_FILES: ${{ steps.changes.outputs.files }}
run: |
if [ -n "$CHANGED_FILES" ]; then
AGENTS=$(echo "$CHANGED_FILES" | .github/scripts/select-eval-agents.sh)
else
# push/workflow_dispatch: run all agents with eval configs
AGENTS=$(for d in eval/*/eval.yaml; do basename "$(dirname "$d")"; done)
fi
if [ -z "$AGENTS" ]; then
echo "::notice::No agents need functional testing for these changes"
else
echo "Selected agents: $(echo "$AGENTS" | tr '\n' ' ')"
fi
{
echo 'agents<<GHEOF'
echo "$AGENTS"
echo 'GHEOF'
} >> "$GITHUB_OUTPUT"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Informational

7. Setup runs before selection 🐞 Bug ➹ Performance

The workflow installs Python, uv, and agent-eval-harness before determining whether any agents are
selected for testing. When no agents are selected, these setup steps still run and increase CI
time/cost unnecessarily.
Agent Prompt
## Issue description
Several expensive setup steps run unconditionally even when `Select eval agents` would produce an empty list and the job would otherwise skip running tests.

## Issue Context
Selection requires checkout and `yq`, but not Python/uv/harness installation.

## Fix Focus Areas
- .github/workflows/functional-tests.yml[119-162]
- .github/workflows/functional-tests.yml[163-171]

## Suggested fix
- Reorder steps to: checkout → install yq (or use a preinstalled yq) → select agents → conditionally install Python/uv/agent-eval-harness/fullsend/etc only when agents are non-empty.
- This keeps behavior the same while reducing runtime for PRs that select no agents.

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

@fullsend-ai-review

Copy link
Copy Markdown

Review — comment

This PR replaces the hardcoded run-functional.sh triage with a dynamic agent selection mechanism that parses harness/*.yaml to determine which agents need functional testing based on changed files. It also adds the review agent eval configuration as a proof-of-concept for the new mechanism. The overall approach is sound — using harness configs as the source of truth for agent dependencies eliminates the chicken-and-egg problem for adding new agents.

Three medium-severity findings are worth discussing before merge.


Findings

1. Pipe subshell in test loop — first agent failure aborts remaining agents (medium · correctness)

File: .github/workflows/functional-tests.yml · "Run functional tests" step

The test loop pipes $SELECTED_AGENTS into while read:

echo "$SELECTED_AGENTS" | while read -r agent; do
  ./eval/run-functional.sh "$agent"
done

With GitHub Actions' default set -e -o pipefail, the while body runs in a pipe subshell. If run-functional.sh exits non-zero for the first agent (e.g., triage), set -e terminates the subshell immediately — subsequent agents (e.g., review) never run. The step correctly fails (pipefail propagates the error), but you lose visibility into whether other agents also have issues.

Remediation: Use a here-string to avoid the subshell and track failures independently:

failed=0
while read -r agent; do
  [ -z "$agent" ] && continue
  echo "=========================================="
  echo "Running functional tests: $agent"
  echo "=========================================="
  ./eval/run-functional.sh "$agent" || failed=1
done <<< "$SELECTED_AGENTS"
[ "$failed" -ne 0 ] && exit 1

2. GHEOF heredoc delimiter collision via crafted filenames (medium · injection-defense)

File: .github/workflows/functional-tests.yml · "Get changed files" step

The step writes PR filenames into GITHUB_OUTPUT using:

echo 'files<<GHEOF'
echo "$FILES"
echo 'GHEOF'

Filenames are fetched from the GitHub API and are attacker-controlled in fork PRs. A file literally named GHEOF prematurely terminates the heredoc. Combined with other specifically-named files (e.g., agents<<GHEOF2, malicious-agent, GHEOF2), an attacker could inject arbitrary GITHUB_OUTPUT entries, including the agents key consumed downstream.

This is mitigated by the gate job (which requires author authorization or ok-to-test label before the functional-tests job runs), but it's a defense-in-depth gap.

Remediation: Use a randomized delimiter:

DELIM="GHEOF_$(openssl rand -hex 8)"
{ echo "files<<${DELIM}"; echo "$FILES"; echo "${DELIM}"; } >> "$GITHUB_OUTPUT"

3. Shared eval infrastructure changes no longer trigger agent tests on PRs (medium · coverage-regression)

File: .github/scripts/select-eval-agents.sh

The old grep-based filter matched ^eval/ broadly — changes to eval/scripts/setup-fixture.sh, eval/scripts/capture-fixture.sh, or eval/scripts/run-fullsend.sh would set relevant=true and run triage tests. The new select-eval-agents.sh only matches eval/<agent>/ paths (e.g., eval/triage/, eval/review/), so changes to shared infrastructure under eval/scripts/ no longer select any agent for PR testing.

Similarly, config.yaml was in the old grep regex but isn't handled by the selection script.

Push-to-main still runs all agents (correct), but the coverage gap on PRs means infrastructure regressions are only caught after merge.

Remediation: Add a wildcard check in select-eval-agents.sh for shared paths that should trigger all agents:

for changed in "${CHANGED_FILES[@]}"; do
  case "$changed" in
    eval/scripts/*|config.yaml|.github/scripts/*|.github/workflows/functional-tests.yml)
      # Shared infrastructure — select all agents with eval configs
      for hf in "$REPO_ROOT"/harness/*.yaml; do
        [[ -f "$hf" ]] || continue
        a="$(basename "$hf" .yaml)"
        [[ -f "$REPO_ROOT/eval/$a/eval.yaml" ]] && echo "$a"
      done | sort -u
      exit 0
      ;;
  esac
done

4. Unconditional setup steps when no agents are selected (low · efficiency)

File: .github/workflows/functional-tests.yml

The if guards were removed from checkout, setup-python, uv, yq, and agent-eval-harness install steps. These now run unconditionally. This is necessary because yq (and checkout) are prerequisites for the "Select eval agents" step. However, setup-python, uv, and agent-eval-harness install are only needed for run-functional.sh, not for agent selection. On PRs that change only docs or README, these add ~1–2 minutes of unnecessary setup.

Functionally correct — the test step itself is properly guarded.


Notes

  • PR title follows Conventional Commits (ci: prefix) ✓
  • eval/review/ config is a reasonable inclusion — it exercises the new mechanism as a proof-of-concept and solves the stated chicken-and-egg problem
  • The run-fullsend.sh change correctly adds PR_NUMBER and REPO_FULL_NAME from FIXTURE_NUMBER and EPHEMERAL_REPO, which are set by setup-fixture.sh and propagated via hook outputs
  • The unit tests in select-eval-agents-test.sh are thorough (15 tests covering direct changes, transitive references, multi-agent selection, exclusion of agents without eval configs, and variable filtering)

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Jul 13, 2026

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review squad pass (3 agents: claude-coder, claude-researcher, gemini-code-review). 5 unique medium+ findings posted inline below. 4 other medium+ findings from the squad (GITHUB_OUTPUT heredoc injection, new tests not wired into CI, unconditional checkout/install steps, yq errors swallowed) matched existing unreplied comments from qodo-code-review[bot] and were skipped to avoid duplicates.

if [[ "$selected" == true ]]; then
echo "$agent"
fi
done

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[HIGH] Selector silently skips functional tests for changes to shared eval infra, CI scripts, and config.yaml

extract_refs() (lines 33-44) only inspects .agent, .doc, .policy, .pre_script, .post_script, .validation_loop.*, host_files[].src, skills[], plugins[], and forge.github.*. There's no rule for eval/scripts/**, .github/scripts/** (including this script itself — no self-regression coverage), .github/workflows/functional-tests.yml, or config.yaml.

The PR description says agent selection "subsumes" the old static grep-based path filter, but that filter matched all of these paths and ran tests unconditionally; this selector matches zero agents for them. Not hypothetical: this PR's own change to eval/scripts/run-fullsend.sh only gets tested because it ships alongside eval/review/eval.yaml in the same diff. A follow-up PR touching only the shared runner or this selector script gets zero functional-test signal, including at the merge_group gate before landing on main.

Suggestion: add a fallback rule — changes under eval/scripts/**, .github/scripts/**, .github/workflows/functional-tests.yml, or config.yaml should select all eval-configured agents (same as the push/workflow_dispatch fallback), not zero. Add a regression test asserting this.

run: ./eval/run-functional.sh triage
SELECTED_AGENTS: ${{ steps.agents.outputs.agents }}
run: |
echo "$SELECTED_AGENTS" | while read -r agent; do

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[HIGH] Multi-agent loop aborts on the first failing agent

echo "$SELECTED_AGENTS" | while read -r agent; do
  [ -z "$agent" ] && continue
  ...
  ./eval/run-functional.sh "$agent"
done

GitHub Actions run: steps execute with bash -eo pipefail by default. If the first selected agent's eval fails, the step aborts immediately and any remaining selected agents never run in that CI invocation — with no indication that they were skipped due to an earlier failure rather than not being selected. Previously only one agent ever ran per invocation, so this failure-isolation gap is new behavior introduced by generalizing to a loop.

Suggestion: capture each agent's exit code, continue the loop, and exit non-zero at the end after all selected agents have run, e.g.:

overall_rc=0
while read -r agent; do
  [ -z "$agent" ] && continue
  ./eval/run-functional.sh "$agent" || overall_rc=1
done <<< "$SELECTED_AGENTS"
exit "$overall_rc"

(.skills[]?),
(.plugins[]?),
.forge.github.pre_script, .forge.github.post_script
] | .[] | select(. != null)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] premature-decision: hardcoded field list in extract_refs unvalidated against harness schema drift

This enumerated field list (.agent, .doc, .policy, etc.) is stated as exhaustive in the script's header comment but isn't validated against the actual harness schema, which already shows drift across agents (e.g. env.runner/runner_env-style path fields used elsewhere). Nothing enforces that a newly-added path-bearing field gets added to this list — the failure mode is silent under-selection that stays green in CI.

Suggestion: either walk all string leaf values generically (filtering to path-looking strings) instead of an explicit field allowlist, or add a lint/test that fails when a harness file contains an unrecognized *_script/path-shaped key not covered here.

agent="$(basename "$harness_file" .yaml)"

# Only consider agents that have eval configs
[[ -f "$REPO_ROOT/eval/$agent/eval.yaml" ]] || continue

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] premature-decision: harness/<agent>.yamleval/<agent>/ 1:1 naming convention assumed, never enforced

agent="$(basename "$harness_file" .yaml)" then checks eval/$agent/eval.yaml — this hardcodes an exact-name match convention with no schema/lint enforcement. A future rename of one side without the other would silently disable functional-test selection for that agent with no error surfaced anywhere in CI.

Suggestion: add a lint check (or a documentation note) asserting this naming convention is load-bearing for CI coverage, and add a test case that a harness/eval name mismatch produces an explicit warning rather than silent exclusion.

EVALS_HOST_CREDENTIALS: ${{ env.HOST_GOOGLE_APPLICATION_CREDENTIALS }}
FULLSEND_DIR: ${{ github.workspace }}
run: ./eval/run-functional.sh triage
SELECTED_AGENTS: ${{ steps.agents.outputs.agents }}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] premature-decision: adding a new eval config now grants code execution with cloud secrets, with no workflow-file diff for reviewers to notice

This is explicitly the PR's stated goal (avoid modifying workflow YAML to add agents), but it also means a PR adding harness/evil.yaml + eval/evil/eval.yaml gets its runner auto-executed here with GCP WIF credentials and EVAL_GH_TOKEN, with zero diff to this workflow file to flag the trust-model change during ok-to-test triage. Not a bug, but an unstated tradeoff worth calling out for maintainers doing PR authorization.

Suggestion: document this explicitly in the PR description and/or as a comment near the gate job so maintainers labeling external PRs ok-to-test understand the new blast radius of adding a harness+eval pair.

@ralphbean

Copy link
Copy Markdown
Member Author

Superseded by #148.

@ralphbean ralphbean closed this Jul 13, 2026
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jul 13, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 4:56 PM UTC · Completed 5:07 PM UTC
Commit: 7b39f3f · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #145 — ci: dynamically select eval agents from changed files

PR #145 was a human-authored PR by @ralphbean that replaced hardcoded functional test agent names with dynamic selection based on changed files and harness config references. It was closed without merge after review feedback, superseded by PR #148 which restructures the approach into a parallel matrix strategy.

Timeline

  1. Jul 10 — Two preparatory commits: review agent eval case + hardcoded review eval in workflow
  2. Jul 13 10:46 UTC — PR opened with dynamic selection mechanism (select-eval-agents.sh)
  3. Jul 13 10:59 UTC — Fullsend review agent posts comment verdict with 3 medium + 1 low findings
  4. Jul 13 10:53 UTC — Qodo posts 5 bug findings + 2 skill insights
  5. Jul 13 13:42 UTC — waynesun09 review squad posts 2 HIGH + 3 MEDIUM findings
  6. Jul 13 16:54 UTC — PR closed, superseded by ci: parallel functional tests with dynamic matrix strategy #148

Review quality assessment

Overlap was good. The fullsend review agent independently identified 3 of the same core issues found by qodo and the human squad: (1) pipe subshell loop aborting on first failure, (2) GHEOF heredoc delimiter collision risk, (3) shared eval infrastructure changes no longer triggering tests. The remediations included ready-to-use code examples.

Severity underrating recurred. The review agent rated the shared infrastructure coverage regression as medium. The human squad rated it HIGH — correctly, since it removes merge-gate signal for a class of changes that the old behavior tested. This severity gap flipped the verdict from request-changes to comment. This is the same pattern documented in issue #45, providing additional evidence that the verdict/severity calibration issue persists.

Security gap. The human squad identified that the dynamic agent selection pattern allows new harness+eval config pairs to inherit GCP WIF credentials and EVAL_GH_TOKEN without any workflow file modification — removing a review safeguard. The fullsend security sub-agent did not flag this trust model expansion.

Existing issues with new evidence

Proposals filed

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

Labels

fullsend-fix requires-manual-review Review requires human judgment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants