From 05166d0783beabc6cfb87bfd4c18bb42e2db561a Mon Sep 17 00:00:00 2001 From: Tim Stranske Date: Sun, 26 Apr 2026 22:43:10 -0500 Subject: [PATCH 1/2] Fix issue-backed source repair handling --- .../agents-pr-meta-update-body.test.js | 40 +++++++++++++++++-- .github/scripts/agents_pr_meta_update_body.js | 16 ++++---- .../scripts/agents_pr_meta_update_body.js | 16 ++++---- 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/.github/scripts/__tests__/agents-pr-meta-update-body.test.js b/.github/scripts/__tests__/agents-pr-meta-update-body.test.js index be674acb6..41c19831d 100644 --- a/.github/scripts/__tests__/agents-pr-meta-update-body.test.js +++ b/.github/scripts/__tests__/agents-pr-meta-update-body.test.js @@ -446,6 +446,20 @@ test('buildSourceContextResolvedCommentBody explains sync-campaign source contex assert.ok(result.includes('No linked GitHub issue is required')); }); +test('buildSourceContextResolvedCommentBody explains issue-backed source context', () => { + const result = buildSourceContextResolvedCommentBody(123, { + sourceType: 'github_issue', + issueNumber: 456, + sourceRef: '#456', + requiresIssue: true, + }); + + assert.ok(result.includes('origin=github_issue')); + assert.ok(result.includes('ref=#456')); + assert.ok(result.includes('A linked GitHub issue is present')); + assert.ok(!result.includes('No linked GitHub issue is required')); +}); + test('resolveExplicitNonIssueWorkflowSourceContext preserves explicit automation source despite stale issue preamble', () => { const context = resolveExplicitNonIssueWorkflowSourceContext({ body: [ @@ -487,11 +501,11 @@ test('resolveExplicitNonIssueWorkflowSourceContext ignores source issue markers' assert.equal(context, null); }); -test('resolveNonIssueWorkflowSourceContextForBodySync preserves issue-sourced sync precedence', () => { +test('resolveNonIssueWorkflowSourceContextForBodySync preserves explicit issue-sourced sync precedence', () => { const context = resolveNonIssueWorkflowSourceContextForBodySync( { body: [ - '', + 'Closes #123', '', '', ].join('\n'), @@ -502,6 +516,22 @@ test('resolveNonIssueWorkflowSourceContextForBodySync preserves issue-sourced sy assert.equal(context, null); }); +test('resolveNonIssueWorkflowSourceContextForBodySync lets explicit non-issue markers replace generated issue metadata', () => { + const context = resolveNonIssueWorkflowSourceContextForBodySync( + { + body: [ + '', + '', + '', + ].join('\n'), + }, + 123, + ); + + assert.equal(context.sourceType, 'local_request'); + assert.equal(context.sourceRef, 'codex-thread-2026-04-26'); +}); + test('hasExplicitIssueSyncReference ignores heuristic issue-number sources', () => { assert.equal( hasExplicitIssueSyncReference({ @@ -512,7 +542,11 @@ test('hasExplicitIssueSyncReference ignores heuristic issue-number sources', () false, ); assert.equal(hasExplicitIssueSyncReference({ body: 'Closes #123' }), true); - assert.equal(hasExplicitIssueSyncReference({ body: '' }), true); + assert.equal(hasExplicitIssueSyncReference({ body: 'Related to #123' }), true); + assert.equal(hasExplicitIssueSyncReference({ body: 'source issue #123' }), true); + assert.equal(hasExplicitIssueSyncReference({ body: 'This issue only mentions review follow-up PR #123' }), false); + assert.equal(hasExplicitIssueSyncReference({ body: 'refs in this paragraph mention PR #123' }), false); + assert.equal(hasExplicitIssueSyncReference({ body: '' }), false); }); test('resolveNonIssueWorkflowSourceContextForBodySync honors explicit non-issue markers over heuristics', () => { diff --git a/.github/scripts/agents_pr_meta_update_body.js b/.github/scripts/agents_pr_meta_update_body.js index 9c0969b1c..eeb1a61dc 100644 --- a/.github/scripts/agents_pr_meta_update_body.js +++ b/.github/scripts/agents_pr_meta_update_body.js @@ -980,13 +980,16 @@ async function createIssueCommentWithRetry({ github, owner, repo, issueNumber, b } function buildSourceContextResolvedCommentBody(prNumber, sourceContext) { + const isIssueBacked = sourceContext?.requiresIssue || sourceContext?.issueNumber || sourceContext?.sourceType === SOURCE_TYPES.GITHUB_ISSUE; return [ '', '### Workflow source detected', '', `PR #${prNumber} now has valid workflow source context (${formatSourceContextForLog(sourceContext)}).`, '', - 'No linked GitHub issue is required for this PR.', + isIssueBacked + ? 'A linked GitHub issue is present for this PR.' + : 'No linked GitHub issue is required for this PR.', ].join('\n'); } @@ -1024,13 +1027,10 @@ function resolveExplicitNonIssueWorkflowSourceContext(pr = {}) { } function hasExplicitIssueSyncReference(pr = {}) { - const body = String(pr.body || ''); - if (//i.test(body)) { - return true; - } - - const text = `${pr.title || ''}\n${body}`; - return /\b(?:close[sd]?|closing|fix(?:e[sd])?|fixing|resolve[sd]?|resolving|address(?:e[sd])?|addressing|relate[sd]?\s+to|refs?|references?|issue|source\s+issue|github\s+issue)\s*[:#-]?\s*#[0-9]+\b/i.test(text); + const text = `${pr.title || ''}\n${pr.body || ''}`; + const explicitClosingReference = /\b(?:close[sd]?|closing|fix(?:e[sd])?|fixing|resolve[sd]?|resolving|address(?:e[sd])?|addressing)\s*[:#-]?\s*#[0-9]+\b/i; + const explicitIssueReference = /\b(?:relate[sd]?\s+to|references?|source\s+issue|github\s+issue|linked\s+issue)\s*[:#-]?\s*#[0-9]+\b/i; + return explicitClosingReference.test(text) || explicitIssueReference.test(text); } function resolveNonIssueWorkflowSourceContextForBodySync(pr = {}, issueNumber = null) { diff --git a/templates/consumer-repo/.github/scripts/agents_pr_meta_update_body.js b/templates/consumer-repo/.github/scripts/agents_pr_meta_update_body.js index 9c0969b1c..eeb1a61dc 100644 --- a/templates/consumer-repo/.github/scripts/agents_pr_meta_update_body.js +++ b/templates/consumer-repo/.github/scripts/agents_pr_meta_update_body.js @@ -980,13 +980,16 @@ async function createIssueCommentWithRetry({ github, owner, repo, issueNumber, b } function buildSourceContextResolvedCommentBody(prNumber, sourceContext) { + const isIssueBacked = sourceContext?.requiresIssue || sourceContext?.issueNumber || sourceContext?.sourceType === SOURCE_TYPES.GITHUB_ISSUE; return [ '', '### Workflow source detected', '', `PR #${prNumber} now has valid workflow source context (${formatSourceContextForLog(sourceContext)}).`, '', - 'No linked GitHub issue is required for this PR.', + isIssueBacked + ? 'A linked GitHub issue is present for this PR.' + : 'No linked GitHub issue is required for this PR.', ].join('\n'); } @@ -1024,13 +1027,10 @@ function resolveExplicitNonIssueWorkflowSourceContext(pr = {}) { } function hasExplicitIssueSyncReference(pr = {}) { - const body = String(pr.body || ''); - if (//i.test(body)) { - return true; - } - - const text = `${pr.title || ''}\n${body}`; - return /\b(?:close[sd]?|closing|fix(?:e[sd])?|fixing|resolve[sd]?|resolving|address(?:e[sd])?|addressing|relate[sd]?\s+to|refs?|references?|issue|source\s+issue|github\s+issue)\s*[:#-]?\s*#[0-9]+\b/i.test(text); + const text = `${pr.title || ''}\n${pr.body || ''}`; + const explicitClosingReference = /\b(?:close[sd]?|closing|fix(?:e[sd])?|fixing|resolve[sd]?|resolving|address(?:e[sd])?|addressing)\s*[:#-]?\s*#[0-9]+\b/i; + const explicitIssueReference = /\b(?:relate[sd]?\s+to|references?|source\s+issue|github\s+issue|linked\s+issue)\s*[:#-]?\s*#[0-9]+\b/i; + return explicitClosingReference.test(text) || explicitIssueReference.test(text); } function resolveNonIssueWorkflowSourceContextForBodySync(pr = {}, issueNumber = null) { From 0a7b60d9df9d0f7d7448239588978b8307c9dde1 Mon Sep 17 00:00:00 2001 From: Tim Stranske Date: Sun, 26 Apr 2026 22:49:37 -0500 Subject: [PATCH 2/2] Handle issue wording in source references --- .github/scripts/__tests__/agents-pr-meta-update-body.test.js | 2 ++ .github/scripts/agents_pr_meta_update_body.js | 2 +- .../consumer-repo/.github/scripts/agents_pr_meta_update_body.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/scripts/__tests__/agents-pr-meta-update-body.test.js b/.github/scripts/__tests__/agents-pr-meta-update-body.test.js index 41c19831d..1fca90926 100644 --- a/.github/scripts/__tests__/agents-pr-meta-update-body.test.js +++ b/.github/scripts/__tests__/agents-pr-meta-update-body.test.js @@ -543,6 +543,8 @@ test('hasExplicitIssueSyncReference ignores heuristic issue-number sources', () ); assert.equal(hasExplicitIssueSyncReference({ body: 'Closes #123' }), true); assert.equal(hasExplicitIssueSyncReference({ body: 'Related to #123' }), true); + assert.equal(hasExplicitIssueSyncReference({ body: 'Related to issue #123' }), true); + assert.equal(hasExplicitIssueSyncReference({ body: 'References issue #123' }), true); assert.equal(hasExplicitIssueSyncReference({ body: 'source issue #123' }), true); assert.equal(hasExplicitIssueSyncReference({ body: 'This issue only mentions review follow-up PR #123' }), false); assert.equal(hasExplicitIssueSyncReference({ body: 'refs in this paragraph mention PR #123' }), false); diff --git a/.github/scripts/agents_pr_meta_update_body.js b/.github/scripts/agents_pr_meta_update_body.js index eeb1a61dc..a65589cb0 100644 --- a/.github/scripts/agents_pr_meta_update_body.js +++ b/.github/scripts/agents_pr_meta_update_body.js @@ -1029,7 +1029,7 @@ function resolveExplicitNonIssueWorkflowSourceContext(pr = {}) { function hasExplicitIssueSyncReference(pr = {}) { const text = `${pr.title || ''}\n${pr.body || ''}`; const explicitClosingReference = /\b(?:close[sd]?|closing|fix(?:e[sd])?|fixing|resolve[sd]?|resolving|address(?:e[sd])?|addressing)\s*[:#-]?\s*#[0-9]+\b/i; - const explicitIssueReference = /\b(?:relate[sd]?\s+to|references?|source\s+issue|github\s+issue|linked\s+issue)\s*[:#-]?\s*#[0-9]+\b/i; + const explicitIssueReference = /\b(?:(?:relate[sd]?\s+to|references?)\s+(?:issue\s+)?|(?:source|github|linked)\s+issue\s*)[:#-]?\s*#[0-9]+\b/i; return explicitClosingReference.test(text) || explicitIssueReference.test(text); } diff --git a/templates/consumer-repo/.github/scripts/agents_pr_meta_update_body.js b/templates/consumer-repo/.github/scripts/agents_pr_meta_update_body.js index eeb1a61dc..a65589cb0 100644 --- a/templates/consumer-repo/.github/scripts/agents_pr_meta_update_body.js +++ b/templates/consumer-repo/.github/scripts/agents_pr_meta_update_body.js @@ -1029,7 +1029,7 @@ function resolveExplicitNonIssueWorkflowSourceContext(pr = {}) { function hasExplicitIssueSyncReference(pr = {}) { const text = `${pr.title || ''}\n${pr.body || ''}`; const explicitClosingReference = /\b(?:close[sd]?|closing|fix(?:e[sd])?|fixing|resolve[sd]?|resolving|address(?:e[sd])?|addressing)\s*[:#-]?\s*#[0-9]+\b/i; - const explicitIssueReference = /\b(?:relate[sd]?\s+to|references?|source\s+issue|github\s+issue|linked\s+issue)\s*[:#-]?\s*#[0-9]+\b/i; + const explicitIssueReference = /\b(?:(?:relate[sd]?\s+to|references?)\s+(?:issue\s+)?|(?:source|github|linked)\s+issue\s*)[:#-]?\s*#[0-9]+\b/i; return explicitClosingReference.test(text) || explicitIssueReference.test(text); }