Skip to content

chore: sync workflow templates - #132

Merged
stranske merged 2 commits into
mainfrom
sync/workflows-93ee083443e7
Jan 8, 2026
Merged

chore: sync workflow templates#132
stranske merged 2 commits into
mainfrom
sync/workflows-93ee083443e7

Conversation

@stranske

@stranske stranske commented Jan 8, 2026

Copy link
Copy Markdown
Owner

Sync Summary

Files Updated

  • agents-verify-to-issue.yml: Verify to issue - creates follow-up issues from verification feedback (Phase 4E)
  • issue_formatter.py: Issue formatter - converts raw text to AGENT_ISSUE_TEMPLATE format

Files Skipped

  • pr-00-gate.yml: File exists and sync_mode is create_only
  • ci.yml: File exists and sync_mode is create_only
  • dependabot.yml: File exists and sync_mode is create_only

Review Checklist

  • CI passes with updated workflows
  • No repo-specific customizations were overwritten

Source: stranske/Workflows
Manifest: .github/sync-manifest.yml

Automated sync from stranske/Workflows
Template hash: 93ee083443e7

Changes synced from sync-manifest.yml
Copilot AI review requested due to automatic review settings January 8, 2026 14:01
@stranske stranske added sync Automated sync from Workflows automated Automated sync from Workflows labels Jan 8, 2026
@github-actions

github-actions Bot commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Action Required: Unable to determine source issue for PR #132. The PR title, branch name, or body must contain the issue number (e.g. #123, branch: issue-123, or the hidden marker ).

@github-actions github-actions Bot added the autofix Let bots format/lint automatically label Jan 8, 2026
@github-actions github-actions Bot added the autofix:patch Autofix patch available label Jan 8, 2026
@github-actions

github-actions Bot commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

Status | ✅ no new diagnostics
History points | 0
Timestamp | 2026-01-08 14:03:33 UTC
Report artifact | autofix-report-pr-132
Remaining | ∅
New | ∅
No additional artifacts

@github-actions

github-actions Bot commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

Autofix updated these files:

  • scripts/langchain/issue_formatter.py

@github-actions

github-actions Bot commented Jan 8, 2026

Copy link
Copy Markdown
Contributor

🤖 Keepalive Loop Status

PR #132 | Agent: Codex | Iteration 0/5

Current State

Metric Value
Iteration progress [----------] 0/5
Action wait (missing-agent-label)
Disposition skipped (transient)
Gate success
Tasks 0/5 complete
Keepalive ❌ disabled
Autofix ❌ disabled

🔍 Failure Classification

| Error type | infrastructure |
| Error category | resource |
| Suggested recovery | Confirm the referenced resource exists (repo, PR, branch, workflow, or file). |

@github-actions github-actions Bot removed the autofix:patch Autofix patch available label Jan 8, 2026
@stranske
stranske merged commit b1f72dc into main Jan 8, 2026
27 checks passed
@stranske
stranske deleted the sync/workflows-93ee083443e7 branch January 8, 2026 14:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR syncs workflow templates from the central Workflows repository, significantly expanding the agents-verify-to-issue.yml workflow to extract and analyze multiple data sources when creating follow-up issues from verification feedback.

Key changes:

  • Enhanced data extraction to parse provider comparison reports, keepalive state, and PR body content
  • Added structural problem detection to identify issues with task formatting and agent productivity
  • Implemented concern deduplication and prioritization across multiple providers
  • Restructured issue body format to present verification analysis, agent history, and actionable tasks

Comment on lines +165 to +168
const isNonActionable = (task) => {
return nonActionablePatterns.some(p => p.test(task.trim())) ||
task.length < 10 ||
task.length > 150;

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The task length validation uses arbitrary thresholds (< 10 or > 150 characters) without clear justification. Tasks between 10-150 characters could still be code snippets or non-actionable items (e.g., "def function_name(param1, param2, param3):"). Consider adding more semantic checks rather than relying solely on length, or document why these specific thresholds were chosen.

Suggested change
const isNonActionable = (task) => {
return nonActionablePatterns.some(p => p.test(task.trim())) ||
task.length < 10 ||
task.length > 150;
// Heuristic to detect code-like content that may not be covered by the regexes above.
// Looks for common code symbols/operators that are unlikely to appear in natural-language tasks.
const isProbablyCodeLike = (task) => {
const codeLikePatterns = [
/[{}();]/, // Braces, parens, semicolons
/::|=>/, // Common in many languages
/<\/\w+>/, // HTML / XML closing tags
];
const trimmed = task.trim();
return codeLikePatterns.some(p => p.test(trimmed));
};
const isNonActionable = (task) => {
const trimmed = task.trim();
const wordCount = trimmed === '' ? 0 : trimmed.split(/\s+/).length;
return (
// Known non-actionable patterns (code, types, comments, etc.)
nonActionablePatterns.some(p => p.test(trimmed)) ||
// Very short items (fewer than 3 words) are rarely actionable tasks.
wordCount > 0 && wordCount < 3 ||
// Very long items that are also code-like are likely snippets, not tasks.
(trimmed.length > 150 && isProbablyCodeLike(trimmed))
);

Copilot uses AI. Check for mistakes.
.sort((a, b) => (b.sources.length - a.sources.length))
.map(c => {
const sourceTag = c.sources.length > 1
? ' *(agreed by both providers)*' : '';

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The sourceTag generation on lines 314-315 uses a binary check (sources.length > 1) and displays "agreed by both providers". This assumes exactly 2 providers. If there are 3+ providers that agree on a concern, the message would be misleading. Consider using "agreed by X providers" or "agreed by multiple providers" for accuracy.

Suggested change
? ' *(agreed by both providers)*' : '';
? ' *(agreed by ' + c.sources.length + ' providers)*' : '';

Copilot uses AI. Check for mistakes.

// Extract individual provider details from expandable section
const providerMatches = [...body.matchAll(
/#### (\w+(?:-\w+)?)\n/g

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The regex pattern /#### (\w+(?:-\w+)?)\n/g may not match provider names that contain multiple hyphens or other special characters. For example, if a provider name is "provider-name-v2" this would only match "provider-name". Consider using a more flexible pattern like /#### ([\w-]+)\n/g to match one or more word characters or hyphens.

Suggested change
/#### (\w+(?:-\w+)?)\n/g
/#### ([\w-]+)\n/g

Copilot uses AI. Check for mistakes.
/^```\w*$/, // Code fence markers
/^class\s+\w+/, // Class definitions
/^def\s+\w+/, // Function definitions
/^\w+:\s*(str|int|float|bool|Any|list|dict|None)/i, // Type annotations

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The pattern /^\w+:\s*(str|int|float|bool|Any|list|dict|None)/i on line 156 is checking for Python type annotations, but the case-insensitive flag i could cause false positives. For example, "STRING: value" would match when it shouldn't. Python type annotations are case-sensitive, so the i flag should be removed.

Suggested change
/^\w+:\s*(str|int|float|bool|Any|list|dict|None)/i, // Type annotations
/^\w+:\s*(str|int|float|bool|Any|list|dict|None)/, // Type annotations

Copilot uses AI. Check for mistakes.
Comment on lines +285 to +289
priority: provider.concerns.indexOf(concern) === 0 ? 'high' : 'normal'
});
} else {
allConcerns.get(key).sources.push(provider.name);
allConcerns.get(key).priority = 'high'; // Multiple providers = high priority

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The priority assignment logic is inconsistent. On line 285, the priority is set to 'high' for the first concern, otherwise 'normal'. But on line 289, when a concern is found in multiple providers, it's always set to 'high'. This means a concern that wasn't first for any provider but appears in multiple providers would override the priority to 'high', but a first concern from a single provider would remain 'high'. The comment says "Multiple providers = high priority" but the logic doesn't match - it should check if sources.length > 1, not just set it unconditionally.

Copilot uses AI. Check for mistakes.
Comment on lines +255 to +256
// Filter out code snippets that aren't real tasks
if (!task.match(/^```|^class |^def |^\w+:\s*\w+\s*$|^#|^\s*$/) &&

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The duplicate filtering logic on line 256 has a slightly different regex pattern than the one used in the isNonActionable function. Line 256 uses /^```|^class |^def |^\w+:\s*\w+\s*$|^#|^\s*$/ while the isNonActionable function uses more comprehensive patterns. This inconsistency could lead to different items being filtered at different stages. Consider using the same isNonActionable function here for consistency.

Suggested change
// Filter out code snippets that aren't real tasks
if (!task.match(/^```|^class |^def |^\w+:\s*\w+\s*$|^#|^\s*$/) &&
// Filter out code snippets and other non-actionable lines
if (!isNonActionable(task) &&

Copilot uses AI. Check for mistakes.
for (const provider of providerData.providers) {
for (const concern of provider.concerns) {
// Normalize for deduplication
const key = concern.toLowerCase().replace(/[^a-z0-9]/g, '').substring(0, 50);

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The concern deduplication logic uses only the first 50 characters of a normalized concern for the key (line 280). This could cause different concerns to be incorrectly merged if they share the same first 50 characters after normalization. For example, "Missing test coverage for authentication module" and "Missing test coverage for authorization handlers" would have very similar prefixes. Consider using the full normalized string or a hash function for more accurate deduplication.

Suggested change
const key = concern.toLowerCase().replace(/[^a-z0-9]/g, '').substring(0, 50);
const key = concern.toLowerCase().replace(/[^a-z0-9]/g, '');

Copilot uses AI. Check for mistakes.
Comment on lines +311 to +316
const concernTasks = [...allConcerns.values()]
.sort((a, b) => (b.sources.length - a.sources.length))
.map(c => {
const sourceTag = c.sources.length > 1
? ' *(agreed by both providers)*' : '';
return '- [ ] ' + c.text + sourceTag;

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The 'priority' field is computed and stored in the concerns map but is never used in the output. The concerns are sorted by sources.length (line 312) but not by priority. Either use the priority field in sorting/output, or remove it to avoid confusion.

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +113
const concernsPattern = '#### ' + providerName +
'[\\s\\S]*?- \\*\\*Concerns:\\*\\*' +
'([\\s\\S]*?)(?=####|### |$)';
const providerSection = body.match(new RegExp(concernsPattern));
if (providerSection) {
const concernRegex = /^\s*-\s+(.+)$/gm;
const concernLines = providerSection[1].match(concernRegex) || [];
provider.concerns = concernLines.map(
l => l.replace(/^\s*-\s+/, '').trim()
);
}

// Extract scores
const scoresPattern = '#### ' + providerName +
'[\\s\\S]*?- \\*\\*Scores:\\*\\*' +
'([\\s\\S]*?)(?=- \\*\\*Summary|####|$)';
const scoresMatch = body.match(new RegExp(scoresPattern));

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

Similar issue as the previous comment - the provider name is used in a regex pattern without escaping. This appears in three places (lines 97-100, 110-113). If provider names contain regex special characters, the RegExp constructor will throw an error or produce incorrect matches.

Copilot uses AI. Check for mistakes.
providerData.uniqueInsights = insightsMatch[1].trim();
}
}

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

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

The old error handling logic that called core.setFailed() when no verification comment was found has been removed. The new code silently continues with empty data if no provider comparison is found (line 69 onwards). This means the workflow will create an issue with "No provider comparison found" text even when there's no verification data at all. Consider adding a check to fail early if no verification data is available, similar to the old behavior.

Suggested change
// If we couldn't find any verification comparison data, fail early
if (
!comparisonComment ||
(
(!providerData.providers || providerData.providers.length === 0) &&
!providerData.agreement &&
!providerData.uniqueInsights
)
) {
core.setFailed('No verification comparison found in verification comments; aborting issue creation.');
return;
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autofix Let bots format/lint automatically automated Automated sync from Workflows sync Automated sync from Workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants