Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/scripts/__tests__/agents-pr-meta-keepalive.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ test('keepalive detection blocks no-automation source context', async () => {
'## Workflow Source',
'',
'Started from:',
'- [x] Local Codex/user request',
'- [x] Do not automate',
'',
'Automation intent:',
'- [x] Human-only unless checks fail',
Expand Down Expand Up @@ -550,7 +550,7 @@ test('keepalive detection blocks no-automation source context', async () => {

assert.equal(outputs.dispatch, 'false');
assert.equal(outputs.reason, 'no-automation-source-context');
assert.equal(outputs.source_type, 'local_request');
assert.equal(outputs.source_type, 'manual_remote');
});

test('keepalive detection accepts sync campaign source context without linked issue', async () => {
Expand Down
60 changes: 60 additions & 0 deletions .github/scripts/__tests__/agents-pr-meta-update-body.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const {
buildSourceContextRepairCommentBody,
buildSourceContextResolvedCommentBody,
resolveExplicitNonIssueWorkflowSourceContext,
hasExplicitIssueSyncReference,
resolveNonIssueWorkflowSourceContextForBodySync,
resolveSourceContextRepairComment,
resolveAgentType,
Expand Down Expand Up @@ -501,6 +502,65 @@ test('resolveNonIssueWorkflowSourceContextForBodySync preserves issue-sourced sy
assert.equal(context, null);
});

test('hasExplicitIssueSyncReference ignores heuristic issue-number sources', () => {
assert.equal(
hasExplicitIssueSyncReference({
title: 'Review follow-up',
body: 'Review follow-up from PR #123',
head: { ref: 'codex/issue-123' },
}),
false,
);
assert.equal(hasExplicitIssueSyncReference({ body: 'Closes #123' }), true);
assert.equal(hasExplicitIssueSyncReference({ body: '<!-- meta:issue:123 -->' }), true);
});

test('resolveNonIssueWorkflowSourceContextForBodySync honors explicit non-issue markers over heuristics', () => {
const branchHeuristicContext = resolveNonIssueWorkflowSourceContextForBodySync(
{
body: [
'<!-- workflow-source:local_request -->',
'<!-- workflow-source-ref:codex-thread-2026-04-26 -->',
].join('\n'),
head: { ref: 'codex/issue-123' },
title: 'Follow-up',
},
123,
);

assert.equal(branchHeuristicContext.sourceType, 'local_request');
assert.equal(branchHeuristicContext.sourceRef, 'codex-thread-2026-04-26');

const prReferenceContext = resolveNonIssueWorkflowSourceContextForBodySync(
{
body: [
'Review follow-up from PR #123',
'<!-- workflow-source:review_followup -->',
'<!-- workflow-source-ref:PR #123 -->',
].join('\n'),
},
123,
);

assert.equal(prReferenceContext.sourceType, 'review_followup');
assert.equal(prReferenceContext.sourceRef, 'PR #123');
});

test('resolveNonIssueWorkflowSourceContextForBodySync yields to explicit issue references', () => {
const context = resolveNonIssueWorkflowSourceContextForBodySync(
{
body: [
'Closes #123',
'<!-- workflow-source:local_request -->',
'<!-- workflow-source-ref:codex-thread-2026-04-26 -->',
].join('\n'),
},
123,
);

assert.equal(context, null);
});

test('resolveSourceContextRepairComment updates an existing warning once', async () => {
const calls = { update: 0, body: '' };
const github = {
Expand Down
5 changes: 4 additions & 1 deletion .github/scripts/__tests__/source-context.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ Automation intent:
`;

assert.equal(sourceTypeFromCheckedTemplate(body), SOURCE_TYPES.LOCAL_REQUEST);
const context = resolvePrSourceContext({ body });
assert.equal(context.sourceType, SOURCE_TYPES.LOCAL_REQUEST);
assert.equal(context.noAutomation, false);
});

test('sourceTypeFromCheckedTemplate treats human-only PRs as manual remote work', () => {
Expand All @@ -198,7 +201,7 @@ test('resolvePrSourceContext marks no-automation sources without changing source
## Workflow Source

Started from:
- [x] Direct PR / remote GitHub work
- [x] Do not automate

Automation intent:
- [x] Human-only unless checks fail
Expand Down
20 changes: 19 additions & 1 deletion .github/scripts/agents_pr_meta_update_body.js
Original file line number Diff line number Diff line change
Expand Up @@ -1023,8 +1023,25 @@ function resolveExplicitNonIssueWorkflowSourceContext(pr = {}) {
};
}

function hasExplicitIssueSyncReference(pr = {}) {
const body = String(pr.body || '');
if (/<!--\s*meta:issue:[0-9]+\s*-->/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);
}

function resolveNonIssueWorkflowSourceContextForBodySync(pr = {}, issueNumber = null) {
return issueNumber ? null : resolveExplicitNonIssueWorkflowSourceContext(pr);
const explicitNonIssueSourceContext = resolveExplicitNonIssueWorkflowSourceContext(pr);
if (!explicitNonIssueSourceContext) {
return null;
}
if (issueNumber && hasExplicitIssueSyncReference(pr)) {
return null;
}
return explicitNonIssueSourceContext;
}

async function resolveSourceContextRepairComment({
Expand Down Expand Up @@ -1652,6 +1669,7 @@ module.exports = {
buildSourceContextRepairCommentBody,
buildSourceContextResolvedCommentBody,
resolveExplicitNonIssueWorkflowSourceContext,
hasExplicitIssueSyncReference,
resolveNonIssueWorkflowSourceContextForBodySync,
resolveSourceContextRepairComment,
isCampaignIssue,
Expand Down
4 changes: 2 additions & 2 deletions .github/scripts/source_context.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const CHECKBOX_SOURCE_PATTERNS = Object.freeze([
[SOURCE_TYPES.DEPENDABOT, /\bdependabot\b|\bdependency\s+update\b/i],
]);

const NO_AUTOMATION_CHECKBOX_PATTERN = /\bdo\s+not\s+automate\b|\bhuman[- ]only\b/i;
const NO_AUTOMATION_CHECKBOX_PATTERN = /\bdo\s+not\s+automate\b/i;

function cleanString(value) {
return String(value || '').trim();
Expand Down Expand Up @@ -155,7 +155,7 @@ function hasCheckedNoAutomationTemplate(body) {
if (!sectionLines.length) {
return false;
}
return checkedLabels(sectionLines).some((label) => NO_AUTOMATION_CHECKBOX_PATTERN.test(label));
return checkedLabels(startedFromLines(sectionLines)).some((label) => NO_AUTOMATION_CHECKBOX_PATTERN.test(label));
}

function hasExplicitIssueReferencePrefix(value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1023,8 +1023,25 @@ function resolveExplicitNonIssueWorkflowSourceContext(pr = {}) {
};
}

function hasExplicitIssueSyncReference(pr = {}) {
const body = String(pr.body || '');
if (/<!--\s*meta:issue:[0-9]+\s*-->/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);
}

function resolveNonIssueWorkflowSourceContextForBodySync(pr = {}, issueNumber = null) {
return issueNumber ? null : resolveExplicitNonIssueWorkflowSourceContext(pr);
const explicitNonIssueSourceContext = resolveExplicitNonIssueWorkflowSourceContext(pr);
if (!explicitNonIssueSourceContext) {
return null;
}
if (issueNumber && hasExplicitIssueSyncReference(pr)) {
return null;
}
return explicitNonIssueSourceContext;
}

async function resolveSourceContextRepairComment({
Expand Down Expand Up @@ -1652,6 +1669,7 @@ module.exports = {
buildSourceContextRepairCommentBody,
buildSourceContextResolvedCommentBody,
resolveExplicitNonIssueWorkflowSourceContext,
hasExplicitIssueSyncReference,
resolveNonIssueWorkflowSourceContextForBodySync,
resolveSourceContextRepairComment,
isCampaignIssue,
Expand Down
4 changes: 2 additions & 2 deletions templates/consumer-repo/.github/scripts/source_context.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const CHECKBOX_SOURCE_PATTERNS = Object.freeze([
[SOURCE_TYPES.DEPENDABOT, /\bdependabot\b|\bdependency\s+update\b/i],
]);

const NO_AUTOMATION_CHECKBOX_PATTERN = /\bdo\s+not\s+automate\b|\bhuman[- ]only\b/i;
const NO_AUTOMATION_CHECKBOX_PATTERN = /\bdo\s+not\s+automate\b/i;

function cleanString(value) {
return String(value || '').trim();
Expand Down Expand Up @@ -155,7 +155,7 @@ function hasCheckedNoAutomationTemplate(body) {
if (!sectionLines.length) {
return false;
}
return checkedLabels(sectionLines).some((label) => NO_AUTOMATION_CHECKBOX_PATTERN.test(label));
return checkedLabels(startedFromLines(sectionLines)).some((label) => NO_AUTOMATION_CHECKBOX_PATTERN.test(label));
}

function hasExplicitIssueReferencePrefix(value) {
Expand Down
Loading