-
Notifications
You must be signed in to change notification settings - Fork 0
chore: sync workflow templates #140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -822,15 +822,44 @@ async function evaluateKeepaliveLoop({ github, context, core, payload: overrideP | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const maxIterations = toNumber(config.max_iterations ?? state.max_iterations, 5); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const failureThreshold = toNumber(config.failure_threshold ?? state.failure_threshold, 3); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Productivity tracking: determine if recent iterations have been productive | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // An iteration is productive if it made file changes or completed tasks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Evidence-based productivity tracking | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Uses multiple signals to determine if work is being done: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 1. File changes (primary signal) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 2. Task completion progress | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 3. Historical productivity trend | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const lastFilesChanged = toNumber(state.last_files_changed, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const prevFilesChanged = toNumber(state.prev_files_changed, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hasRecentFailures = Boolean(state.failure?.count > 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isProductive = lastFilesChanged > 0 && !hasRecentFailures; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Track task completion trend | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const previousTasks = state.tasks || {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const prevUnchecked = toNumber(previousTasks.unchecked, checkboxCounts.unchecked); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const tasksCompletedSinceLastRound = prevUnchecked - checkboxCounts.unchecked; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Calculate productivity score (0-100) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This is evidence-based: higher score = more confidence work is happening | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let productivityScore = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (lastFilesChanged > 0) productivityScore += Math.min(40, lastFilesChanged * 10); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (tasksCompletedSinceLastRound > 0) productivityScore += Math.min(40, tasksCompletedSinceLastRound * 20); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prevFilesChanged > 0 && iteration > 1) productivityScore += 10; // Recent historical activity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!hasRecentFailures) productivityScore += 10; // No failures is a positive signal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // An iteration is productive if it has a reasonable productivity score | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isProductive = productivityScore >= 20 && !hasRecentFailures; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Early detection: Check for diminishing returns pattern | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If we had activity before but now have none, might be naturally completing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const diminishingReturns = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| iteration >= 2 && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prevFilesChanged > 0 && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lastFilesChanged === 0 && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tasksCompletedSinceLastRound === 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // max_iterations is a "stuck detection" threshold, not a hard cap | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Continue past max if productive work is happening | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // But stop earlier if we detect diminishing returns pattern | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const shouldStopForMaxIterations = iteration >= maxIterations && !isProductive; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const shouldStopEarly = diminishingReturns && iteration >= Math.ceil(maxIterations * 0.6); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const shouldStopEarly = diminishingReturns && iteration >= Math.ceil(maxIterations * 0.6); | |
| const shouldStopEarly = | |
| diminishingReturns && | |
| iteration >= Math.max(2, Math.ceil(maxIterations * 0.6)); |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The llmConfidenceAdjusted parameter is extracted from inputs here but is never passed from the workflow file. The workflow only passes quality-related outputs like llm_raw_confidence, llm_quality_warnings, etc., but doesn't include llm_confidence_adjusted or llm-confidence-adjusted. This means the confidence adjustment warning at line 1289 will never be displayed since llmConfidenceAdjusted will always be false. Either add the missing input parameter in the workflow file or remove this unused variable.
| const llmConfidenceAdjusted = toBool(inputs.llm_confidence_adjusted ?? inputs.llmConfidenceAdjusted, false); | |
| const llmConfidenceAdjusted = | |
| Number.isFinite(llmRawConfidence) && | |
| Number.isFinite(llmConfidence) && | |
| llmRawConfidence !== llmConfidence; |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The warning parsing logic assumes warnings are semicolon-delimited when JSON parsing fails, but there's no guarantee that the warnings string format uses semicolons. If warnings come in a different format (comma-separated, newline-separated, or plain text), this will fail to parse them correctly. Consider adding more robust parsing that handles multiple common delimiters or documenting the expected format more explicitly.
| // Parse warnings (could be JSON array or comma-separated) | |
| let warnings = []; | |
| try { | |
| warnings = JSON.parse(llmQualityWarnings); | |
| } catch { | |
| warnings = llmQualityWarnings.split(';').filter(w => w.trim()); | |
| } | |
| for (const warning of warnings) { | |
| summaryLines.push(`- ⚠️ ${warning.trim()}`); | |
| // Parse warnings (could be JSON array or delimited string) | |
| let warnings = []; | |
| let rawWarnings = String(llmQualityWarnings); | |
| try { | |
| const parsed = JSON.parse(llmQualityWarnings); | |
| if (Array.isArray(parsed)) { | |
| warnings = parsed; | |
| } else if (typeof parsed === 'string') { | |
| rawWarnings = parsed; | |
| } else if (parsed && typeof parsed === 'object') { | |
| rawWarnings = Object.values(parsed).join('\n'); | |
| } | |
| } catch { | |
| // Fall back to treating llmQualityWarnings as a raw delimited string | |
| } | |
| if (!warnings.length && rawWarnings) { | |
| // Support multiple common delimiters: semicolon, comma, newline | |
| warnings = String(rawWarnings) | |
| .split(/[\n;,]/) | |
| .map(w => w.trim()) | |
| .filter(Boolean); | |
| } | |
| for (const warning of warnings) { | |
| summaryLines.push(`- ⚠️ ${String(warning).trim()}`); |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The data loss alert uses a hardcoded threshold of 200 characters, but this threshold isn't documented or justified. Different types of analysis might naturally have different text lengths, and 200 characters seems arbitrary. Consider making this threshold configurable or adding a comment explaining why 200 characters is the chosen threshold for detecting data loss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The productivity score calculation can exceed 100 in edge cases. For example, if
lastFilesChangedis 4+ (40 points),tasksCompletedSinceLastRoundis 2+ (40 points), there's historical activity (10 points), and no failures (10 points), the score would be 100. However, iflastFilesChangedis 5, the formulaMath.min(40, lastFilesChanged * 10)would give 40, but the total could still be 100. The issue is that the score is described as 0-100 but the logic doesn't enforce a maximum of 100. Consider capping the final score withMath.min(100, productivityScore)after all additions.