Skip to content

feat: add generic refine agent - #86

Closed
ascerra wants to merge 16 commits into
mainfrom
feat/add-refine-agent
Closed

feat: add generic refine agent#86
ascerra wants to merge 16 commits into
mainfrom
feat/add-refine-agent

Conversation

@ascerra

@ascerra ascerra commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a platform-agnostic refinement agent that decomposes work items into implementable children with acceptance criteria
  • Includes harness config, sandbox policy (read-only GitHub API), pre/post scripts, result schema, platform context docs (Jira/GitHub/GitLab), and test suite (29 tests passing)
  • Depends on shared scripts from feat: add generic explore agent #11 (explore agent) — comment-helpers.sh, pre-explore.sh, and markdown-to-adf.py

Related Issue

Continuation of agent migration from konflux-ci/refinement to generic agents repo.

Changes

File Description
agents/refine.md Generic refine agent prompt (no Konflux-specific references)
harness/refine.yaml Harness config with env.runner/env.sandbox format, human-directive mount
policies/refine.yaml Sandbox policy with read-only GitHub API access
schemas/refine-result.schema.json Output validation schema
scripts/pre-refine.sh Context preparation (issue, exploration, platform, routing)
scripts/post-refine.sh Result processing, comment posting, label management
scripts/post-refine-test.sh 29-test suite covering reply targeting, plan summary, labels, JSON extraction
scripts/platform-{jira,github,gitlab}.md Platform-specific hierarchy and format context
env/refine.env Sandbox environment variables
docs/refine.md User-facing documentation
config.yaml Registers harness/refine.yaml
README.md Lists refine agent in agent table

Testing

  • bash scripts/post-refine-test.sh — 29/29 tests passing
  • Integration test with live issue (post-merge)

Checklist

  • No Konflux-specific references in agent code
  • Sandbox policy enforces read-only GitHub API access
  • PUT verb blocked in disallowedTools
  • Human directive file mounted into sandbox
  • Forge block uses env.runner/env.sandbox format
  • Pipeline labels parameterized via environment variables

Made with Cursor

@ascerra
ascerra requested a review from a team as a code owner July 9, 2026 17:45
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 9, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 5:46 PM UTC · Completed 5:57 PM UTC
Commit: 8e5887d · View workflow run →

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add platform-agnostic refine agent with harness, policy, schema, and scripts

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

Grey Divider

AI Description

• Add a generic refine agent that always decomposes work into implementable child items.
• Wire a full refine harness (pre/post scripts, schema validation loop) with read-only sandbox
 policy.
• Document platform-specific hierarchy/format rules and add a shell test suite for post-processing.
Diagram

graph TD
  A(("Trigger /fs-refine")) --> B["harness/refine.yaml"] --> C["scripts/pre-refine.sh"] --> D["agents/refine.md"] --> E["schemas/refine-result.schema.json"] --> F["scripts/post-refine.sh"] --> G{{"Issue platform\n(GitHub/Jira)"}}
  F --> H[("Run artifact\nrefine-result.json")]

  subgraph Legend
    direction LR
    _start(("Trigger")) ~~~ _cfg["Config/Harness"] ~~~ _dec{{"Decision/Target"}} ~~~ _art[("Artifact")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Adopt a shared cross-agent result schema
  • ➕ Reduces schema proliferation and makes downstream tooling consistent across explore/refine/critique
  • ➕ Enables reusable validation/post-processing utilities
  • ➖ Requires broader refactor and coordination across other agent PRs
  • ➖ May slow delivery of the refine agent rollout
2. Do not auto-update issue descriptions; comment-only output
  • ➕ Avoids additional write paths/permissions and reduces risk of accidental overwrites
  • ➕ Keeps refine as a purely additive workflow step
  • ➖ Lowers usability (refined description is harder to find/consume)
  • ➖ May create noisy, fragmented specs across many comments
3. Move post-processing logic into a small typed tool (Python)
  • ➕ More maintainable parsing/templating than large bash + jq pipelines
  • ➕ Easier unit testing and future extensions (multi-platform handling)
  • ➖ Adds runtime dependency/packaging decisions
  • ➖ Higher initial implementation cost than shell scripts

Recommendation: The PR’s approach (separate refine harness with read-only sandbox + runner-side post-script) is appropriate for least-privilege and keeps the agent prompt platform-agnostic via injected platform context. Consider converging on a shared result schema across agents later, but it’s reasonable to ship refine with its own schema now. If write-risk becomes a concern, the first simplification would be making proposed_description comment-only rather than patching the issue body/description.

Files changed (14) +1925 / -0

Enhancement (1) +576 / -0
refine.mdIntroduce generic refine agent prompt and output contract +576/-0

Introduce generic refine agent prompt and output contract

• Adds a platform-agnostic refinement agent prompt that always decomposes a work item into implementable children with acceptance criteria, dependencies, confidence scoring, open questions, and a proposed description. Enforces read-only behavior via disallowed tool patterns and mandates JSON-only output.

agents/refine.md

Tests (1) +286 / -0
post-refine-test.shAdd unit-style shell tests for post-refine summary/label logic +286/-0

Add unit-style shell tests for post-refine summary/label logic

• Adds a 29-test bash suite that verifies reply-target selection, plan summary formatting, revision detection, label payload generation, iteration output discovery, and jq extraction behavior. Enables validating core post-refine logic without live APIs.

scripts/post-refine-test.sh

Documentation (5) +226 / -0
README.mdAdd Refine agent to the agent catalog table +1/-0

Add Refine agent to the agent catalog table

• Documents the new Refine agent entry, including trigger label and command. Helps users discover the new pipeline stage.

README.md

refine.mdAdd user-facing Refine agent documentation +79/-0

Add user-facing Refine agent documentation

• Documents refine behavior, pipeline position (Explore → Refine → Critique), revision rounds, control labels, and platform support. Includes guidance for human directives, routing skills, and platform context injection.

docs/refine.md

platform-github.mdAdd GitHub platform context for hierarchy and description rules +47/-0

Add GitHub platform context for hierarchy and description rules

• Documents how refine should model hierarchy on GitHub (labels + sub-issues) and how to format descriptions in markdown. Captures constraints and fallback behavior assumptions for child linking.

scripts/platform-github.md

platform-gitlab.mdAdd GitLab platform context template (planned support) +47/-0

Add GitLab platform context template (planned support)

• Provides a GitLab hierarchy/format guidance template for the agent, noting creation is not yet fully wired. Establishes expected epic/issue/task mapping and fallback strategies by tier.

scripts/platform-gitlab.md

platform-jira.mdAdd Jira platform context for typed hierarchy and ADF conversion +52/-0

Add Jira platform context for typed hierarchy and ADF conversion

• Defines Jira hierarchy levels and parent-child constraints, plus guidance on respecting available issue types and routing limitations across projects. Documents markdown-to-ADF conversion expectations and spike/doc task conventions.

scripts/platform-jira.md

Other (7) +837 / -0
config.yamlRegister refine harness in global agent configuration +1/-0

Register refine harness in global agent configuration

• Adds harness/refine.yaml to the configured agent sources so the new refine agent is discoverable/runnable.

config.yaml

refine.envAdd refine sandbox environment variable defaults +6/-0

Add refine sandbox environment variable defaults

• Defines default sandbox paths for issue context, exploration context, critique feedback, routing skill, and platform context used by the agent prompt/scripts.

env/refine.env

refine.yamlAdd refine harness wiring (env, mounts, schema validation loop) +78/-0

Add refine harness wiring (env, mounts, schema validation loop)

• Creates the refine harness config including host file mounts (contexts + human directive), pre/post scripts, schema validation loop, and split runner vs sandbox env configuration. Uses the standard sandbox image and attaches the refine policy.

harness/refine.yaml

refine.yamlAdd read-only sandbox policy for refine agent +71/-0

Add read-only sandbox policy for refine agent

• Defines filesystem and network restrictions for the refine sandbox, allowing read-only access to GitHub and Jira endpoints while permitting model provider access. Reinforces the model where mutations happen on the runner via post-script.

policies/refine.yaml

refine-result.schema.jsonDefine JSON schema for refine agent output +95/-0

Define JSON schema for refine agent output

• Introduces a JSON Schema requiring input metadata, complete status, confidence, target level, children array, and human-readable comment/summary. Validates optional fields like dependencies, assumptions, and proposed_description size limits.

schemas/refine-result.schema.json

post-refine.shImplement refine post-processing: publish plan, update description, label for critique +301/-0

Implement refine post-processing: publish plan, update description, label for critique

• Processes refine agent output by locating the latest iteration result, building a sticky summary comment (including open questions and assumptions), and linking to the full artifact. Optionally updates Jira/GitHub descriptions, attaches refine-result.json to Jira, and adds ready-to-critique (+ revision round) labels.

scripts/post-refine.sh

pre-refine.shImplement refine pre-processing: gather issue/explore/critique context and routing +285/-0

Implement refine pre-processing: gather issue/explore/critique context and routing

• Ensures issue-context.json exists (delegating to pre-explore.sh), locates exploration context via workspace, user ref, Jira attachment, or GHA artifact fallback, and optionally loads critique feedback for revision rounds. Injects routing skill and platform context into the workspace and exports env vars for the harness/agent.

scripts/pre-refine.sh

@qodo-code-review

qodo-code-review Bot commented Jul 9, 2026

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. Output filename mismatch ✓ Resolved 🐞 Bug ≡ Correctness
Description
Schema validation and post-processing are misconfigured: harness/refine.yaml sets
FULLSEND_OUTPUT_FILE=refine-result.json (so validation expects output/refine-result.json), but
agents/refine.md and scripts/post-refine.sh are hardcoded to write/read agent-result.json, which can
cause validation failure and post-refine to not find the result file.
Code

harness/refine.yaml[R52-66]

+env:
+  runner:
+    ISSUE_KEY: "${ISSUE_KEY}"
+    ISSUE_SOURCE: "${ISSUE_SOURCE}"
+    REPO_FULL_NAME: "${REPO_FULL_NAME}"
+    EXPLORE_RUN_ID: "${EXPLORE_RUN_ID}"
+    EXPLORE_CONTEXT_REF: "${EXPLORE_CONTEXT_REF}"
+    CRITIQUE_RUN_ID: "${CRITIQUE_RUN_ID}"
+    REVIEW_ROUND: "${REVIEW_ROUND}"
+    MAX_REVIEW_ROUNDS: "${MAX_REVIEW_ROUNDS}"
+    AUTO_CREATE: "${AUTO_CREATE}"
+    GITHUB_ISSUE_NUMBER: "${GITHUB_ISSUE_NUMBER}"
+    HUMAN_DIRECTIVE: "${HUMAN_DIRECTIVE}"
+    FULLSEND_OUTPUT_FILE: refine-result.json
+  sandbox:
Relevance

●●● Strong

Team has merged output/validation contract fixes; filename mismatch likely treated as breaking
validation loop.

PR-#24
PR-#9

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The validator derives the expected output path from FULLSEND_OUTPUT_FILE; refine harness sets it to
refine-result.json, while both the agent instructions and post-script use agent-result.json,
creating an internally inconsistent contract.

harness/refine.yaml[52-66]
scripts/validate-output-schema.sh[20-40]
agents/refine.md[455-463]
scripts/post-refine.sh[41-50]

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 refine harness config expects `refine-result.json`, but the agent prompt and post-script are keyed to `agent-result.json`, and the schema validator uses `FULLSEND_OUTPUT_FILE` to select the expected output file. This inconsistency can break the validation loop and/or cause `post-refine.sh` to fail finding the result.

### Issue Context
- Validator expects `output/${FULLSEND_OUTPUT_FILE}` when set.
- Refine harness sets `FULLSEND_OUTPUT_FILE: refine-result.json`.
- Refine agent instructions and post-script both reference `agent-result.json`.

### Fix Focus Areas
- harness/refine.yaml[52-66]
- scripts/validate-output-schema.sh[20-40]
- agents/refine.md[455-463]
- scripts/post-refine.sh[41-50]
- scripts/post-refine-test.sh[168-201]

### Suggested fix (pick one consistent approach)
**Option A (match most agents):**
- Remove `FULLSEND_OUTPUT_FILE` from `harness/refine.yaml` (or set it to `agent-result.json`).
- Keep `agents/refine.md` and `post-refine.sh` using `agent-result.json`.

**Option B (custom filename like code/fix agents):**
- Update `agents/refine.md` to instruct writing `$FULLSEND_OUTPUT_DIR/refine-result.json`.
- Update `scripts/post-refine.sh` (and `scripts/post-refine-test.sh`) to search for `refine-result.json` instead of `agent-result.json`.

Either way: ensure validator, agent instruction, and post-script all agree on the same filename.

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


2. Missing shared scripts ✓ Resolved 🐞 Bug ☼ Reliability
Description
The refine pipeline will fail at runtime because post-refine.sh sources comment-helpers.sh and calls
markdown-to-adf.py, and pre-refine.sh exits if pre-explore.sh is missing; none of these files are
present in the repository snapshot, so context prep and/or post-processing will abort.
Code

scripts/post-refine.sh[R33-40]

+# NOTE: This script uses comment-helpers.sh and markdown-to-adf.py from
+# the explore agent. These must be present in the scripts/ directory.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "${SCRIPT_DIR}/comment-helpers.sh"
+
Relevance

●●● Strong

Missing companion scripts have caused merged fixes (fallbacks/inlining) before; runtime aborts are
addressed.

PR-#41
PR-#35

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
post-refine.sh directly sources a non-existent helper script and invokes a non-existent converter
script; pre-refine.sh explicitly exits when pre-explore.sh is not found. In the current repository
snapshot, there are no matching files for these referenced paths, so the refine run will abort.

scripts/post-refine.sh[33-40]
scripts/post-refine.sh[203-214]
scripts/pre-refine.sh[37-45]

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

### Issue description
Refine’s pre/post scripts depend on `scripts/comment-helpers.sh`, `scripts/pre-explore.sh`, and `scripts/markdown-to-adf.py`, but those files are not present in this repo snapshot, causing `source`/execution failures.

### Issue Context
- `post-refine.sh` uses `source "${SCRIPT_DIR}/comment-helpers.sh"` and later runs `python3 "${SCRIPT_DIR}/markdown-to-adf.py"`.
- `pre-refine.sh` hard-fails if `pre-explore.sh` is not found when issue context is missing.

### Fix Focus Areas
- scripts/post-refine.sh[33-40]
- scripts/post-refine.sh[203-214]
- scripts/pre-refine.sh[37-45]

### Suggested fix
1. Add/commit the required shared scripts into `scripts/` (or adjust paths to where they actually live in this repo).
2. If you intentionally want a soft dependency (because another PR introduces them), then:
  - Guard `source` with an existence check and fail with a clear error that references the required PR/commit, or
  - Vendor minimal required functions directly in `post-refine.sh` / `pre-refine.sh`.
3. Ensure the harness image contains any runtime deps those scripts require.

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


3. ISSUE_KEY unsanitized in notice ✓ Resolved 📜 Skill insight ⛨ Security
Description
GitHub Actions workflow commands (::notice::, ::error::, ::warning::) are emitted with
interpolated variables that are not individually sanitized, enabling workflow-command injection via
::, encoded newlines, or control characters. This can corrupt logs and potentially alter workflow
behavior when attacker-controlled values reach these variables.
Code

scripts/pre-refine.sh[35]

+echo "::notice::Pre-refine: preparing context (source=${ISSUE_SOURCE}, key=${ISSUE_KEY})"
Relevance

●● Moderate

No historical evidence of enforcing workflow-command injection sanitization for ::notice:: variable
interpolation.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The checklist requires sanitizing every variable interpolated into GitHub Actions workflow commands.
The added scripts emit ::notice::/::error::/::warning:: lines that interpolate variables
(e.g., ISSUE_SOURCE, ISSUE_KEY, CONTEXT_REPO, CONTEXT_PATH) with no sanitization before
printing.

scripts/pre-refine.sh[35-35]
scripts/pre-refine.sh[62-62]
Skill: pr-review
Skill: code-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
GitHub Actions workflow commands are emitted with unsanitized interpolated variables (e.g., `ISSUE_SOURCE`, `ISSUE_KEY`, `CONTEXT_REPO`, `CONTEXT_PATH`). Per compliance, every interpolated value in a workflow command must be individually sanitized (including `::`, `%`, newlines, and control chars).

## Issue Context
The scripts log using `echo "::notice::..."` / `echo "::error::..."` / `echo "::warning::..."`. These are parsed by GitHub Actions as workflow commands.

## Fix Focus Areas
- scripts/pre-refine.sh[35-35]
- scripts/pre-refine.sh[62-62]
- scripts/post-refine.sh[99-99]
- scripts/post-refine.sh[270-273]
- scripts/post-refine.sh[284-285]
- scripts/post-refine.sh[298-299]

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


View more (3)
4. Protected paths modified in PR ✗ Dismissed 📜 Skill insight § Compliance
Description
This PR modifies protected governance/infrastructure paths (agents/, harness/, policies/,
scripts/), so it must not be auto-approved and requires explicit human review. Without enforcing
this, high-impact pipeline/sandbox behavior could be changed without governance oversight.
Code

harness/refine.yaml[R1-7]

+---
+agent: agents/refine.md
+doc: docs/refine.md
+model: opus
+image: ghcr.io/fullsend-ai/fullsend-sandbox:latest
+policy: policies/refine.yaml
+
Relevance

●● Moderate

Protected-path human-review concern previously raised but left undetermined; no clear accept/reject
evidence.

PR-#59
PR-#27

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The diff adds/changes files under protected directories (agent prompt, harness config, sandbox
policy, and runner scripts). The rule requires raising a protected-path finding to ensure these
changes receive human governance review.

harness/refine.yaml[1-7]
policies/refine.yaml[1-13]
scripts/pre-refine.sh[1-36]
scripts/post-refine.sh[1-40]
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 were modified; this PR must be gated for human review and cannot be auto-approved.

## Issue Context
The compliance rule requires a finding whenever protected paths change.

## Fix Focus Areas
- harness/refine.yaml[1-78]
- policies/refine.yaml[1-71]
- scripts/pre-refine.sh[1-285]
- scripts/post-refine.sh[1-301]
- agents/refine.md[1-576]

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


5. No linked authorizing issue ✗ Dismissed 📜 Skill insight § Compliance
Description
This is a non-trivial feature addition but the PR does not include an explicit linked issue
authorizing the work. Lack of authorization linkage increases governance and audit risk for
substantial changes.
Code

agents/refine.md[R1-16]

+---
+name: refine
+description: >-
+  Best-effort feature refinement agent. Reads a work item and exploration
+  context, assesses confidence, and ALWAYS decomposes into implementable
+  child work items. Flags uncertainties honestly but never halts — the
+  critique agent downstream decides if human input is needed.
+tools: Bash(gh,jq,python3,find,ls,cat,head,grep,wc,tree)
+model: opus
+disallowedTools: >-
+  Bash(git push *), Bash(git push),
+  Bash(gh issue create *), Bash(gh issue edit *), Bash(gh issue comment *),
+  Bash(gh pr create *), Bash(gh pr edit *), Bash(gh pr merge *),
+  Bash(gh api *POST*), Bash(gh api *DELETE*), Bash(gh api *PATCH*), Bash(gh api *PUT*)
+---
+
Relevance

●● Moderate

Only prior “link authorizing issue/justification” suggestions were undetermined; no clear
enforcement precedent.

PR-#29
PR-#25

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The checklist requires non-trivial PRs to link to an authorizing issue. This PR introduces a new
agent (new harness/policy/scripts/schema/docs), which is substantial work, but no explicit
authorizing issue link is provided in the PR metadata.

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
Non-trivial changes must be explicitly authorized via a linked issue.

## Issue Context
Add a concrete issue link (e.g., `Fixes #123` or a full URL) in the PR description so reviewers/auditors can trace authorization.

## Fix Focus Areas
- agents/refine.md[1-16]

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


6. Label update failures ignored ✓ Resolved 📜 Skill insight ☼ Reliability
Description
The script suppresses failures when adding critique-signaling labels (e.g.,
ready-to-critique/refine-revision-round-N) to GitHub and Jira, then logs success
unconditionally. This can silently break the refine→critique handoff and leave issues unlabeled or
in the wrong state while the logs claim labels were added.
Code

scripts/post-refine.sh[R276-285]

+# --- Add label to signal critique stage ---
+if [[ -n "${GITHUB_ISSUE_NUMBER:-}" && "${GITHUB_ISSUE_NUMBER}" != "N/A" ]]; then
+  LABEL_PAYLOAD='["ready-to-critique"]'
+  if [[ "$REVIEW_ROUND" -gt 1 ]]; then
+    LABEL_PAYLOAD="[\"ready-to-critique\",\"refine-revision-round-${REVIEW_ROUND}\"]"
+  fi
+  gh api "repos/${REPO_FULL_NAME}/issues/${GITHUB_ISSUE_NUMBER}/labels" \
+    --input - <<< "{\"labels\":${LABEL_PAYLOAD}}" --silent 2>/dev/null || true
+  echo "::notice::Added label 'ready-to-critique' to GitHub issue #${GITHUB_ISSUE_NUMBER}"
+fi
Relevance

●● Moderate

Reliability fixes common, but no direct precedent on masking label-add failures with “|| true” then
success notice.

PR-#41
PR-#10

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance requires explicit handling of guard/contract failure paths, and here the label-add
operation is the mechanism that signals critique readiness. In scripts/post-refine.sh, the GitHub
(gh api ... || true) and Jira (curl ... || true) label update commands are explicitly made
non-fatal via || true, but are immediately followed by unconditional success notices (e.g.,
::notice::Added label ...), which hides failures and makes the pipeline appear healthy even when
the labels were not applied.

scripts/post-refine.sh[276-285]
scripts/post-refine.sh[287-299]
scripts/post-refine.sh[276-299]
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
The critique-signaling label update is a guard/contract mechanism; failures must not be silently ignored, and success notices should only be printed when the label mutation actually succeeds.

## Issue Context
`scripts/post-refine.sh` applies labels that drive the refine→critique handoff (e.g., `ready-to-critique`/`refine-revision-round-N`) to both GitHub and Jira. Those label mutation commands are currently written as non-fatal (`gh api ... || true` and `curl ... || true`), yet the script still prints success notices unconditionally, which can leave issues unlabeled while logs claim labels were added and downstream stages may never trigger.

## Fix Focus Areas
- scripts/post-refine.sh[276-285]
- scripts/post-refine.sh[287-299]

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



Remediation recommended

7. Undocumented issue body edits ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
docs/refine.md describes the post-script as posting a summary comment, attaching the plan, and
adding a ready-to-critique label, but post-refine.sh also overwrites the Jira description / GitHub
issue body when proposed_description is present, which is a user-visible behavior not reflected in
the docs.
Code

scripts/post-refine.sh[R203-235]

+# Update issue description if proposed_description is present
+PROPOSED_DESC=$(jq -r '.proposed_description // ""' "${RESULT_FILE}")
+if [[ -n "$PROPOSED_DESC" && "$PROPOSED_DESC" != "null" ]]; then
+  if [[ "${ISSUE_SOURCE:-}" == "jira" && -n "${JIRA_HOST:-}" && -n "${JIRA_EMAIL:-}" && -n "${JIRA_API_TOKEN:-}" ]]; then
+    AUTH_DESC=$(printf '%s:%s' "$JIRA_EMAIL" "$JIRA_API_TOKEN" | base64 -w0)
+    ADF_FLAGS=""
+    if [[ "$JIRA_HOST" != *"atlassian.net"* ]]; then
+      ADF_FLAGS="--no-expand"
+    fi
+    DESC_ADF=$(printf '%s' "$PROPOSED_DESC" | python3 "${SCRIPT_DIR}/markdown-to-adf.py" $ADF_FLAGS | jq '.body')
+
+    DESC_HTTP=$(curl -sS -o /dev/null -w "%{http_code}" \
+      -X PUT \
+      -H "Authorization: Basic $AUTH_DESC" \
+      -H "Content-Type: application/json" \
+      -d "$(jq -nc --argjson desc "$DESC_ADF" '{fields: {description: $desc}}')" \
+      "https://${JIRA_HOST}/rest/api/3/issue/${ISSUE_KEY}")
+
+    if [[ "$DESC_HTTP" =~ ^2 ]]; then
+      echo "::notice::Updated ${ISSUE_KEY} description (previous version in History tab)"
+    else
+      echo "::warning::Failed to update ${ISSUE_KEY} description (HTTP ${DESC_HTTP}) — falling back to comment"
+      new_comment "## Proposed Feature Description
+
+${PROPOSED_DESC}"
+    fi
+
+  elif $USE_GITHUB; then
+    gh api "repos/${REPO_FULL_NAME}/issues/${GITHUB_ISSUE_NUMBER}" \
+      -X PATCH --field "body=${PROPOSED_DESC}" --silent 2>/dev/null \
+      && echo "::notice::Updated GitHub issue #${GITHUB_ISSUE_NUMBER} body" \
+      || echo "::warning::Failed to update GitHub issue body"
+  fi
Relevance

●●● Strong

Doc/script behavior alignment changes have been accepted previously; docs accuracy is enforced.

PR-#15

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The documentation states only comment/attachment/label behavior, while the post-script contains
explicit Jira/GitHub API calls to update the description/body when proposed_description is present.

docs/refine.md[9-12]
scripts/post-refine.sh[203-235]

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 refine pipeline mutates the issue description/body when `proposed_description` is present, but user-facing docs currently state the post-script only comments, attaches the plan, and labels. This mismatch can surprise users and complicates operational expectations.

### Issue Context
- Jira: `PUT /rest/api/3/issue/${ISSUE_KEY}` updates description.
- GitHub: `PATCH repos/.../issues/...` updates issue body.

### Fix Focus Areas
- scripts/post-refine.sh[203-235]
- docs/refine.md[9-12]

### Suggested fix
Choose one:
1. **Document it clearly** in `docs/refine.md` (and any other user docs) as an explicit behavior and describe when it happens.
2. **Gate it behind an env flag** (e.g., `REFINE_UPDATE_DESCRIPTION=true`) defaulting to false, to avoid unexpected overwrites.
3. **Change behavior** to post the proposed description as a comment/attachment instead of overwriting the source-of-truth description.

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


Grey Divider

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

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread scripts/pre-refine.sh Outdated
Comment thread scripts/post-refine.sh
Comment thread harness/refine.yaml
Comment thread agents/refine.md
Comment thread scripts/post-refine.sh
Comment thread harness/refine.yaml
Comment thread scripts/post-refine.sh Outdated
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review

Changes since prior review

The 2 commits since 84b2b45 modified 2 files (agents/refine.md, scripts/pre-explore.sh). No prior findings were resolved.

Key changes:

  • agents/refine.md: Added "File/repo anchors on leaf Stories and Tasks" section to agent prompt
  • scripts/pre-explore.sh: Renamed JSON field keyissue_id (aligning with schemas), added host-prefetched clone preservation, updated validate_repo() and clone logic to use authenticated GH_TOKEN access
Prior finding Status
Double-linkify-corruption in linkify Persists
Schema custom_fields prompt-mismatch Persists
Missing FULLSEND_VALIDATED_ITERATION_DIR Persists
Image not pinned by digest Persists
Missing doc reference in docs/README.md Persists
Path-mismatch in duplicate-gate.json Persists (low)
Schema consistency (explore vs refine) Persists
Missing conditional required fields Persists
ORG_KNOWLEDGE not mounted into sandbox Persists
TARGET_REPO_DIR not wired Persists
GHA command injection (multiple scripts) Persists
Inconsistent GitHub detection Persists
Error messages to stdout Persists
Hardcoded project keys Persists
Excessive permission (PUSH_TOKEN) Persists
Forward dependency (docs) Persists

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, and 12 files under scripts/ — 15 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [double-linkify-corruption] scripts/comment-helpers.sh:324 — In the linkify function's generic fallback path, repl_url runs on the output of repl_jira. When repl_jira wraps a bare Jira key as [KEY-123](https://host/browse/KEY-123), the subsequent repl_url matches the URL inside the markdown link and wraps it again, producing corrupted markdown (persists).
    Remediation: Run repl_url before repl_jira, or make repl_url skip URLs already inside markdown link syntax.

  • [schema-prompt-mismatch] schemas/refine-result.schema.json — The agent prompt instructs including a custom_fields map on children when allowed_custom_fields are present. The schema has additionalProperties: false without a custom_fields property — output will fail validation (persists).
    Remediation: Add custom_fields to the children items properties, or remove the custom_fields instructions from the prompt.

  • [result-file-discovery-pattern] scripts/post-refine.sh:127 — Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR as a trust boundary (persists).
    Remediation: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback.

  • [image-not-pinned] harness/refine.yaml:5 — All existing harness definitions pin the sandbox image by digest (@sha256:...). The refine harness uses :latest, which is non-reproducible and breaks the codebase convention for deterministic builds (persists).
    Remediation: Pin the image to a specific sha256 digest.

  • [missing-doc-reference] docs/README.md — The docs index lists all shipped agents but does not include the new Refine agent. The PR adds docs/refine.md and updates the top-level README.md but omits the corresponding row in docs/README.md (persists).
    Remediation: Add a row to the agents table in docs/README.md.

Low

  • [gha-command-injection] scripts/pre-explore.sh:487 — The ::notice:: command interpolates ${CLONED[*]} without sanitization. Although GitHub org/repo naming rules make injection impractical, the codebase convention is to sanitize all values interpolated into GHA workflow commands (new).

  • [gha-command-injection] scripts/pre-explore.sh:498 — The ::warning:: in validate_repo interpolates ${ref} without sanitization (new).

  • [gha-command-injection] scripts/post-refine.sh, scripts/post-explore.sh, scripts/pre-refine.sh — Inconsistent sanitize_gha application: success paths use sanitized variants but error/warning paths interpolate raw values into GHA workflow commands (persists).

  • [token-exposure] scripts/pre-explore.shGH_TOKEN used in validate_repo and clone operations but never registered with ::add-mask::. Codebase pattern is to mask tokens early. git -c http.extraHeader passes the token in the command line, visible in /proc/*/cmdline (new).

  • [excessive-permission] harness/refine.yamlPUSH_TOKEN injected into runner environment but never referenced in post-refine.sh script body. Violates least-privilege (persists).

  • [platform-coupling] scripts/pre-explore.sh — GitHub-specific authentication added to validate_repo and clone logic. The script was already GitHub-focused, so this is a pragmatic improvement rather than architectural drift, but worth noting for future platform abstraction (new).

  • [hardcoded-project-keys] scripts/pre-explore.sh:390 — Jira API hints block probes three hardcoded project keys specific to a single Jira instance (persists).

  • [path-mismatch] agents/refine.md — Prior medium finding partially addressed: the agent prompt now searches both /tmp/workspace/ and /sandbox/workspace/ for duplicate-gate.json (persists).

  • [schema-consistency] schemas/explore-result.schema.json — Missing additionalProperties: false at root and nested objects. Uses disposition instead of status for the blocked_duplicate field (persists).

  • [missing-conditional-required] schemas/refine-result.schema.jsonspike_title optional but semantically required when resolution is research_spike; assumption_used optional but semantically required when resolution is assumed_default (persists).

  • [missing-host-file] harness/refine.yamlORG_KNOWLEDGE env var points to /sandbox/workspace/org-knowledge.md but no host_files entry mounts it. Degrades gracefully (persists).

  • [logic-inconsistency] scripts/post-refine.sh — Three different GitHub detection patterns (persists).

  • [dead-env-var] agents/refine.mdTARGET_REPO_DIR documented as input but never wired (persists).

  • [error-handling-idiom] scripts/post-refine.sh, scripts/post-explore.sh, scripts/comment-helpers.sh — Error messages print to stdout instead of stderr (persists).

  • [forward-dependency] docs/refine.md — Documentation references explore and critique agents that don't exist in the repository (persists).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run

Review

Changes since prior review

The commit since bee87be modified 8 files (agents/refine.md, schemas/explore-result.schema.json, schemas/refine-result.schema.json, scripts/comment-helpers.sh, scripts/post-refine-test.sh, scripts/post-refine.sh, scripts/pre-explore.sh, scripts/pre-refine.sh). No prior findings were resolved.

Prior finding Status
Path-mismatch in duplicate-gate.json Persists (low — partially addressed in prior commit)
Double-linkify-corruption in linkify Persists
Schema custom_fields prompt-mismatch Persists
Missing FULLSEND_VALIDATED_ITERATION_DIR Persists (also in post-explore.sh)
Schema consistency (explore vs refine) Persists
Missing conditional required fields Persists
ORG_KNOWLEDGE not mounted into sandbox Persists
TARGET_REPO_DIR not wired Persists
GHA command injection (multiple scripts) Persists
Inconsistent GitHub detection Persists
Error messages to stdout Persists
Hardcoded project keys Persists

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, and 12 files under scripts/ — 15 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [double-linkify-corruption] scripts/comment-helpers.sh:324 — In the linkify function's generic fallback path, repl_url runs on the output of repl_jira. When repl_jira wraps a bare Jira key as [KEY-123](https://host/browse/KEY-123), the subsequent repl_url matches the URL inside the markdown link and wraps it again, producing corrupted markdown (persists).
    Remediation: Run repl_url before repl_jira, or make repl_url skip URLs already inside markdown link syntax.

  • [schema-prompt-mismatch] schemas/refine-result.schema.json:110 — The agent prompt instructs including a custom_fields map on children when allowed_custom_fields are present. The schema has additionalProperties: false without a custom_fields property — output will fail validation (persists).
    Remediation: Add custom_fields to the children items properties, or remove the custom_fields instructions from the prompt.

  • [result-file-discovery-pattern] scripts/post-refine.sh:127, scripts/post-explore.sh — Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR as a trust boundary (persists).
    Remediation: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback in both scripts.

  • [image-not-pinned] harness/refine.yaml:5 — All existing harness definitions pin the sandbox image by digest (@sha256:...). The refine harness uses :latest, which is non-reproducible and breaks the codebase convention for deterministic builds.
    Remediation: Pin the image to a specific sha256 digest.

  • [missing-doc-reference] docs/README.md — The docs index lists all shipped agents but does not include the new Refine agent. The PR adds docs/refine.md and updates the top-level README.md but omits the corresponding row in docs/README.md.
    Remediation: Add a row to the agents table in docs/README.md.

Low

  • [path-mismatch] agents/refine.md:107 — Prior medium finding partially addressed: the agent prompt now searches both /tmp/workspace/ and /sandbox/workspace/ for duplicate-gate.json, and degrades gracefully if neither exists.

  • [schema-consistency] schemas/explore-result.schema.json — Missing additionalProperties: false at root and nested objects, unlike refine-result.schema.json. Also uses disposition instead of status for the blocked_duplicate field (persists).

  • [missing-conditional-required] schemas/refine-result.schema.jsonspike_title optional but semantically required when resolution is research_spike; assumption_used optional but semantically required when resolution is assumed_default (persists).

  • [missing-host-file] harness/refine.yamlORG_KNOWLEDGE env var points to /sandbox/workspace/org-knowledge.md but no host_files entry mounts it into the sandbox. Degrades gracefully (persists).

  • [logic-inconsistency] scripts/post-refine.sh — Three different GitHub detection patterns. Label application and comment posting paths have inconsistent GitHub detection (persists).

  • [dead-env-var] agents/refine.mdTARGET_REPO_DIR documented as input but never wired (persists).

  • [hardcoded-project-keys] scripts/pre-explore.sh:390 — Jira API hints block probes three hardcoded project keys specific to a single Jira instance. Inconsistent with platform-agnostic design (persists).

  • [gha-command-injection] scripts/post-refine.sh, scripts/pre-explore.sh, scripts/post-explore.sh, scripts/pre-refine.sh — Inconsistent sanitize_gha application: success paths use sanitized variants but error/warning paths interpolate raw values into GHA workflow commands. post-explore.sh has no sanitize_gha function at all (persists).

  • [excessive-permission] harness/refine.yamlPUSH_TOKEN injected into runner environment but never referenced in post-refine.sh script body. Violates least-privilege (persists).

  • [error-handling-idiom] scripts/post-refine.sh:134, scripts/post-explore.sh:114, scripts/comment-helpers.sh:37 — Error messages print to stdout instead of stderr, unlike all other post-scripts (persists).

  • [forward-dependency] docs/refine.md — Documentation references explore and critique agents that don't exist in the repository. The docs explicitly acknowledge this (persists).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (2)

Review

Changes since prior review

The commit since 5f73801 modified 2 files (agents/refine.md, scripts/comment-helpers.sh). The agents/refine.md change addresses the prior [path-mismatch] finding by making the agent search both /tmp/workspace/ and /sandbox/workspace/ for duplicate-gate.json.

Prior finding Status
Path-mismatch in duplicate-gate.json Partially addressed (downgraded to low)
Double-linkify-corruption in linkify Persists
Schema custom_fields prompt-mismatch Persists
Missing FULLSEND_VALIDATED_ITERATION_DIR Persists (also in post-explore.sh)
Schema consistency (explore vs refine) Persists
Missing conditional required fields Persists
ORG_KNOWLEDGE not mounted into sandbox Persists
TARGET_REPO_DIR not wired Persists
GHA command injection (multiple scripts) Persists
Inconsistent GitHub detection Persists
Error messages to stdout Persists
Hardcoded project keys Persists

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, and 12 files under scripts/ — 15 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [double-linkify-corruption] scripts/comment-helpers.sh:324 — In the linkify function's generic fallback path, repl_url runs on the output of repl_jira. When repl_jira wraps a bare Jira key as [KEY-123](https://host/browse/KEY-123), the subsequent repl_url matches the URL inside the markdown link and wraps it again, producing corrupted markdown (persists).
    Remediation: Run repl_url before repl_jira, or make repl_url skip URLs already inside markdown link syntax.

  • [schema-prompt-mismatch] schemas/refine-result.schema.json — The agent prompt instructs including a custom_fields map on children when allowed_custom_fields are present. The schema has additionalProperties: false without a custom_fields property — output will fail validation (persists).
    Remediation: Add custom_fields to the children items properties, or remove the custom_fields instructions from the prompt.

  • [result-file-discovery-pattern] scripts/post-refine.sh:127, scripts/post-explore.sh — Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR as a trust boundary (persists).
    Remediation: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback in both scripts.

Low

  • [path-mismatch] agents/refine.md:107 — Prior medium finding partially addressed: the agent prompt now searches both /tmp/workspace/ and /sandbox/workspace/ for duplicate-gate.json, and degrades gracefully if neither exists.

  • [missing-authorization] No linked issue for a 22-file feature addition. The PR body provides provenance ("Continuation of agent migration from konflux-ci/refinement") but non-trivial changes to protected paths require formal authorization via a linked issue.

  • [scope-creep] The PR title "feat: add generic refine agent" understates scope. Beyond the refine agent itself, the PR adds 9 shared utility scripts (comment-helpers.sh, jira-project-schema.sh, markdown-to-adf.py, adf-to-markdown.py, pre-explore.sh, post-explore.sh, platform docs) that serve multiple agents.

  • [schema-consistency] schemas/explore-result.schema.json — Missing additionalProperties: false at root and nested objects, unlike refine-result.schema.json. Also uses disposition instead of status for the blocked_duplicate field (persists).

  • [missing-conditional-required] schemas/refine-result.schema.jsonspike_title optional but semantically required when resolution is research_spike; assumption_used optional but semantically required when resolution is assumed_default (persists).

  • [missing-host-file] harness/refine.yamlORG_KNOWLEDGE env var points to /sandbox/workspace/org-knowledge.md but no host_files entry mounts it into the sandbox. Degrades gracefully (persists).

  • [logic-inconsistency] scripts/post-refine.sh — Three different GitHub detection patterns. Label application and comment posting paths have inconsistent GitHub detection (persists).

  • [dead-env-var] agents/refine.mdTARGET_REPO_DIR documented as input but never wired (persists).

  • [hardcoded-project-keys] scripts/pre-explore.sh:390 — Jira API hints block probes three hardcoded project keys specific to a single Jira instance. Inconsistent with platform-agnostic design (persists).

  • [gha-command-injection] scripts/post-refine.sh, scripts/pre-explore.sh, scripts/post-explore.sh — Inconsistent sanitize_gha application: success paths use sanitized variants but error/warning paths interpolate raw values into GHA workflow commands. post-explore.sh has no sanitize_gha function at all (persists).

  • [excessive-permission] harness/refine.yamlPUSH_TOKEN injected into runner environment but never referenced in post-refine.sh script body. Violates least-privilege (persists).

  • [error-handling-idiom] scripts/post-refine.sh:134, scripts/post-explore.sh:114 — Error messages print to stdout instead of stderr, unlike all other post-scripts (persists).

  • [forward-dependency] docs/refine.md — Documentation references explore and critique agents that don't exist in the repository. The docs explicitly acknowledge this (persists).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (3)

Review

Changes since prior review

The commit since 2072453 modified 1 file (harness/refine.yaml). No prior findings were resolved.

Prior finding Status
Path-mismatch in duplicate-gate.json Persists
Double-linkify-corruption in linkify Persists
Schema custom_fields prompt-mismatch Persists
Missing FULLSEND_VALIDATED_ITERATION_DIR Persists (also in post-explore.sh)
Schema consistency (explore vs refine) Persists
Missing conditional required fields Persists
ORG_KNOWLEDGE not mounted into sandbox Persists
TARGET_REPO_DIR not wired Persists
GHA command injection (multiple scripts) Persists
Inconsistent GitHub detection Persists
Error messages to stdout Persists
Hardcoded project keys Persists

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, and 12 files under scripts/ — 15 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [missing-authorization] No linked issue for a 22-file feature addition. The PR body provides provenance ("Continuation of agent migration from konflux-ci/refinement") but non-trivial changes to protected paths require formal authorization via a linked issue.
    Remediation: Create and link a feature issue.

  • [scope-creep] The PR title "feat: add generic refine agent" understates scope. Beyond the refine agent itself, the PR adds 9 shared utility scripts (comment-helpers.sh, jira-project-schema.sh, markdown-to-adf.py, adf-to-markdown.py, pre-explore.sh, post-explore.sh, platform docs) that serve multiple agents.
    Remediation: Update the PR title/description to accurately reflect scope, or split shared infrastructure into a separate PR.

  • [path-mismatch] agents/refine.md:26 — The agent prompt hardcodes /tmp/workspace/duplicate-gate.json (lines 26, 81, 105). The harness mounts workspace files at /sandbox/workspace/. Inside the sandbox, cat will silently fail (|| true), making the duplicate-work gate feature non-functional (persists).
    Remediation: Change to /sandbox/workspace/duplicate-gate.json, or add a DUPLICATE_GATE env var in env/refine.env.

  • [double-linkify-corruption] scripts/comment-helpers.sh:324 — In the linkify function's generic fallback path, repl_url runs on the output of repl_jira. When repl_jira wraps a bare Jira key as [KEY-123](https://host/browse/KEY-123), the subsequent repl_url matches the URL inside the markdown link and wraps it again, producing corrupted markdown (persists).
    Remediation: Run repl_url before repl_jira, or make repl_url skip URLs already inside markdown link syntax.

  • [schema-prompt-mismatch] schemas/refine-result.schema.json — The agent prompt instructs including a custom_fields map on children when allowed_custom_fields are present. The schema has additionalProperties: false without a custom_fields property — output will fail validation (persists).
    Remediation: Add custom_fields to the children items properties, or remove the custom_fields instructions from the prompt.

  • [result-file-discovery-pattern] scripts/post-refine.sh:127, scripts/post-explore.sh:107 — Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR as a trust boundary (persists; same gap in post-explore.sh).
    Remediation: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback in both scripts.

Low

  • [forward-dependency] docs/refine.md — Documentation references explore and critique agents that don't exist in the repository. The docs explicitly acknowledge this ("added in separate PRs") and pre-refine.sh handles missing explore context gracefully.

  • [schema-consistency] schemas/explore-result.schema.json — Missing additionalProperties: false at root and nested objects, unlike refine-result.schema.json. Also uses disposition instead of status for the blocked_duplicate field, inconsistent with refine-result.schema.json (persists).

  • [missing-conditional-required] schemas/refine-result.schema.jsonspike_title optional but semantically required when resolution is research_spike; assumption_used optional but semantically required when resolution is assumed_default (persists).

  • [missing-host-file] harness/refine.yamlORG_KNOWLEDGE env var points to /sandbox/workspace/org-knowledge.md but no host_files entry mounts it into the sandbox. Degrades gracefully (persists).

  • [logic-inconsistency] scripts/post-refine.sh — Three different GitHub detection patterns. Label application and comment posting paths have inconsistent GitHub detection, though functionally equivalent at runtime (persists).

  • [gha-command-injection] scripts/post-refine.sh, scripts/pre-explore.sh, scripts/post-explore.sh — Inconsistent sanitize_gha application: success paths use sanitized variants but error/warning paths interpolate raw values into GHA workflow commands. post-explore.sh has no sanitize_gha function at all (persists).

  • [excessive-permission] harness/refine.yamlPUSH_TOKEN injected into runner environment but never referenced in post-refine.sh script body. Violates least-privilege.

  • [dead-env-var] agents/refine.mdTARGET_REPO_DIR documented as input but never wired (persists).

  • [hardcoded-project-keys] scripts/pre-explore.sh:390 — Jira API hints block probes three hardcoded project keys specific to a single Jira instance. Inconsistent with platform-agnostic design (persists).

  • [error-handling-idiom] scripts/post-refine.sh:134, scripts/post-explore.sh:114 — Error messages print to stdout instead of stderr, unlike all other post-scripts (persists).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (4)

Review

Changes since prior review

The commit since 7d9d755 modified 9 files, adding a duplicate-work gate feature (blocked_duplicate status) across the refine and explore agents. One new medium-severity finding identified (path-mismatch in duplicate-gate.json path). No prior findings were resolved.

Prior finding Status
Schema custom_fields prompt-mismatch Persists
Double-linkify-corruption in linkify Persists
Missing FULLSEND_VALIDATED_ITERATION_DIR Persists (also in new post-explore.sh)
ORG_KNOWLEDGE not mounted into sandbox Persists
TARGET_REPO_DIR not wired Persists
GHA command injection (multiple scripts) Persists (new instances in pre-refine.sh, post-explore.sh)
Inconsistent GitHub detection Persists
Error messages to stdout Persists (also in new post-explore.sh)
Hardcoded project keys Persists

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, and 12 files under scripts/ — 15 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [path-mismatch] agents/refine.md:26 — The agent prompt hardcodes /tmp/workspace/duplicate-gate.json (lines 26, 81, 105). The harness mounts this file at /sandbox/workspace/duplicate-gate.json. Inside the sandbox, the cat command will silently fail (|| true), so the agent will never see the override flag. The duplicate-work gate feature is non-functional inside the sandbox.
    Remediation: Change all occurrences to /sandbox/workspace/duplicate-gate.json, or add a DUPLICATE_GATE env var in env/refine.env.

  • [double-linkify-corruption] scripts/comment-helpers.sh:324 — In the linkify function's generic fallback path, repl_url runs on the output of repl_jira. When repl_jira wraps a bare Jira key, the subsequent repl_url matches the URL inside the markdown link and wraps it again, producing corrupted markdown (persists).
    Remediation: Run repl_url before repl_jira, or make repl_url skip URLs already inside markdown link syntax.

  • [schema-prompt-mismatch] schemas/refine-result.schema.json — The agent prompt instructs including a custom_fields map on children when allowed_custom_fields are present. The schema has additionalProperties: false without a custom_fields property — output will fail validation (persists).
    Remediation: Add custom_fields to the children items properties, or remove the custom_fields instructions from the prompt.

  • [result-file-discovery-pattern] scripts/post-refine.sh:127, scripts/post-explore.sh:107 — Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR as a trust boundary (persists; same gap in new post-explore.sh).
    Remediation: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback in both scripts.

Low

  • [schema-consistency] schemas/explore-result.schema.json — Missing additionalProperties: false at root and nested objects, unlike refine-result.schema.json and all other agent schemas. Also uses disposition instead of status for the blocked_duplicate field, inconsistent with refine-result.schema.json.

  • [missing-conditional-required] schemas/refine-result.schema.jsonspike_title optional but semantically required when resolution is research_spike; assumption_used optional but semantically required when resolution is assumed_default (persists).

  • [missing-host-file] harness/refine.yamlORG_KNOWLEDGE env var points to /sandbox/workspace/org-knowledge.md but no host_files entry mounts it into the sandbox. Degrades gracefully (persists).

  • [dead-env-var] agents/refine.mdTARGET_REPO_DIR documented as input but never wired (persists).

  • [logic-inconsistency] scripts/post-refine.sh — Three different GitHub detection patterns (persists).

  • [hardcoded-project-keys] scripts/pre-explore.sh:390 — Jira API hints block probes three hardcoded project keys specific to a single Jira instance (persists).

  • [error-handling-idiom] scripts/post-refine.sh:134, scripts/post-explore.sh:114 — Error messages print to stdout instead of stderr, unlike all other post-scripts (persists; same pattern in new post-explore.sh).

  • [gha-command-injection] scripts/post-refine.sh:412, scripts/pre-explore.sh:101, scripts/pre-refine.sh:149, scripts/post-explore.sh:130 — Inconsistent sanitize_gha application: success paths use sanitized variants but error/warning paths interpolate raw values into GHA workflow commands (persists; new instances in pre-refine.sh and post-explore.sh).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (5)

Review

Changes since prior review

The commit since 2ed4e6e modified 2 files (scripts/comment-helpers.sh, scripts/pre-explore.sh). One new finding identified (double-linkify-corruption in the changed comment-helpers.sh). No prior findings were resolved.

Prior finding Status
Schema custom_fields prompt-mismatch Persists
Missing FULLSEND_VALIDATED_ITERATION_DIR Persists
ORG_KNOWLEDGE not mounted into sandbox Persists
PUSH_TOKEN / Jira auth not masked Removed (challenger: PUSH_TOKEN unused in script body; masking claim overstated)
GHA command injection (4 scripts) Persists (pre-explore.sh pre-validation finding downgraded to info)
TARGET_REPO_DIR not wired Persists
Inconsistent GitHub detection Persists
Error messages to stdout Persists
_resolve_companion duplicated Removed (challenger: intentional per ADR-0045 content-addressed isolation)
_CH_ namespace prefix inconsistency Removed (challenger: CH prefix is for variables, not functions)

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, and 11 files under scripts/ — 14 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [double-linkify-corruption] scripts/comment-helpers.sh:323 — In the linkify function's generic fallback path, repl_url runs on the output of repl_jira. When repl_jira wraps a bare Jira key as [KEY-123](https://host/browse/KEY-123), the subsequent repl_url regex matches the https:// URL inside the markdown link (including the trailing )) and wraps it again, producing corrupted markdown like [KEY-123]([url](url). This affects any input line containing a bare Jira key that doesn't match the structured early-return patterns.
    Remediation: Run repl_url before repl_jira, or make repl_url skip URLs already inside markdown link syntax (e.g., negative lookbehind for ]().

  • [schema-prompt-mismatch] schemas/refine-result.schema.json — The agent prompt instructs including a custom_fields map on children when allowed_custom_fields are present. The schema has additionalProperties: false without a custom_fields property — output will fail validation.
    Remediation: Add "custom_fields": { "type": "object" } to the children items properties, or remove the custom_fields instructions from the prompt.

  • [result-file-discovery-pattern] scripts/post-refine.sh:127 — Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR. Missing this pattern breaks the established trust-boundary convention.
    Remediation: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback.

Low

  • [missing-conditional-required] schemas/refine-result.schema.jsonspike_title is optional but semantically required when resolution is research_spike; assumption_used is optional but semantically required when resolution is assumed_default. The rendering code tolerates missing values, so this is a schema-tightening suggestion rather than a runtime bug.

  • [missing-host-file] harness/refine.yamlORG_KNOWLEDGE env var points to /sandbox/workspace/org-knowledge.md. pre-refine.sh calls pack_org_knowledge which writes to /tmp/workspace/org-knowledge.md on the runner, but no host_files entry mounts it into the sandbox. The feature degrades gracefully — the agent proceeds without org knowledge and flags the gap (severity reassessed from medium; graceful degradation confirmed).

  • [dead-env-var] agents/refine.mdTARGET_REPO_DIR documented as input but never wired through env/refine.env, harness/refine.yaml, or scripts/pre-refine.sh (persists).

  • [logic-inconsistency] scripts/post-refine.sh — Three different GitHub detection patterns: (1) $USE_GITHUB for label removal and comments, (2) -n GITHUB_ISSUE_NUMBER && != N/A for label addition, (3) ISSUE_SOURCE == github elif for initial routing (persists).

  • [hardcoded-project-keys] scripts/pre-explore.sh:1246 — Jira API hints block probes three hardcoded project keys (KFLUXUI, KFLUXSE, STONEINTG) specific to a single Jira instance. For a generic agent, these return 404 for any other tenant, producing misleading project_probes in the hints file. Not a runtime failure but noise for non-Konflux tenants.

  • [gha-command-injection] scripts/post-refine.sh:364::warning:: error paths interpolate raw GITHUB_ISSUE_NUMBER, ISSUE_KEY, and REVIEW_ROUND while the corresponding ::notice:: success paths correctly use SAFE_GH_NUM, SAFE_JIRA_KEY, and SAFE_ROUND (persists).

  • [error-handling-idiom] scripts/post-refine.sh:134 — Error messages print to stdout instead of stderr, unlike all other post-scripts (persists).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (6)

Review

Changes since prior review

The commits since b3646f0 modified 6 files (agents/refine.md, schemas/refine-result.schema.json, scripts/comment-helpers.sh, scripts/post-refine-test.sh, scripts/post-refine.sh, scripts/pre-explore.sh). The changes add an open_questions resolution-bucket feature (needs_human, research_spike, assumed_default) across the agent prompt, schema, helpers, post-script, and tests. No prior findings were resolved.

Prior finding Status
Schema custom_fields prompt-mismatch Persists
ORG_KNOWLEDGE not mounted into sandbox Persists (severity reassessed to low)
Missing FULLSEND_VALIDATED_ITERATION_DIR Persists
PUSH_TOKEN / Jira auth not masked Persists
GHA command injection (4 scripts) Persists
TARGET_REPO_DIR not wired Persists
Inconsistent GitHub detection Persists
Error messages to stdout Persists
_resolve_companion duplicated Persists
_CH_ namespace prefix inconsistency Persists
Scope creep (comment-helpers.sh) Removed (not actionable)
Missing authorization (no linked issue) Subsumed by protected-path
env/refine.env shell expansion Removed (intentional pattern)
pre-explore.sh emoji checkmarks Removed (cosmetic)

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, and 11 files under scripts/ — 14 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [schema-prompt-mismatch] schemas/refine-result.schema.json — The agent prompt instructs including a custom_fields map on children when allowed_custom_fields are present. The schema has additionalProperties: false without a custom_fields property — output will fail validation.
    Remediation: Add "custom_fields": { "type": "object" } to the children items properties, or remove the custom_fields instructions from the prompt.

  • [result-file-discovery-pattern] scripts/post-refine.sh:127 — Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR. Missing this pattern breaks the established trust-boundary convention.
    Remediation: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback.

Low

  • [missing-host-file] harness/refine.yamlORG_KNOWLEDGE env var points to /sandbox/workspace/org-knowledge.md and the agent reads it in Phase 1. pre-refine.sh calls pack_org_knowledge which writes to /tmp/workspace/org-knowledge.md on the runner, but no host_files entry mounts it into the sandbox. The feature degrades gracefully — the agent proceeds without org knowledge and flags the gap — but the mount is missing (severity reassessed from medium; graceful degradation confirmed).

  • [missing-conditional-required] schemas/refine-result.schema.jsonspike_title is optional but semantically required when resolution is research_spike; assumption_used is optional but semantically required when resolution is assumed_default. The rendering code tolerates missing values, so this is a schema-tightening suggestion rather than a runtime bug.

  • [secrets-handling] scripts/post-refine.shPUSH_TOKEN and Jira auth tokens not masked (persists from prior review). Every other post-script masks PUSH_TOKEN immediately. Jira base64 auth computed three separate times but never masked.

  • [gha-command-injection] scripts/post-refine.sh, scripts/pre-refine.sh, scripts/pre-explore.sh, scripts/jira-project-schema.sh — Inconsistent sanitize_gha application across four scripts (persists). Success paths use sanitized variables but error/warning paths interpolate raw values into ::warning:: and ::notice:: commands.

  • [dead-env-var] agents/refine.mdTARGET_REPO_DIR documented as input but never wired (persists).

  • [logic-inconsistency] scripts/post-refine.sh — Three different GitHub detection patterns (persists).

  • [error-handling-idiom] scripts/post-refine.sh — Error messages print to stdout instead of stderr, unlike all other post-scripts (persists).

  • [code-duplication] scripts/post-refine.sh_resolve_companion function duplicated verbatim across scripts (~126 lines total) (persists).

  • [naming-inconsistency] scripts/comment-helpers.sh — Private helpers _default_child_project and _format_string_array_bullets drop the _CH_ namespace prefix (persists).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (7)

Review

Changes since prior review

The commits since ca1e31d added 2 new files (scripts/jira-project-schema.sh, scripts/pre-explore.sh) and modified 2 existing files (scripts/post-refine.sh, scripts/pre-refine.sh). The prior [missing-dependency] finding for pre-explore.sh is resolved — the file is now included directly in this PR.

Prior finding Status
Schema custom_fields prompt-mismatch Persists
PUSH_TOKEN / Jira auth not masked Persists (severity reassessed to low)
pre-explore.sh dependency on PR #11 Resolved — now included in this PR
GHA command injection (post-refine.sh) Persists
GHA command injection (pre-refine.sh) Persists
TARGET_REPO_DIR not wired Persists
Inconsistent GitHub detection Persists
Missing null guard (open_questions) Not reproduced
Naming inconsistency (env/refine.env) Persists
Naming inconsistency (comment-helpers.sh) Persists

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, and 11 files under scripts/ — 14 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [schema-prompt-mismatch] schemas/refine-result.schema.json:63 — The agent prompt instructs including a custom_fields map on children when allowed_custom_fields are present. The schema has additionalProperties: false without a custom_fields property — output will fail validation.
    Remediation: Add "custom_fields": { "type": "object" } to the children items properties, or remove the custom_fields instructions from the prompt.

  • [missing-host-file] harness/refine.yaml:23ORG_KNOWLEDGE env var points to /sandbox/workspace/org-knowledge.md and the agent reads it in Phase 1. pre-refine.sh calls pack_org_knowledge which writes to /tmp/workspace/org-knowledge.md on the runner, but no host_files entry mounts it into the sandbox. The org knowledge feature is non-functional.
    Remediation: Add a host_files entry: { src: /tmp/workspace/org-knowledge.md, dest: /sandbox/workspace/org-knowledge.md, optional: true }.

  • [result-file-discovery-pattern] scripts/post-refine.sh:127 — Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR. Missing this pattern breaks the established trust-boundary convention.
    Remediation: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback.

Low

  • [secrets-handling] scripts/post-refine.shPUSH_TOKEN and Jira auth tokens not masked (persists from prior review). Every other post-script masks PUSH_TOKEN immediately. Jira base64 auth computed three separate times but never masked. Mitigated by curl -sS flags but inconsistent.

  • [gha-command-injection] scripts/post-refine.sh:377, scripts/pre-refine.sh:366, scripts/pre-explore.sh:101, scripts/jira-project-schema.sh:128 — Inconsistent sanitize_gha application across four scripts (persists in post-refine.sh and pre-refine.sh; new in pre-explore.sh and jira-project-schema.sh). Success paths use sanitized variables but error/warning paths interpolate raw values into ::warning:: and ::notice:: commands. In pre-explore.sh, raw values are logged before input validation.

  • [scope-creep] scripts/comment-helpers.sh — PR introduces shared infrastructure scripts (comment-helpers.sh, adf-to-markdown.py, markdown-to-adf.py, jira-project-schema.sh, pre-explore.sh) originally from PR feat: add generic explore agent #11 that serve the broader pipeline.

  • [missing-authorization] agents/refine.md — 4698-line feature addition with no linked issue to formalize authorization scope.

  • [dead-env-var] agents/refine.md:236TARGET_REPO_DIR documented as input but never wired (persists).

  • [logic-inconsistency] scripts/post-refine.sh:366 — Three different GitHub detection patterns (persists).

  • [error-handling-idiom] scripts/post-refine.sh:135 — Error messages print to stdout instead of stderr, unlike all other post-scripts.

  • [code-duplication] scripts/post-refine.sh:46_resolve_companion function duplicated verbatim across three scripts (~165 lines total). The repo has a bundling system for shared code.

  • [naming-inconsistency] env/refine.env:4 — Uses ${REVIEW_ROUND:-1} shell parameter expansion; other env files use plain static exports (persists).

  • [naming-inconsistency] scripts/comment-helpers.sh — Private helpers _default_child_project and _format_string_array_bullets drop the _CH_ namespace prefix (persists).

  • [naming-inconsistency] scripts/pre-explore.sh:261 — Uses emoji checkmarks in log output; existing scripts use plain text or GHA workflow commands.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (8)

Review

Changes since prior review

The commits since e31798dd added 2 new files (scripts/comment-helpers.sh, scripts/adf-to-markdown.py) and modified 7 existing files. This partially resolves the prior [missing-dependency] finding — comment-helpers.sh and markdown-to-adf.py are now in this PR, but pre-explore.sh remains an unresolved dependency on PR #11.

Prior finding Status
Schema custom_fields prompt-mismatch Persists
PUSH_TOKEN / Jira auth not masked Persists
pre-explore.sh dependency on PR #11 Partially resolved (comment-helpers.sh added; pre-explore.sh still missing)
GHA command injection (post-refine.sh) Persists
GHA command injection (pre-refine.sh) Persists
TARGET_REPO_DIR not wired Persists
Inconsistent GitHub detection Persists

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, scripts/pre-refine.sh, scripts/post-refine.sh, scripts/post-refine-test.sh, scripts/platform-github.md, scripts/platform-gitlab.md, scripts/platform-jira.md, scripts/comment-helpers.sh, scripts/markdown-to-adf.py, scripts/adf-to-markdown.py — 12 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [schema-prompt-mismatch] schemas/refine-result.schema.json:63 — The agent prompt (agents/refine.md) instructs the agent to include a custom_fields map on children when allowed_custom_fields are present in the issue context. However, the children items schema has additionalProperties: false without defining a custom_fields property. If the agent follows the prompt, output will fail schema validation, consuming a retry iteration (max_iterations: 2).
    Remediation: Add "custom_fields": { "type": "object" } to the children items properties in the schema, or remove the custom_fields instructions from the agent prompt.

  • [secrets-handling] scripts/post-refine.shPUSH_TOKEN and Jira auth tokens not masked (persists from prior review). PUSH_TOKEN is passed via forge.github.env.runner but never masked with ::add-mask::. Jira base64 auth tokens computed three separate times (AUTH_DESC, AUTH_ATTACH, AUTH_LABEL) but never masked. Same pattern in pre-refine.sh (AUTH, CRIT_AUTH). Every other post-script that receives PUSH_TOKEN masks it immediately.
    Remediation: Mask at top of script: echo "::add-mask::${PUSH_TOKEN}". Compute Jira auth once and mask: JIRA_AUTH=$(printf '%s:%s' "$JIRA_EMAIL" "$JIRA_API_TOKEN" | base64 -w0); echo "::add-mask::${JIRA_AUTH}".

Low

  • [dead-env-var] agents/refine.md:236TARGET_REPO_DIR documented as an input env var but never wired through env/refine.env, harness/refine.yaml, or scripts/pre-refine.sh (persists from prior review).
    Remediation: Remove from the Inputs list or wire through the harness.

  • [gha-command-injection] scripts/post-refine.sh — Inconsistent sanitize_gha application (persists from prior review). Success paths use sanitized variables (SAFE_GH_NUM, SAFE_JIRA_KEY) but error/warning paths interpolate raw GITHUB_ISSUE_NUMBER, ISSUE_KEY, and REVIEW_ROUND into ::warning:: commands.
    Remediation: Compute SAFE_* variables before if/else blocks so both branches use sanitized values.

  • [gha-command-injection] scripts/pre-refine.sh:336 — Raw ISSUE_SOURCE in ::warning:: output (persists from prior review). SAFE_ISSUE_SOURCE is computed at line 101 but raw ISSUE_SOURCE is used at line 336.
    Remediation: Use SAFE_ISSUE_SOURCE in the warning output.

  • [missing-dependency] scripts/pre-refine.sh:56pre-explore.sh still not included (partially resolved from prior review). comment-helpers.sh and markdown-to-adf.py were pulled into this PR, but pre-explore.sh remains an external dependency on PR feat: add generic explore agent #11. The script has explicit existence checks with clear error messages.
    Remediation: Coordinate merge ordering so PR feat: add generic explore agent #11 merges first.

  • [logic-inconsistency] scripts/post-refine.sh — Inconsistent GitHub detection conditions (persists from prior review). Three different patterns: (1) $USE_GITHUB for label removal and comments, (2) -n GITHUB_ISSUE_NUMBER && != N/A for label addition, (3) ISSUE_SOURCE == github elif for initial routing.
    Remediation: Use $USE_GITHUB consistently for all GitHub operations.

  • [missing-null-guard] scripts/post-refine.sh:173jq '.open_questions | length' does not use // [] null-coalescing, unlike the test file’s jq '.open_questions // [] | length'. open_questions is not required in the schema. Works today since jq’s null | length returns 0, but inconsistent with defensive patterns used elsewhere.
    Remediation: Change to jq '.open_questions // [] | length'.

  • [naming-inconsistency] env/refine.env:4 — Uses ${REVIEW_ROUND:-1} shell parameter expansion while other env files use plain static exports.
    Remediation: Use a plain static export (export REVIEW_ROUND=1).

  • [naming-inconsistency] scripts/comment-helpers.sh — Private helper functions _default_child_project and _format_string_array_bullets drop the _CH_ namespace prefix used by other library-private helpers (_CH_AGENT, _CH_DIR, etc.).
    Remediation: Follow the _ch_ namespace for all library-private helpers.


Notes

  • Architecture: File layout follows established agent patterns well. Image choice (fullsend-sandbox:latest) is correct for a read-only agent.
  • Schema: additionalProperties: false and required fields correctly set. $schema and $id match repo conventions.
  • Security posture: Sandbox policy correctly enforces read-only API access. disallowedTools blocks all gh api calls. GH_TOKEN properly excluded from env.sandbox.
  • Dependency resolution: comment-helpers.sh and markdown-to-adf.py moved from PR feat: add generic explore agent #11 into this PR, partially resolving the cross-PR dependency. pre-explore.sh remains the only unresolved dependency.
  • New utility: adf-to-markdown.py provides Jira ADF → Markdown conversion for the pre-script’s issue context fetching, complementing the existing markdown-to-adf.py.
  • PR title: feat: add generic refine agent uses Conventional Commits format per AGENTS.md.

Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (9)

Review

Findings

High

  • [protected-path] agents/refine.md, harness/refine.yaml, policies/refine.yaml, scripts/post-refine.sh, scripts/pre-refine.sh, scripts/post-refine-test.sh, scripts/platform-github.md, scripts/platform-gitlab.md, scripts/platform-jira.md — 9 files under protected paths (agents/, harness/, policies/, scripts/) are modified. The PR has no linked issue authorizing changes to governance and infrastructure files. Human approval is always required for protected-path changes.

Medium

  • [schema-prompt-mismatch] schemas/refine-result.schema.json:66 — The agent prompt (agents/refine.md, Phase 1 routable_projects section) instructs the agent to include a custom_fields map on children when allowed_custom_fields are present in the issue context. However, the children schema has additionalProperties: false without defining a custom_fields property. If the agent follows the prompt, output will fail schema validation, consuming a retry iteration (max_iterations: 2).
    Remediation: Add "custom_fields": { "type": "object", "additionalProperties": true } to the children items properties in the schema, or remove the custom_fields instructions from the agent prompt.

  • [secrets-handling] scripts/post-refine.shPUSH_TOKEN and Jira auth tokens not masked (persists from prior review). PUSH_TOKEN is passed via forge.github.env.runner but never masked with ::add-mask::. Jira base64 auth tokens computed three separate times (AUTH_DESC, AUTH_ATTACH, AUTH_LABEL) but never masked. Same pattern in pre-refine.sh (AUTH, CRIT_AUTH). Every other post-script that receives PUSH_TOKEN masks it immediately.
    Remediation: Mask at top of script: echo "::add-mask::${PUSH_TOKEN}". Compute Jira auth once and mask: JIRA_AUTH=$(printf '%s:%s' "$JIRA_EMAIL" "$JIRA_API_TOKEN" | base64 -w0); echo "::add-mask::${JIRA_AUTH}".

  • [missing-dependency] scripts/post-refine.sh, scripts/pre-refine.sh — Hard dependencies on files from PR feat: add generic explore agent #11 (persists from prior review, severity lowered from high to medium). post-refine.sh sources comment-helpers.sh and calls markdown-to-adf.py; pre-refine.sh calls pre-explore.sh. None exist on main. Scripts have explicit existence checks with clear error messages and immediate exit.
    Remediation: Coordinate merge ordering so PR feat: add generic explore agent #11 merges first.

Low

  • [dead-env-var] agents/refine.md:104TARGET_REPO_DIR documented as an input env var "set by the pre-script" but never wired through env/refine.env, harness/refine.yaml, or scripts/pre-refine.sh.
    Remediation: Remove from the Inputs list or wire through the harness.

  • [gha-command-injection] scripts/post-refine.sh — Inconsistent sanitize_gha application (persists from prior review). Success paths use sanitized variables (SAFE_GH_NUM, SAFE_JIRA_KEY) but error/warning paths interpolate raw GITHUB_ISSUE_NUMBER, ISSUE_KEY, and REVIEW_ROUND into ::warning:: commands.
    Remediation: Compute SAFE_* variables before if/else blocks so both branches use sanitized values.

  • [gha-command-injection] scripts/pre-refine.sh — Raw ISSUE_SOURCE in ::notice:: and ::warning:: output (persists from prior review). SAFE_ISSUE_SOURCE is computed at line 37 but raw ISSUE_SOURCE is used at lines 303 and 306.
    Remediation: Use SAFE_ISSUE_SOURCE in the warning output.

  • [test-coverage] scripts/post-refine-test.sh — Test gaps (persists from prior review). Tests miss: (a) GitHub fallback routing where ISSUE_SOURCE=github and GITHUB_ISSUE_NUMBER is empty (the code path setting GITHUB_ISSUE_NUMBER="${ISSUE_KEY}"), (b) proposed-description update flow, (c) Jira attachment handling, (d) data-sources footer construction.
    Remediation: Add tests for the GitHub fallback routing and data-sources footer construction at minimum.

  • [logic-inconsistency] scripts/post-refine.sh — Inconsistent GitHub detection conditions (persists from prior review). Three different patterns: (1) $USE_GITHUB for label removal and comments, (2) -n GITHUB_ISSUE_NUMBER && != N/A for label addition, (3) ISSUE_SOURCE == github elif for initial routing.
    Remediation: Use $USE_GITHUB consistently for all GitHub operations.


Notes

  • Architecture: File layout follows established agent patterns well. Image choice (fullsend-sandbox:latest) is correct for a read-only agent.
  • Schema: additionalProperties: false and required fields are correctly set. $schema and $id match repo conventions.
  • Security posture: Sandbox policy correctly enforces read-only API access. disallowedTools blocks all gh api calls. GH_TOKEN is properly excluded from env.sandbox.
  • Cross-repo contracts: No breaking changes — all modifications to existing files are purely additive.
  • PR title: feat: add generic refine agent uses Conventional Commits format per AGENTS.md.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 9, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:12 PM UTC · Completed 6:23 PM UTC
Commit: 99cb712 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 9, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 7:57 PM UTC · Completed 8:10 PM UTC
Commit: a47c056 · View workflow run →

@fullsend-ai-review
fullsend-ai-review Bot dismissed stale reviews from themself July 9, 2026 20:10

Superseded by updated review

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment feature labels Jul 9, 2026
Comment thread env/refine.env

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.

Same deal as the other PR, move this to the harness

@rh-hemartin rh-hemartin 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.

I want to move some envs to the harness file.

@ascerra
ascerra marked this pull request as draft July 13, 2026 20:39
@ascerra

ascerra commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Update for konflux-ci/refinement base: consumption (7a404e0)

Refinement PR https://github.com/konflux-ci/refinement/pull/18 now pins this harness via ADR 0045 base: so we can test generic agents before this PR merges to main.

This push adds (generic only):

Still install-only (stays in refinement, not this PR):

  • Konflux skill URL pins (konflux-architecture, red-hat-konflux-teams)
  • program-decomposition skill
  • jira-routing / stage create allowlists
  • pack-org-knowledge.sh + curated Path B / Drive Path A
  • local pre/post that pack ORG_KNOWLEDGE

Reviewer note: Prior review threads that were already fixed in earlier commits remain fixed. New work is the ORG_KNOWLEDGE contract + companion resolution for base: testing from refinement. When this merges, refinement will flip base: from this branch SHA to main.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 24, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 7:48 PM UTC · Ended 8:03 PM UTC
Commit: 7a404e0 · View workflow run →

@ascerra
ascerra force-pushed the feat/add-refine-agent branch from 7a404e0 to ab73ea1 Compare July 24, 2026 20:03
@ascerra

ascerra commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

CI fix pass (ab73ea1)

Rebased onto current main and squashed to a single conventional commit so checks pass:

  • commit-lint: tip subjects no longer end with :; explore’s non-conventional root commit removed via squash
  • detect / functional-tests: branch now includes .github/scripts/select-eval-agents.sh from main (required because pull_request_target checks out PR head)
  • test / shellcheck (explore): fixed SC2015 / SC2129 / SC2034 / SC2295 in pre-explore.sh + comment-helpers.sh

Harness file #sha256= unchanged — only the commit OID moves for refinement base: pins.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 24, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 8:04 PM UTC · Ended 8:11 PM UTC
Commit: ab73ea1 · View workflow run →

Introduce refine harness, agent prompt, scripts, and schema. Consume
optional ORG_KNOWLEDGE for install-injected org context without failing
when the pack is absent. Resolve companion script helpers for
base-composition installs.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@ascerra
ascerra force-pushed the feat/add-refine-agent branch from ab73ea1 to e31798d Compare July 24, 2026 20:11
@ascerra

ascerra commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto latest main (d7afc9c) so the branch is no longer out of date. Tip: e31798d (harness #sha256= unchanged).

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 24, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:13 PM UTC · Completed 8:29 PM UTC
Commit: e31798d · View workflow run →

ascerra and others added 2 commits July 28, 2026 17:17
Stop treating every assumption as a reply-required Open Question.
Require resolution=needs_human|research_spike|assumed_default, render
sticky sections accordingly, and ban triple-booking assume+spike+ask.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 28, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:19 PM UTC · Completed 9:38 PM UTC
Commit: 2ed4e6e · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 29, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:12 AM UTC · Completed 1:30 AM UTC
Commit: 7d9d755 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

Phase 0 duplicate gate emits blocked_duplicate with empty children and
skips ready-to-critique. Second /fs-refine after the sticky marker overrides.
Syncs comment-helpers + explore companions for same-commit fetch.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 29, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 11:51 AM UTC · Completed 12:12 PM UTC
Commit: 2072453 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 4, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:19 PM UTC · Completed 8:38 PM UTC
Commit: 5f73801 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

Phase 0 cats /tmp/workspace/duplicate-gate.json; also try the
sandbox mount path and report clearly when neither exists so
override=true is not silently missed.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 4, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:44 PM UTC · Completed 10:06 PM UTC
Commit: bee87be · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

Align refine (and explore schema copy) with 0.0–5.0 confidence and
issue_id/project.id naming so ticket IDs survive secret redaction.

Assisted-by: Cursor
Signed-off-by: Adam Scerra <ascerra@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 8, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 5:04 PM UTC · Completed 5:21 PM UTC

Commit: 84b2b45 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

Companion fetch must match explore tip so refine runs do not regress
rate-limit / private-repo guards.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 8, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 11:09 PM UTC · Ended 11:13 PM UTC

Commit: d4bdc62 · View workflow run →

Ask Story/Task children for 1–3 concrete repo file/package anchors from
explore evidence (REPO-INDEX / accessed sources), never invented paths.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 8, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 11:14 PM UTC · Completed 11:36 PM UTC

Commit: e52b424 · View workflow run →

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

url = mo.group(0).rstrip(").,;]")
return f"[{url}]({url})"

out = re.sub(r"https?://[^\s<>{}\"|\\^`\[\]]+", repl_url, out)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] double-linkify-corruption

In the linkify function generic fallback path, repl_url runs on the output of repl_jira, double-wrapping URLs inside markdown links and producing corrupted markdown.

Suggested fix: Run repl_url before repl_jira, or make repl_url skip URLs already inside markdown link syntax.

Comment thread scripts/post-refine.sh
}

RESULT_FILE=""
for dir in iteration-*/output; do

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] result-file-discovery-pattern

Result file discovery uses only the iteration-*/output glob fallback. Every other post-script first checks FULLSEND_VALIDATED_ITERATION_DIR as a trust boundary.

Suggested fix: Add the standard FULLSEND_VALIDATED_ITERATION_DIR block before the glob fallback.

Comment thread harness/refine.yaml
agent: agents/refine.md
doc: docs/refine.md
model: opus
image: ghcr.io/fullsend-ai/fullsend-sandbox:latest

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] image-not-pinned

All existing harness definitions pin the sandbox image by digest (@sha256:...). The refine harness uses :latest, which is non-reproducible and breaks the codebase convention for deterministic builds.

Suggested fix: Pin the image to a specific sha256 digest.

Comment thread scripts/pre-explore.sh
for c in "${CLONED[@]+"${CLONED[@]}"}"; do
[[ "$c" == "$ref" ]] && already=true && break
done
$already || CLONED+=("$ref")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] gha-command-injection

The ::notice:: command interpolates ${CLONED[*]} without sanitization. Although GitHub org/repo naming rules make injection impractical, the codebase convention is to sanitize all values interpolated into GHA workflow commands.

Comment thread scripts/pre-explore.sh
extract_repo_refs_from_text() {
TEXT_CONTENT=$(jq -r '
[.description // "", (.comments // [] | .[].body // "")] | join("\n")
' "$WORKSPACE/issue-context.json")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] gha-command-injection

The ::warning:: in validate_repo interpolates ${ref} without sanitization.

Comment thread scripts/pre-explore.sh
if [[ "${ISSUE_SOURCE:-}" == "jira" && -n "${JIRA_HOST:-}" && -n "${JIRA_EMAIL:-}" && -n "${JIRA_API_TOKEN:-}" ]]; then
_jira_auth=$(printf '%s:%s' "$JIRA_EMAIL" "$JIRA_API_TOKEN" | base64 -w0)
_probe_codes=""
for _proj in KFLUXUI KFLUXSE STONEINTG; do

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] hardcoded-project-keys

Jira API hints block probes three hardcoded project keys specific to a single Jira instance.

@ascerra

ascerra commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Closing without merge — keep the branch

Closing #86 (refine). Refine is not cancelled.

Same situation as #11: an open draft PR used as a pin target meant every branch update re-triggered fullsend review. Extending /fs-stop was the candidate platform fix; we’re not rushing that. Closing this PR lets us keep testing and updating feat/add-refine-agent without review on every push. Reopen when refine is ready for review.

Team decision 2026-08-10 (notes).

Depends on explore shared scripts from #11 (feat/add-explore-agent); downstream critique is #87 (feat/add-critique-agent). Pin installs to branch SHAs.

@ascerra ascerra closed this Aug 11, 2026
@fullsend-ai-retro

fullsend-ai-retro Bot commented Aug 11, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 12:41 AM UTC · Completed 12:52 AM UTC

Commit: e52b424 · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #86 — feat: add generic refine agent

Outcome: Closed without merge after 33 days and 19 review agent runs.

Timeline

  • Jul 9: PR opened with 22 new files (6,218 additions) adding a platform-agnostic refine agent — agent definition, harness config, sandbox policy, pre/post scripts, test suite, platform context docs, and shared infrastructure bundled from unmerged PR feat: add generic explore agent #11 (explore agent).
  • Jul 9 (rounds 1–3): Review agent caught ~11 genuine issues: output filename mismatch (refine-result.json vs agent-result.json), GHA command injection via unsanitized variables, missing fullsend-check-output validation call, trigger label not removed after completion, schema missing additionalProperties: false and using wrong draft version, and missing dependency guards for shared scripts from PR feat: add generic explore agent #11. Author fixed all in commits 99cb712 and a47c056.
  • Jul 10: Human reviewer rh-hemartin left one comment ("move env to the harness") — a repo convention the review agent did not flag.
  • Jul 24–Aug 8 (rounds 4–19): Review agent ran 16 more times across 8 pushes. Each round re-raised ~7–12 findings, mostly the same persisting set: double-linkify-corruption, schema-prompt-mismatch, result-file-discovery-pattern, image-not-pinned, hardcoded-project-keys, gha-command-injection on error paths, error-handling-idiom, and excessive-permission. The author had acknowledged these as intentional, deferred, or low-priority.
  • Aug 11: Author closed the PR, explaining: "every branch update re-triggered fullsend review. Closing stops review noise while the branch continues development." Development continues on the branch; the PR was used as a dependency pin target for PRs feat: add generic explore agent #11 and feat: add generic critique agent #87.

Review quality assessment

Early rounds were high-value. The review agent identified genuine correctness bugs, security issues, and schema deficiencies — 11 findings that the author fixed. The challenger sub-agent and multi-dimension approach worked well for first-pass review.

Later rounds delivered diminishing returns. Rounds 4–19 produced ~85 additional inline findings, but nearly all were repeats of the same ~9 persisting issues. The author had responded to each with explanations ("Acknowledged: intentional," "Fixed earlier," "Depends on PR #11"), but the review agent did not incorporate these responses. This noise-to-signal ratio degraded trust and ultimately caused the author to close the PR.

One human-only catch. rh-hemartin identified a repo convention (env vars should live in the harness config, not a separate env file) that the review agent missed. This convention is not documented in AGENTS.md.

CI failures went unaddressed. The CI test check failed consistently due to shellcheck warnings (unquoted variables in comment-helpers.sh and post-refine.sh), a missing trailing newline in pre-explore.sh, and missing required doc sections (## Setup, ## Triggers, ## Configuration) in docs/refine.md. These are the author's responsibility to fix, not the review agent's.

Evidence for existing issues (no new proposals filed)

All problems identified in this retro are already tracked by existing open issues. PR #86 provides additional evidence for the severity and user impact of the review dedup/noise cluster:

  • fullsend#1013 / fullsend#2959: PR feat: add generic refine agent #86 had ~9 findings repeated verbatim across 10+ review rounds, matching the dedup gap these issues describe. Scale: 19 runs, ~97 total inline findings.
  • agents#685 / agents#106: The review agent re-raised findings the author had explicitly acknowledged as intentional or deferred (e.g., hard dependency on PR feat: add generic explore agent #11, hardcoded Jira keys). Author responses were not incorporated into re-review decisions.
  • fullsend#2587 / fullsend#2599: No per-PR review cap prevented the 19-run accumulation. The author's only recourse was closing the PR — a user-hostile outcome.
  • fullsend#4682 / fullsend#3515: Author dismissals and explanations in review threads did not suppress findings in subsequent rounds.
  • fullsend#4115: A repo-configurable "pause-review" label would have let the author continue development without closing the PR.
  • agents#302: The review agent did not self-report coverage limitations despite reviewing a 6,218-line, 22-file PR.
  • agents#343: Re-review narrowing (step 3c) reduced dimension dispatches but did not prevent individual finding repetition within dispatched dimensions.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants