From bcfdaaf117dd87b30b04a8febd00150ea832ac85 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 22:16:00 +0000 Subject: [PATCH 1/4] Initial plan From bfbc187fd50bfbc5cd1fcef80bc7cd7a4929a2c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 22:32:37 +0000 Subject: [PATCH 2/4] fix: add standardized error codes for comment and merge handlers Agent-Logs-Url: https://github.com/github/gh-aw/sessions/11d46f42-2415-4a21-8543-72633d809c12 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/comment_memory.cjs | 2 +- actions/setup/js/comment_memory.test.cjs | 16 ++++++++++++++++ actions/setup/js/merge_pull_request.cjs | 8 ++++---- actions/setup/js/merge_pull_request.test.cjs | 2 +- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/actions/setup/js/comment_memory.cjs b/actions/setup/js/comment_memory.cjs index 9395720d0e4..addecbaec99 100644 --- a/actions/setup/js/comment_memory.cjs +++ b/actions/setup/js/comment_memory.cjs @@ -30,7 +30,7 @@ function sanitizeMemoryID(memoryID) { function buildManagedMemoryBody(rawBody, memoryID, options) { const { includeFooter, runUrl, workflowName, workflowSource, workflowSourceURL, historyUrl, triggeringIssueNumber, triggeringPRNumber } = options; if (!/^[a-zA-Z0-9_-]+$/.test(memoryID)) { - throw new Error("memory_id must contain only alphanumeric characters, hyphens, and underscores"); + throw new Error("E001: memory_id must contain only alphanumeric characters, hyphens, and underscores"); } const openingTag = `<${COMMENT_MEMORY_TAG} id="${memoryID}">`; const closingTag = ``; diff --git a/actions/setup/js/comment_memory.test.cjs b/actions/setup/js/comment_memory.test.cjs index 87f2f004a78..04f8dad855c 100644 --- a/actions/setup/js/comment_memory.test.cjs +++ b/actions/setup/js/comment_memory.test.cjs @@ -50,6 +50,22 @@ describe("comment_memory", () => { expect(body).toContain("Generated by"); }); + it("throws E001 for invalid memory ID in managed body builder", async () => { + const module = await import("./comment_memory.cjs"); + expect(() => + module.buildManagedMemoryBody("Persist me", "bad id", { + includeFooter: false, + runUrl: "https://example.com/run/3", + workflowName: "Workflow", + workflowSource: "", + workflowSourceURL: "", + historyUrl: undefined, + triggeringIssueNumber: undefined, + triggeringPRNumber: undefined, + }) + ).toThrow("E001:"); + }); + it("finds only managed comments with provenance marker", async () => { const module = await import("./comment_memory.cjs"); const github = { diff --git a/actions/setup/js/merge_pull_request.cjs b/actions/setup/js/merge_pull_request.cjs index 85cb9f4fdc2..27de5f68f02 100644 --- a/actions/setup/js/merge_pull_request.cjs +++ b/actions/setup/js/merge_pull_request.cjs @@ -41,7 +41,7 @@ async function getPullRequestWithMergeability(githubClient, owner, repo, pullNum pull_number: pullNumber, }); if (data && data.mergeable === null) { - throw new Error(MERGEABILITY_PENDING_ERROR); + throw new Error(`E099: ${MERGEABILITY_PENDING_ERROR}`); } return data; }, @@ -50,7 +50,7 @@ async function getPullRequestWithMergeability(githubClient, owner, repo, pullNum initialDelayMs: 1000, shouldRetry: error => { const msg = getErrorMessage(error).toLowerCase(); - return isTransientError(error) || msg === MERGEABILITY_PENDING_ERROR; + return isTransientError(error) || msg === MERGEABILITY_PENDING_ERROR || msg === `e099: ${MERGEABILITY_PENDING_ERROR}`; }, }, `fetch pull request #${pullNumber}` @@ -66,7 +66,7 @@ async function getPullRequestWithMergeability(githubClient, owner, repo, pullNum return fallback.data; } } catch (fallbackError) { - throw new Error(`Failed to fetch pull request #${pullNumber} after retry and fallback attempts. Retry error: ${getErrorMessage(error)}. Fallback error: ${getErrorMessage(fallbackError)}`); + throw new Error(`E099: Failed to fetch pull request #${pullNumber} after retry and fallback attempts. Retry error: ${getErrorMessage(error)}. Fallback error: ${getErrorMessage(fallbackError)}`); } throw error; }); @@ -141,7 +141,7 @@ async function getReviewSummary(githubClient, owner, repo, pullNumber) { async function getBranchPolicy(githubClient, owner, repo, baseBranch) { const baseBranchValidation = sanitizeBranchName(baseBranch, "target base"); if (!baseBranchValidation.valid || !baseBranchValidation.value) { - throw new Error(`Invalid target base branch for policy evaluation: ${baseBranchValidation.error} (original: ${JSON.stringify(baseBranch)}, normalized: ${JSON.stringify(baseBranchValidation.normalized || "")})`); + throw new Error(`E001: Invalid target base branch for policy evaluation: ${baseBranchValidation.error} (original: ${JSON.stringify(baseBranch)}, normalized: ${JSON.stringify(baseBranchValidation.normalized || "")})`); } const sanitizedBaseBranch = baseBranchValidation.value; diff --git a/actions/setup/js/merge_pull_request.test.cjs b/actions/setup/js/merge_pull_request.test.cjs index 611f742da8e..600e0e8464e 100644 --- a/actions/setup/js/merge_pull_request.test.cjs +++ b/actions/setup/js/merge_pull_request.test.cjs @@ -96,7 +96,7 @@ describe("merge_pull_request branch validation", () => { }, }; - await expect(__testables.getBranchPolicy(githubClient, "github", "gh-aw", "main;rm -rf /")).rejects.toThrow("Invalid target base branch for policy evaluation"); + await expect(__testables.getBranchPolicy(githubClient, "github", "gh-aw", "main;rm -rf /")).rejects.toThrow("E001: Invalid target base branch for policy evaluation"); expect(githubClient.rest.repos.getBranch).not.toHaveBeenCalled(); }); From a495b4a2d980322c10ca96bb00cb26c9f28caf60 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 22:35:51 +0000 Subject: [PATCH 3/4] fix: align mergeability retry with coded error message Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/merge_pull_request.cjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/merge_pull_request.cjs b/actions/setup/js/merge_pull_request.cjs index 27de5f68f02..6e93aef93e8 100644 --- a/actions/setup/js/merge_pull_request.cjs +++ b/actions/setup/js/merge_pull_request.cjs @@ -11,6 +11,7 @@ const { withRetry, isTransientError } = require("./error_recovery.cjs"); const { normalizeBranchName } = require("./normalize_branch_name.cjs"); const { resolveNumberFromTemporaryId } = require("./temporary_id.cjs"); const MERGEABILITY_PENDING_ERROR = "pull request mergeability is still being computed"; +const MERGEABILITY_PENDING_ERROR_CODED = `E099: ${MERGEABILITY_PENDING_ERROR}`; /** * @typedef {import('./types/handler-factory').HandlerFactoryFunction} HandlerFactoryFunction @@ -41,7 +42,7 @@ async function getPullRequestWithMergeability(githubClient, owner, repo, pullNum pull_number: pullNumber, }); if (data && data.mergeable === null) { - throw new Error(`E099: ${MERGEABILITY_PENDING_ERROR}`); + throw new Error(MERGEABILITY_PENDING_ERROR_CODED); } return data; }, @@ -50,7 +51,7 @@ async function getPullRequestWithMergeability(githubClient, owner, repo, pullNum initialDelayMs: 1000, shouldRetry: error => { const msg = getErrorMessage(error).toLowerCase(); - return isTransientError(error) || msg === MERGEABILITY_PENDING_ERROR || msg === `e099: ${MERGEABILITY_PENDING_ERROR}`; + return isTransientError(error) || msg === MERGEABILITY_PENDING_ERROR_CODED.toLowerCase(); }, }, `fetch pull request #${pullNumber}` From 0da167991ef0f59a9bd026914f7ee797f2107f29 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 23:12:18 +0000 Subject: [PATCH 4/4] refactor: use shared constants for USE-001 error codes Agent-Logs-Url: https://github.com/github/gh-aw/sessions/676d864f-9839-4f2d-8ed0-07e0dd1c52b5 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/comment_memory.cjs | 3 ++- actions/setup/js/error_codes.cjs | 8 ++++++++ actions/setup/js/merge_pull_request.cjs | 7 ++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/actions/setup/js/comment_memory.cjs b/actions/setup/js/comment_memory.cjs index addecbaec99..f62d2a16ee5 100644 --- a/actions/setup/js/comment_memory.cjs +++ b/actions/setup/js/comment_memory.cjs @@ -4,6 +4,7 @@ require("./shim.cjs"); const { sanitizeContent } = require("./sanitize_content.cjs"); const { getErrorMessage } = require("./error_helpers.cjs"); +const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs"); const { resolveTarget, isStagedMode } = require("./safe_output_helpers.cjs"); const { resolveTargetRepoConfig, resolveAndValidateRepo } = require("./repo_helpers.cjs"); const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs"); @@ -30,7 +31,7 @@ function sanitizeMemoryID(memoryID) { function buildManagedMemoryBody(rawBody, memoryID, options) { const { includeFooter, runUrl, workflowName, workflowSource, workflowSourceURL, historyUrl, triggeringIssueNumber, triggeringPRNumber } = options; if (!/^[a-zA-Z0-9_-]+$/.test(memoryID)) { - throw new Error("E001: memory_id must contain only alphanumeric characters, hyphens, and underscores"); + throw new Error(`${SAFE_OUTPUT_E001}: memory_id must contain only alphanumeric characters, hyphens, and underscores`); } const openingTag = `<${COMMENT_MEMORY_TAG} id="${memoryID}">`; const closingTag = ``; diff --git a/actions/setup/js/error_codes.cjs b/actions/setup/js/error_codes.cjs index 07ac2798e93..a7260c71f4d 100644 --- a/actions/setup/js/error_codes.cjs +++ b/actions/setup/js/error_codes.cjs @@ -42,6 +42,12 @@ const ERR_PARSE = "ERR_PARSE"; /** @type {string} System and I/O errors */ const ERR_SYSTEM = "ERR_SYSTEM"; +/** @type {string} Safe output validation/input errors (legacy numeric taxonomy) */ +const SAFE_OUTPUT_E001 = "E001"; + +/** @type {string} Safe output operation/runtime failures (legacy numeric taxonomy) */ +const SAFE_OUTPUT_E099 = "E099"; + module.exports = { ERR_VALIDATION, ERR_PERMISSION, @@ -50,4 +56,6 @@ module.exports = { ERR_NOT_FOUND, ERR_PARSE, ERR_SYSTEM, + SAFE_OUTPUT_E001, + SAFE_OUTPUT_E099, }; diff --git a/actions/setup/js/merge_pull_request.cjs b/actions/setup/js/merge_pull_request.cjs index 6e93aef93e8..a60bc7f8666 100644 --- a/actions/setup/js/merge_pull_request.cjs +++ b/actions/setup/js/merge_pull_request.cjs @@ -10,8 +10,9 @@ const { selectLatestRelevantChecks } = require("./check_runs_helpers.cjs"); const { withRetry, isTransientError } = require("./error_recovery.cjs"); const { normalizeBranchName } = require("./normalize_branch_name.cjs"); const { resolveNumberFromTemporaryId } = require("./temporary_id.cjs"); +const { SAFE_OUTPUT_E001, SAFE_OUTPUT_E099 } = require("./error_codes.cjs"); const MERGEABILITY_PENDING_ERROR = "pull request mergeability is still being computed"; -const MERGEABILITY_PENDING_ERROR_CODED = `E099: ${MERGEABILITY_PENDING_ERROR}`; +const MERGEABILITY_PENDING_ERROR_CODED = `${SAFE_OUTPUT_E099}: ${MERGEABILITY_PENDING_ERROR}`; /** * @typedef {import('./types/handler-factory').HandlerFactoryFunction} HandlerFactoryFunction @@ -67,7 +68,7 @@ async function getPullRequestWithMergeability(githubClient, owner, repo, pullNum return fallback.data; } } catch (fallbackError) { - throw new Error(`E099: Failed to fetch pull request #${pullNumber} after retry and fallback attempts. Retry error: ${getErrorMessage(error)}. Fallback error: ${getErrorMessage(fallbackError)}`); + throw new Error(`${SAFE_OUTPUT_E099}: Failed to fetch pull request #${pullNumber} after retry and fallback attempts. Retry error: ${getErrorMessage(error)}. Fallback error: ${getErrorMessage(fallbackError)}`); } throw error; }); @@ -142,7 +143,7 @@ async function getReviewSummary(githubClient, owner, repo, pullNumber) { async function getBranchPolicy(githubClient, owner, repo, baseBranch) { const baseBranchValidation = sanitizeBranchName(baseBranch, "target base"); if (!baseBranchValidation.valid || !baseBranchValidation.value) { - throw new Error(`E001: Invalid target base branch for policy evaluation: ${baseBranchValidation.error} (original: ${JSON.stringify(baseBranch)}, normalized: ${JSON.stringify(baseBranchValidation.normalized || "")})`); + throw new Error(`${SAFE_OUTPUT_E001}: Invalid target base branch for policy evaluation: ${baseBranchValidation.error} (original: ${JSON.stringify(baseBranch)}, normalized: ${JSON.stringify(baseBranchValidation.normalized || "")})`); } const sanitizedBaseBranch = baseBranchValidation.value;