Skip to content

fix(#2393): add diagnostic stderr output to post-script failure paths - #2395

Merged
ralphbean merged 4 commits into
mainfrom
agent/2393-post-script-diagnostic-errors
Jun 18, 2026
Merged

fix(#2393): add diagnostic stderr output to post-script failure paths#2395
ralphbean merged 4 commits into
mainfrom
agent/2393-post-script-diagnostic-errors

Conversation

@fullsend-ai-coder

Copy link
Copy Markdown
Contributor

All exit 1 paths across the 6 post-scripts (post-triage, post-code, post-review, post-retro, post-fix, post-prioritize) now emit a clear error message to stderr before exiting. This addresses three categories of issues:

  1. Silent exit paths: post-review.sh exited with the fullsend
    post-review exit code but produced no diagnostic message.
    post-fix.sh exited silently when process-fix-result.py failed
    with bad input. Both now emit descriptive stderr messages.

  2. Stdout-only errors: All echo "ERROR:..." and echo "::error::..."
    messages now include >&2 to ensure they appear on stderr, making
    them visible in GitHub Actions logs regardless of stdout buffering.

  3. Missing context: HTTP-related failures now include the endpoint
    or command that failed. The add_label function in post-triage.sh
    captures and reports the gh API error output. Push failures in
    post-code.sh include the push output. PR creation failures include
    the head/base branch info. post-prioritize.sh errors include
    project and org context.


Closes #2393

Post-script verification

  • Branch is not main/master (agent/2393-post-script-diagnostic-errors)
  • Secret scan passed (gitleaks — 25d4659c9a0f620899e379ebe0894d45c0836016..HEAD)
  • Pre-commit hooks passed (authoritative run on runner)
  • Tests ran inside sandbox

All exit 1 paths across the 6 post-scripts (post-triage, post-code,
post-review, post-retro, post-fix, post-prioritize) now emit a clear
error message to stderr before exiting. This addresses three categories
of issues:

1. Silent exit paths: post-review.sh exited with the fullsend
   post-review exit code but produced no diagnostic message.
   post-fix.sh exited silently when process-fix-result.py failed
   with bad input. Both now emit descriptive stderr messages.

2. Stdout-only errors: All echo "ERROR:..." and echo "::error::..."
   messages now include >&2 to ensure they appear on stderr, making
   them visible in GitHub Actions logs regardless of stdout buffering.

3. Missing context: HTTP-related failures now include the endpoint
   or command that failed. The add_label function in post-triage.sh
   captures and reports the gh API error output. Push failures in
   post-code.sh include the push output. PR creation failures include
   the head/base branch info. post-prioritize.sh errors include
   project and org context.

Closes #2393
@github-actions

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

Site preview

Preview: https://8d7477d9-site.fullsend-ai.workers.dev

Commit: 36186df8fcf01ac28556afbd649e5ffeae3a76d1

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 5:33 PM UTC · Completed 5:45 PM UTC
Commit: 12b47a9 · View workflow run →

@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [protected-path] internal/scaffold/fullsend-repo/scripts/ — All 6 changed files are under the protected scripts/ path. The PR links to issue Post-script failures are silent — add diagnostic error output #2393 and the description explains the rationale for modifying these governance/infrastructure files. Human approval is always required for protected-path changes, regardless of context.

Low

  • [error-handling] internal/scaffold/fullsend-repo/scripts/post-retro.sh:161 — The error path at line 161 (ERROR: failed to post summary comment...) still writes to stdout, not stderr. This is the only exit 1 error path in post-retro.sh that the PR does not redirect to stderr, inconsistent with the PR's stated goal.
    Remediation: Add >&2 to the echo on line 161.

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:338${PUSH_OUTPUT} is interpolated unsanitized into a ::error:: GHA workflow command. PUSH_OUTPUT captures the combined stdout/stderr of git push, which could contain sequences like ::set-env:: if a server-side git hook or proxy injects them. The >&2 redirect does not mitigate the injection vector — the GHA runner processes :: commands on both stdout and stderr.
    Remediation: Sanitize PUSH_OUTPUT by stripping :: sequences before interpolating, or use a plain ERROR: prefix instead of ::error::.

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:416 — The stderr output of gh pr create is written to the runner via cat "${PR_CREATE_STDERR}" >&2 without sanitization. The GHA runner scans both stdout and stderr for workflow commands. If the GitHub API error response echoes back user-controlled data containing :: sequences, those would be interpreted as workflow commands.
    Remediation: Pipe through sed to neutralize workflow commands before output: sed 's/::/ : : /g' "${PR_CREATE_STDERR}" >&2.

  • [error-output-consistency] internal/scaffold/fullsend-repo/scripts/post-prioritize.sh — The post-scripts mix error-handling conventions: plain echo "ERROR: ..." to stdout, GHA workflow commands echo "::error::..." to stdout, and now >&2 redirections. The PR is actively improving consistency, but establishing a clear convention would help: use ::error:: for GHA annotations (stdout per GHA spec) and ERROR: with >&2 for script-level diagnostics.

Info

  • [error-handling] internal/scaffold/fullsend-repo/scripts/post-code.sh:409 — The temp file created by PR_CREATE_STDERR=$(mktemp) is cleaned up in both the success and failure branches. However, if the script exits unexpectedly between mktemp and the cleanup rm -f calls (due to set -e or a signal), the temp file will leak. Negligible impact in an ephemeral GHA runner environment.

  • [diagnostic-completeness] internal/scaffold/fullsend-repo/scripts/post-review.sh:180 — The new error message provides useful context (exit code, PR number, repo). However, the fullsend post-review command's stderr is not captured, so the actual failure output is lost. Consider capturing stderr and including it in the error message, consistent with the pattern used for gh pr create in post-code.sh.

Previous run

Review

Findings

Medium

  • [protected-path] internal/scaffold/fullsend-repo/scripts/ — All 6 changed files are under the protected scripts/ path. The PR links to issue Post-script failures are silent — add diagnostic error output #2393 and the description explains the rationale for modifying these governance/infrastructure files. Human approval is always required for protected-path changes, regardless of context.

Low

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:338${PUSH_OUTPUT} is interpolated unsanitized into a ::error:: GHA workflow command. PUSH_OUTPUT captures the combined stdout/stderr of git push, which could contain sequences like ::set-env:: if a server-side git hook or proxy injects them. The >&2 redirect does not mitigate the injection vector — the GHA runner processes :: commands on both stdout and stderr.
    Remediation: Sanitize PUSH_OUTPUT by stripping :: sequences before interpolating, or use a plain ERROR: prefix instead of ::error::.

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:416 — The stderr output of gh pr create is written to the runner via cat "${PR_CREATE_STDERR}" >&2 without sanitization. The GHA runner scans both stdout and stderr for workflow commands. If the GitHub API error response echoes back user-controlled data containing :: sequences, those would be interpreted as workflow commands.
    Remediation: Pipe through sed to neutralize workflow commands before output: sed 's/::/ : : /g' "${PR_CREATE_STDERR}" >&2.

Info

  • [error-handling] internal/scaffold/fullsend-repo/scripts/post-code.sh:409 — The temp file created by PR_CREATE_STDERR=$(mktemp) is cleaned up in both the success and failure branches. However, if the script exits unexpectedly between mktemp and the cleanup rm -f calls (due to set -e or a signal), the temp file will leak. Negligible impact in an ephemeral GHA runner environment.

  • [diagnostic-completeness] internal/scaffold/fullsend-repo/scripts/post-review.sh:180 — The new error message provides useful context (exit code, PR number, repo). However, the fullsend post-review command's stderr is not captured, so the actual failure output is lost. Consider capturing stderr and including it in the error message, consistent with the pattern used for gh pr create in post-code.sh.

Previous run (2)

Review

Findings

Medium

  • [protected-path] internal/scaffold/fullsend-repo/scripts/ — All 6 changed files are under the protected scripts/ path. The PR links to issue Post-script failures are silent — add diagnostic error output #2393 and the description explains the rationale for modifying these governance/infrastructure files. Human approval is always required for protected-path changes, regardless of context.

Low

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:338${PUSH_OUTPUT} is interpolated unsanitized into a ::error:: GHA workflow command. PUSH_OUTPUT captures the combined stdout/stderr of git push, which could contain sequences like ::set-env:: if a server-side git hook or proxy injects them. The runner processes :: commands on both stdout and stderr.
    Remediation: Sanitize PUSH_OUTPUT by stripping :: sequences before interpolating, or use a plain ERROR: prefix instead.

  • [error-handling] internal/scaffold/fullsend-repo/scripts/post-code.sh:414 — The gh pr create stderr is redirected to a hardcoded path (2>/tmp/pr_create_stderr). The file already uses hardcoded /tmp paths for other downloads (gitleaks, lychee, uv), so this is consistent with existing patterns. However, using mktemp would be safer against parallel invocation and the temp file is never cleaned up on either success or failure.
    Remediation: Use mktemp to create the temp file and add cleanup in a trap.

  • [pattern-consistency] internal/scaffold/fullsend-repo/scripts/post-code.sh:416 — The conditional [[ -s /tmp/pr_create_stderr ]] uses [[ ]] test syntax while the rest of post-code.sh consistently uses [ ] for conditionals (20+ instances, zero prior [[ ]] uses).
    Remediation: Change [[ -s /tmp/pr_create_stderr ]] to [ -s /tmp/pr_create_stderr ] to match the file's convention.

Info

  • [diagnostic-completeness] internal/scaffold/fullsend-repo/scripts/post-review.sh:180 — The new error message provides useful context (exit code, PR number, repo). However, the fullsend post-review command's stderr is not captured, so the actual failure output is lost. Consider capturing stderr from the command and including it in the error message, consistent with the pattern used for gh pr create in post-code.sh.
Previous run (3)

Review

Findings

Medium

  • [logic-error] internal/scaffold/fullsend-repo/scripts/post-code.sh:415 — Adding 2>&1 to the gh pr create command merges stderr into stdout. On success, PR_CREATE_OUTPUT (assigned to PR_URL) may contain stderr warnings or progress messages mixed with the actual PR URL, corrupting the downstream echo "pr_url=${PR_URL}" GITHUB_OUTPUT entry. The original code correctly captured only stdout into PR_URL.
    Remediation: Capture stderr separately — use a temp file for stderr (2>"${PR_STDERR}") and only output it on failure, keeping the stdout-only capture for PR_URL. Alternatively, remove 2>&1 from the success path.

  • [protected-path] internal/scaffold/fullsend-repo/scripts/ — All 6 changed files are under the protected scripts/ path. The PR links to issue Post-script failures are silent — add diagnostic error output #2393 and the description explains the rationale for modifying these governance/infrastructure files. Human approval is always required for protected-path changes, regardless of context.

Low

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:338${PUSH_OUTPUT} is interpolated unsanitized into a ::error:: GHA workflow command. While exploitability is low (attacker would need server-side git hook control), defense-in-depth suggests either sanitizing the value or logging without the ::error:: prefix.

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:417${PR_CREATE_OUTPUT} is interpolated unsanitized into echo "::error::${PR_CREATE_OUTPUT}". The gh CLI does not typically echo raw user content in error messages, but sanitization or using a plain ERROR: prefix (as done elsewhere in this PR) would be more defensive.

  • [pattern-inconsistency] internal/scaffold/fullsend-repo/scripts/post-fix.sh:308 — The new error message uses ERROR: prefix while most other messages in the same file use ::error:: (GHA annotation format). Similarly in post-review.sh:180. These new errors will not render as red annotations in the GitHub Actions UI, unlike peer messages in the same files.

Previous run

Review

Findings

Medium

  • [protected-path] internal/scaffold/fullsend-repo/scripts/ — All 6 changed files are under the protected scripts/ path. The PR links to issue Post-script failures are silent — add diagnostic error output #2393 and the description explains the rationale for modifying these governance/infrastructure files. Human approval is always required for protected-path changes, regardless of context.

Low

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:338${PUSH_OUTPUT} is interpolated unsanitized into a ::error:: GHA workflow command. PUSH_OUTPUT captures the combined stdout/stderr of git push, which could contain sequences like ::set-env:: if a server-side git hook or proxy injects them. The >&2 redirect does not mitigate the injection vector — the GHA runner processes :: commands on both stdout and stderr.
    Remediation: Sanitize PUSH_OUTPUT by stripping :: sequences before interpolating, or use a plain ERROR: prefix instead of ::error::.

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:416 — The stderr output of gh pr create is written to the runner via cat "${PR_CREATE_STDERR}" >&2 without sanitization. The GHA runner scans both stdout and stderr for workflow commands. If the GitHub API error response echoes back user-controlled data containing :: sequences, those would be interpreted as workflow commands.
    Remediation: Pipe through sed to neutralize workflow commands before output: sed 's/::/ : : /g' "${PR_CREATE_STDERR}" >&2.

Info

  • [error-handling] internal/scaffold/fullsend-repo/scripts/post-code.sh:409 — The temp file created by PR_CREATE_STDERR=$(mktemp) is cleaned up in both the success and failure branches. However, if the script exits unexpectedly between mktemp and the cleanup rm -f calls (due to set -e or a signal), the temp file will leak. Negligible impact in an ephemeral GHA runner environment.

  • [diagnostic-completeness] internal/scaffold/fullsend-repo/scripts/post-review.sh:180 — The new error message provides useful context (exit code, PR number, repo). However, the fullsend post-review command's stderr is not captured, so the actual failure output is lost. Consider capturing stderr and including it in the error message, consistent with the pattern used for gh pr create in post-code.sh.

Previous run (2)

Review

Findings

Medium

  • [protected-path] internal/scaffold/fullsend-repo/scripts/ — All 6 changed files are under the protected scripts/ path. The PR links to issue Post-script failures are silent — add diagnostic error output #2393 and the description explains the rationale for modifying these governance/infrastructure files. Human approval is always required for protected-path changes, regardless of context.

Low

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:338${PUSH_OUTPUT} is interpolated unsanitized into a ::error:: GHA workflow command. PUSH_OUTPUT captures the combined stdout/stderr of git push, which could contain sequences like ::set-env:: if a server-side git hook or proxy injects them. The runner processes :: commands on both stdout and stderr.
    Remediation: Sanitize PUSH_OUTPUT by stripping :: sequences before interpolating, or use a plain ERROR: prefix instead.

  • [error-handling] internal/scaffold/fullsend-repo/scripts/post-code.sh:414 — The gh pr create stderr is redirected to a hardcoded path (2>/tmp/pr_create_stderr). The file already uses hardcoded /tmp paths for other downloads (gitleaks, lychee, uv), so this is consistent with existing patterns. However, using mktemp would be safer against parallel invocation and the temp file is never cleaned up on either success or failure.
    Remediation: Use mktemp to create the temp file and add cleanup in a trap.

  • [pattern-consistency] internal/scaffold/fullsend-repo/scripts/post-code.sh:416 — The conditional [[ -s /tmp/pr_create_stderr ]] uses [[ ]] test syntax while the rest of post-code.sh consistently uses [ ] for conditionals (20+ instances, zero prior [[ ]] uses).
    Remediation: Change [[ -s /tmp/pr_create_stderr ]] to [ -s /tmp/pr_create_stderr ] to match the file's convention.

Info

  • [diagnostic-completeness] internal/scaffold/fullsend-repo/scripts/post-review.sh:180 — The new error message provides useful context (exit code, PR number, repo). However, the fullsend post-review command's stderr is not captured, so the actual failure output is lost. Consider capturing stderr from the command and including it in the error message, consistent with the pattern used for gh pr create in post-code.sh.
Previous run (3)

Review

Findings

Medium

  • [logic-error] internal/scaffold/fullsend-repo/scripts/post-code.sh:415 — Adding 2>&1 to the gh pr create command merges stderr into stdout. On success, PR_CREATE_OUTPUT (assigned to PR_URL) may contain stderr warnings or progress messages mixed with the actual PR URL, corrupting the downstream echo "pr_url=${PR_URL}" GITHUB_OUTPUT entry. The original code correctly captured only stdout into PR_URL.
    Remediation: Capture stderr separately — use a temp file for stderr (2>"${PR_STDERR}") and only output it on failure, keeping the stdout-only capture for PR_URL. Alternatively, remove 2>&1 from the success path.

  • [protected-path] internal/scaffold/fullsend-repo/scripts/ — All 6 changed files are under the protected scripts/ path. The PR links to issue Post-script failures are silent — add diagnostic error output #2393 and the description explains the rationale for modifying these governance/infrastructure files. Human approval is always required for protected-path changes, regardless of context.

Low

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:338${PUSH_OUTPUT} is interpolated unsanitized into a ::error:: GHA workflow command. While exploitability is low (attacker would need server-side git hook control), defense-in-depth suggests either sanitizing the value or logging without the ::error:: prefix.

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:417${PR_CREATE_OUTPUT} is interpolated unsanitized into echo "::error::${PR_CREATE_OUTPUT}". The gh CLI does not typically echo raw user content in error messages, but sanitization or using a plain ERROR: prefix (as done elsewhere in this PR) would be more defensive.

  • [pattern-inconsistency] internal/scaffold/fullsend-repo/scripts/post-fix.sh:308 — The new error message uses ERROR: prefix while most other messages in the same file use ::error:: (GHA annotation format). Similarly in post-review.sh:180. These new errors will not render as red annotations in the GitHub Actions UI, unlike peer messages in the same files.

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

@ralphbean ralphbean 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.

/fs-fix A couple things inline.

echo "::error::Failed to create PR: see above for details"
--body "${PR_BODY}" 2>&1); then
echo "::error::Failed to create PR for ${REPO_FULL_NAME} (head: ${BRANCH}, base: ${TARGET_BRANCH})" >&2
[[ -n "${PR_CREATE_OUTPUT}" ]] && echo "::error::${PR_CREATE_OUTPUT}" >&2

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.

[critical] The 2>&1 here merges stderr into the capture, so on success PR_URL ends up with any progress messages gh prints alongside the actual URL. The original code only captured stdout, which was correct for the success path.

Could we redirect stderr to a temp file so stdout stays clean for PR_URL? Something like:

if ! PR_URL=$(gh pr create \
  --repo "${REPO_FULL_NAME}" \
  --head "${BRANCH}" \
  --base "${TARGET_BRANCH}" \
  --title "${PR_TITLE}" \
  --body "${PR_BODY}" 2>/tmp/pr_create_stderr); then
  echo "::error::Failed to create PR for ${REPO_FULL_NAME} (head: ${BRANCH}, base: ${TARGET_BRANCH})" >&2
  [[ -s /tmp/pr_create_stderr ]] && cat /tmp/pr_create_stderr >&2
  exit 1
fi

PR_FILES=$(gh pr view "${PR_NUMBER}" --repo "${REPO_FULL_NAME}" --json files --jq '.files[].path')
if [ -z "${PR_FILES}" ]; then
echo "::error::Failed to fetch PR files or PR has no changed files — refusing to approve"
echo "::error::Failed to fetch PR files or PR has no changed files — refusing to approve (GET repos/${REPO_FULL_NAME}/pulls/${PR_NUMBER}/files)" >&2

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.

[minor] The diagnostic says GET repos/.../pulls/.../files but the actual command is gh pr view --json files, which hits GraphQL. Might send someone down the wrong path — maybe (gh pr view --json files) instead?

@ralphbean

Copy link
Copy Markdown
Member

/fs-fix see inline comments above

@fullsend-ai-coder

fullsend-ai-coder Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 8:15 PM UTC · Completed 8:23 PM UTC
Commit: 4e21a60 · View workflow run →

- post-code.sh: redirect gh pr create stderr to temp file instead of
  merging into stdout with 2>&1, keeping PR_URL clean on success
- post-review.sh: fix diagnostic message to reference the actual command
  (gh pr view --json files) instead of the REST API endpoint

Addresses review feedback on #2395
@fullsend-ai-coder

Copy link
Copy Markdown
Contributor Author

🔧 Fix agent — iteration 1 (human-triggered)

Addressed both review findings: fixed stderr capture in post-code.sh PR creation and corrected diagnostic message in post-review.sh.

Fixed (2):

  1. 2>&1 merges stderr into PR_URL capture variable (internal/scaffold/fullsend-repo/scripts/post-code.sh): Redirected gh pr create stderr to /tmp/pr_create_stderr instead of merging into stdout with 2>&1. On success, PR_URL now captures only the URL. On failure, stderr is dumped from the temp file.
  2. diagnostic references REST API endpoint instead of actual gh CLI command (internal/scaffold/fullsend-repo/scripts/post-review.sh): Changed diagnostic from 'GET repos/.../pulls/.../files' to 'gh pr view --json files' to match the actual GraphQL-based command.

Tests: passed

Updated by fullsend fix agent

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:26 PM UTC · Completed 8:37 PM UTC
Commit: f01e246 · 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.

else
echo "::error::Push failed with unexpected error"
echo "::error::Push failed with unexpected error (git push origin ${BRANCH})" >&2
echo "::error::Push output: ${PUSH_OUTPUT}" >&2

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] injection

PUSH_OUTPUT is interpolated unsanitized into a ::error:: GHA workflow command. PUSH_OUTPUT captures stdout/stderr of git push, which could contain ::set-env:: sequences if a server-side git hook or proxy injects them.

Suggested fix: Sanitize PUSH_OUTPUT by stripping :: sequences before interpolating, or use a plain ERROR: prefix instead.

@@ -411,8 +412,9 @@ if ! PR_URL=$(gh pr create \
--head "${BRANCH}" \
--base "${TARGET_BRANCH}" \
--title "${PR_TITLE}" \

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] error-handling

gh pr create stderr is redirected to a hardcoded path (2>/tmp/pr_create_stderr). Using mktemp would be safer against parallel invocation, and the temp file is never cleaned up.

Suggested fix: Use mktemp to create the temp file and add cleanup in a trap.

--body "${PR_BODY}"); then
echo "::error::Failed to create PR: see above for details"
--body "${PR_BODY}" 2>/tmp/pr_create_stderr); then
echo "::error::Failed to create PR for ${REPO_FULL_NAME} (head: ${BRANCH}, base: ${TARGET_BRANCH})" >&2

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] pattern-consistency

The conditional [[ -s /tmp/pr_create_stderr ]] uses [[ ]] test syntax while the rest of post-code.sh consistently uses [ ] for conditionals (20+ instances, zero prior [[ ]] uses).

Suggested fix: Change [[ -s /tmp/pr_create_stderr ]] to [ -s /tmp/pr_create_stderr ] to match the file's convention.

# appear as a failure.
exit 0
elif [ "${POST_REVIEW_EXIT}" -ne 0 ]; then
echo "ERROR: fullsend post-review failed with exit code ${POST_REVIEW_EXIT} (PR #${PR_NUMBER} in ${REPO_FULL_NAME})" >&2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[info] diagnostic-completeness

The fullsend post-review command's stderr is not captured, so the actual failure output is lost. Consider capturing stderr and including it in the error message.

Suggested fix: Capture stderr from the fullsend post-review call and include it in the error message.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jun 17, 2026

@ralphbean ralphbean 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.

/fs-fix These two lines should use ::error:: instead of ERROR: — see inline.

python3 "${PROCESS_SCRIPT}" "${RESULT_FILE}" "${REPO_FULL_NAME}" "${PR_NUMBER}" || PROCESS_EXIT=$?
if [ "${PROCESS_EXIT}" -eq 1 ]; then
exit 1 # hard failure (bad input)
echo "ERROR: process-fix-result.py failed with exit code 1 (bad input) for PR #${PR_NUMBER} in ${REPO_FULL_NAME}" >&2

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.

[minor] This uses ERROR: where the rest of the file uses ::error::. The ::error:: prefix renders as a red annotation in the Actions UI, which is the whole point of this PR — making failures visible. Same thing on post-review.sh:180.

::error:: works fine with >&2, so we get both benefits.

@ralphbean

Copy link
Copy Markdown
Member

/fs-fix see inline comments above

@fullsend-ai-coder

fullsend-ai-coder Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 8:46 PM UTC · Completed 8:56 PM UTC
Commit: 4e21a60 · View workflow run →

- post-fix.sh, post-review.sh: change ERROR: prefix to ::error:: so
  failures render as red annotations in the Actions UI (per reviewer)
- post-code.sh: use mktemp instead of hardcoded /tmp/pr_create_stderr,
  clean up temp file on both success and failure paths, and switch from
  [[ ]] to [ ] for pattern consistency with the rest of the file

Addresses review feedback on #2395
@fullsend-ai-coder

Copy link
Copy Markdown
Contributor Author

🔧 Fix agent — iteration 2 (human-triggered)

Addressed 3 findings: changed ERROR: to ::error:: in post-fix.sh and post-review.sh per human reviewer, and improved post-code.sh to use mktemp with cleanup and consistent [ ] syntax per bot reviewer. Declined 1 low-severity bot finding (PUSH_OUTPUT sanitization) as out of scope.

Fixed (3):

  1. post-fix.sh uses ERROR: prefix instead of ::error:: (internal/scaffold/fullsend-repo/scripts/post-fix.sh): Changed ERROR: to ::error:: on line 308 so the failure renders as a red annotation in the Actions UI, matching the rest of the file
  2. post-review.sh uses ERROR: prefix instead of ::error:: (internal/scaffold/fullsend-repo/scripts/post-review.sh): Changed ERROR: to ::error:: on line 180 so the failure renders as a red annotation in the Actions UI
  3. post-code.sh uses hardcoded /tmp/pr_create_stderr and [[ ]] syntax (internal/scaffold/fullsend-repo/scripts/post-code.sh): Replaced hardcoded /tmp/pr_create_stderr with mktemp, added cleanup on both success and failure paths, and switched [[ -s ... ]] to [ -s ... ] for consistency with the rest of the file

Disagreed (1):

  1. Sanitize PUSH_OUTPUT to strip :: sequences before interpolating into workflow command: Low-severity bot finding. The PUSH_OUTPUT comes from git push stderr/stdout which is controlled by the git remote, not user input. GitHub Actions workflow command injection via git push output is a theoretical risk but would require a compromised git server. Out of scope for this PR's goal of adding diagnostic messages.

Tests: passed

Updated by fullsend fix agent

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:59 PM UTC · Completed 9:10 PM UTC
Commit: e972b2c · 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.

else
echo "::error::Push failed with unexpected error"
echo "::error::Push failed with unexpected error (git push origin ${BRANCH})" >&2
echo "::error::Push output: ${PUSH_OUTPUT}" >&2

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] injection

PUSH_OUTPUT is interpolated unsanitized into a ::error:: GHA workflow command. PUSH_OUTPUT captures the combined stdout/stderr of git push, which could contain sequences like ::set-env:: if a server-side git hook or proxy injects them. The >&2 redirect does not mitigate the injection vector.

Suggested fix: Sanitize PUSH_OUTPUT by stripping :: sequences before interpolating, or use a plain ERROR: prefix instead of ::error::.

--title "${PR_TITLE}" \
--body "${PR_BODY}"); then
echo "::error::Failed to create PR: see above for details"
--body "${PR_BODY}" 2>"${PR_CREATE_STDERR}"); then

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] injection

The stderr output of gh pr create is written to the runner via cat without sanitization. The GHA runner scans both stdout and stderr for workflow commands. If the GitHub API error response echoes back user-controlled data containing :: sequences, those would be interpreted as workflow commands.

Suggested fix: Pipe through sed to neutralize workflow commands before output.

@@ -406,15 +407,19 @@ Closes #${ISSUE_NUMBER}
- [x] Pre-commit hooks passed (authoritative run on runner)
- [x] Tests ran inside sandbox"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[info] error-handling

The temp file created by PR_CREATE_STDERR=$(mktemp) is cleaned up in both branches but could leak on unexpected exit. Negligible impact in an ephemeral GHA runner environment.

# appear as a failure.
exit 0
elif [ "${POST_REVIEW_EXIT}" -ne 0 ]; then
echo "::error::fullsend post-review failed with exit code ${POST_REVIEW_EXIT} (PR #${PR_NUMBER} in ${REPO_FULL_NAME})" >&2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[info] diagnostic-completeness

The new error message provides useful context (exit code, PR number, repo) but the fullsend post-review command stderr is not captured, so the actual failure output is lost.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jun 17, 2026

@ralphbean ralphbean 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.

LGTM.

@ralphbean
ralphbean added this pull request to the merge queue Jun 17, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 17, 2026
@ralphbean
ralphbean added this pull request to the merge queue Jun 17, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Jun 17, 2026
@ifireball
ifireball added this pull request to the merge queue Jun 18, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 18, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Jun 18, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure · Started 3:35 PM UTC · Completed 3:49 PM UTC
Commit: 36186df · View workflow run →

@ralphbean
ralphbean added this pull request to the merge queue Jun 18, 2026
Merged via the queue into main with commit a4a5008 Jun 18, 2026
10 checks passed
@ralphbean
ralphbean deleted the agent/2393-post-script-diagnostic-errors branch June 18, 2026 15:57
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jun 18, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 4:01 PM UTC · Completed 4:16 PM UTC
Commit: 36186df · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #2395 — add diagnostic stderr output to post-script failure paths

Timeline

  1. Issue Post-script failures are silent — add diagnostic error output #2393 created (Jun 17, 17:04) → triage auto-labeled ready-to-code (17:10)
  2. Code agent produced PR fix(#2393): add diagnostic stderr output to post-script failure paths #2395 (17:29) touching 6 post-scripts
  3. Review docs: Add agent-compatible code problem document #1 (17:45) — bot found medium [logic-error]: 2>&1 on gh pr create merges stderr into PR_URL capture variable
  4. Human review (18:02) — ralphbean independently caught the same 2>&1 bug + wrong API endpoint reference → CHANGES_REQUESTED + /fs-fix
  5. Fix docs: Add agent-compatible code problem document #1 (20:23) — addressed both human findings
  6. Review Add problem areas: Tekton pipeline review, migration path, multi-tenancy #2 (20:37) — bot found injection, mktemp, [[ ]] consistency issues
  7. Human review Add problem areas: Tekton pipeline review, migration path, multi-tenancy #2 (20:43) — ralphbean caught ERROR: vs ::error:: prefix inconsistency → /fs-fix
  8. Fix Add problem areas: Tekton pipeline review, migration path, multi-tenancy #2 (20:56) — fixed 3 items, reasonably declined 1 (PUSH_OUTPUT sanitization as out-of-scope)
  9. Review docs: Add codebase context problem document and trim CLAUDE.md #3 (21:10) — re-flagged the same declined injection findings + found one missed stderr redirect in post-retro.sh:161
  10. Human approval (21:18) — "LGTM" from ralphbean; 2 more approvals next day
  11. Merge (Jun 18, 15:57) after merging main into branch
  12. Review Use AI to help formalise intent after rapid local prototyping #4 — one run failed with GitHub 422 (invalid inline comment positions after merge commit), parallel run succeeded

What went well

  • Review bot caught the real bug (logic-error from 2>&1) before the human did, demonstrating good review quality
  • Fix agent performed well — addressed feedback accurately across both iterations, made sound judgment declining the low-severity injection finding as out-of-scope
  • Reasonable rework rate — 2 fix iterations for a 6-file change is acceptable, especially given the human reviewer caught style/convention issues the code agent couldn't have anticipated
  • End-to-end time was ~28 hours including overnight wait for additional approvals

Improvement areas (all already tracked)

All systemic issues observed in this workflow are covered by existing open issues:

No new proposals filed — all improvement opportunities are already tracked.

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

Labels

requires-manual-review Review requires human judgment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Post-script failures are silent — add diagnostic error output

3 participants