@agile-vibe-coding/avc 0.2.3 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +475 -3
- package/cli/agents/agent-selector.md +23 -0
- package/cli/agents/code-implementer.md +117 -0
- package/cli/agents/code-validator.md +80 -0
- package/cli/agents/context-reviewer-epic.md +101 -0
- package/cli/agents/context-reviewer-story.md +92 -0
- package/cli/agents/context-writer-epic.md +145 -0
- package/cli/agents/context-writer-story.md +111 -0
- package/cli/agents/doc-writer-epic.md +42 -0
- package/cli/agents/doc-writer-story.md +43 -0
- package/cli/agents/duplicate-detector.md +110 -0
- package/cli/agents/epic-story-decomposer.md +318 -39
- package/cli/agents/mission-scope-generator.md +68 -4
- package/cli/agents/mission-scope-validator.md +40 -6
- package/cli/agents/project-context-extractor.md +21 -6
- package/cli/agents/scaffolding-generator.md +99 -0
- package/cli/agents/seed-validator.md +71 -0
- package/cli/agents/story-scope-reviewer.md +147 -0
- package/cli/agents/story-splitter.md +83 -0
- package/cli/agents/validator-documentation.json +31 -0
- package/cli/agents/validator-documentation.md +3 -1
- package/cli/api-reference-tool.js +368 -0
- package/cli/checks/catalog.json +76 -0
- package/cli/checks/code/quality.json +26 -0
- package/cli/checks/code/testing.json +14 -0
- package/cli/checks/code/traceability.json +26 -0
- package/cli/checks/cross-refs/epic.json +171 -0
- package/cli/checks/cross-refs/story.json +149 -0
- package/cli/checks/epic/api.json +114 -0
- package/cli/checks/epic/backend.json +126 -0
- package/cli/checks/epic/cloud.json +126 -0
- package/cli/checks/epic/data.json +102 -0
- package/cli/checks/epic/database.json +114 -0
- package/cli/checks/epic/developer.json +182 -0
- package/cli/checks/epic/devops.json +174 -0
- package/cli/checks/epic/frontend.json +162 -0
- package/cli/checks/epic/mobile.json +102 -0
- package/cli/checks/epic/qa.json +90 -0
- package/cli/checks/epic/security.json +184 -0
- package/cli/checks/epic/solution-architect.json +192 -0
- package/cli/checks/epic/test-architect.json +90 -0
- package/cli/checks/epic/ui.json +102 -0
- package/cli/checks/epic/ux.json +90 -0
- package/cli/checks/fixes/epic-fix-template.md +10 -0
- package/cli/checks/fixes/story-fix-template.md +10 -0
- package/cli/checks/story/api.json +186 -0
- package/cli/checks/story/backend.json +102 -0
- package/cli/checks/story/cloud.json +102 -0
- package/cli/checks/story/data.json +210 -0
- package/cli/checks/story/database.json +102 -0
- package/cli/checks/story/developer.json +168 -0
- package/cli/checks/story/devops.json +102 -0
- package/cli/checks/story/frontend.json +174 -0
- package/cli/checks/story/mobile.json +102 -0
- package/cli/checks/story/qa.json +210 -0
- package/cli/checks/story/security.json +198 -0
- package/cli/checks/story/solution-architect.json +230 -0
- package/cli/checks/story/test-architect.json +210 -0
- package/cli/checks/story/ui.json +102 -0
- package/cli/checks/story/ux.json +102 -0
- package/cli/coding-order.js +401 -0
- package/cli/dependency-checker.js +72 -0
- package/cli/epic-story-validator.js +284 -799
- package/cli/index.js +0 -0
- package/cli/init-model-config.js +17 -10
- package/cli/init.js +514 -92
- package/cli/kanban-server-manager.js +1 -2
- package/cli/llm-claude.js +98 -31
- package/cli/llm-gemini.js +29 -5
- package/cli/llm-local.js +493 -0
- package/cli/llm-openai.js +262 -41
- package/cli/llm-provider.js +147 -8
- package/cli/llm-token-limits.js +113 -4
- package/cli/llm-verifier.js +209 -1
- package/cli/llm-xiaomi.js +143 -0
- package/cli/message-constants.js +3 -12
- package/cli/messaging-api.js +6 -12
- package/cli/micro-check-fixer.js +335 -0
- package/cli/micro-check-runner.js +449 -0
- package/cli/micro-check-scorer.js +148 -0
- package/cli/micro-check-validator.js +538 -0
- package/cli/model-pricing.js +23 -0
- package/cli/model-selector.js +3 -2
- package/cli/prompt-logger.js +57 -0
- package/cli/repl-ink.js +106 -346
- package/cli/repl-old.js +1 -2
- package/cli/seed-processor.js +194 -24
- package/cli/sprint-planning-processor.js +2638 -289
- package/cli/template-processor.js +50 -3
- package/cli/token-tracker.js +50 -23
- package/cli/tools/generate-story-validators.js +1 -1
- package/cli/validation-router.js +70 -8
- package/cli/worktree-runner.js +654 -0
- package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
- package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
- package/kanban/client/dist/index.html +2 -2
- package/kanban/client/src/App.jsx +43 -14
- package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
- package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
- package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
- package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
- package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
- package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
- package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
- package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
- package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
- package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
- package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
- package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
- package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
- package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
- package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
- package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
- package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
- package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
- package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
- package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
- package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
- package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
- package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
- package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
- package/kanban/client/src/components/stats/CostModal.jsx +34 -3
- package/kanban/client/src/hooks/useGrouping.js +59 -0
- package/kanban/client/src/lib/api.js +118 -4
- package/kanban/client/src/lib/status-grouping.js +10 -0
- package/kanban/client/src/store/kanbanStore.js +8 -0
- package/kanban/server/index.js +23 -2
- package/kanban/server/routes/ceremony.js +153 -4
- package/kanban/server/routes/costs.js +9 -3
- package/kanban/server/routes/openai-oauth.js +366 -0
- package/kanban/server/routes/settings.js +447 -14
- package/kanban/server/routes/websocket.js +7 -2
- package/kanban/server/routes/work-items.js +141 -1
- package/kanban/server/services/CeremonyService.js +275 -24
- package/kanban/server/services/TaskRunnerService.js +261 -0
- package/kanban/server/workers/run-task-worker.js +121 -0
- package/kanban/server/workers/seed-worker.js +94 -0
- package/kanban/server/workers/sponsor-call-worker.js +14 -6
- package/kanban/server/workers/sprint-planning-worker.js +94 -12
- package/package.json +2 -3
- package/cli/agents/solver-epic-api.json +0 -15
- package/cli/agents/solver-epic-api.md +0 -39
- package/cli/agents/solver-epic-backend.json +0 -15
- package/cli/agents/solver-epic-backend.md +0 -39
- package/cli/agents/solver-epic-cloud.json +0 -15
- package/cli/agents/solver-epic-cloud.md +0 -39
- package/cli/agents/solver-epic-data.json +0 -15
- package/cli/agents/solver-epic-data.md +0 -39
- package/cli/agents/solver-epic-database.json +0 -15
- package/cli/agents/solver-epic-database.md +0 -39
- package/cli/agents/solver-epic-developer.json +0 -15
- package/cli/agents/solver-epic-developer.md +0 -39
- package/cli/agents/solver-epic-devops.json +0 -15
- package/cli/agents/solver-epic-devops.md +0 -39
- package/cli/agents/solver-epic-frontend.json +0 -15
- package/cli/agents/solver-epic-frontend.md +0 -39
- package/cli/agents/solver-epic-mobile.json +0 -15
- package/cli/agents/solver-epic-mobile.md +0 -39
- package/cli/agents/solver-epic-qa.json +0 -15
- package/cli/agents/solver-epic-qa.md +0 -39
- package/cli/agents/solver-epic-security.json +0 -15
- package/cli/agents/solver-epic-security.md +0 -39
- package/cli/agents/solver-epic-solution-architect.json +0 -15
- package/cli/agents/solver-epic-solution-architect.md +0 -39
- package/cli/agents/solver-epic-test-architect.json +0 -15
- package/cli/agents/solver-epic-test-architect.md +0 -39
- package/cli/agents/solver-epic-ui.json +0 -15
- package/cli/agents/solver-epic-ui.md +0 -39
- package/cli/agents/solver-epic-ux.json +0 -15
- package/cli/agents/solver-epic-ux.md +0 -39
- package/cli/agents/solver-story-api.json +0 -15
- package/cli/agents/solver-story-api.md +0 -39
- package/cli/agents/solver-story-backend.json +0 -15
- package/cli/agents/solver-story-backend.md +0 -39
- package/cli/agents/solver-story-cloud.json +0 -15
- package/cli/agents/solver-story-cloud.md +0 -39
- package/cli/agents/solver-story-data.json +0 -15
- package/cli/agents/solver-story-data.md +0 -39
- package/cli/agents/solver-story-database.json +0 -15
- package/cli/agents/solver-story-database.md +0 -39
- package/cli/agents/solver-story-developer.json +0 -15
- package/cli/agents/solver-story-developer.md +0 -39
- package/cli/agents/solver-story-devops.json +0 -15
- package/cli/agents/solver-story-devops.md +0 -39
- package/cli/agents/solver-story-frontend.json +0 -15
- package/cli/agents/solver-story-frontend.md +0 -39
- package/cli/agents/solver-story-mobile.json +0 -15
- package/cli/agents/solver-story-mobile.md +0 -39
- package/cli/agents/solver-story-qa.json +0 -15
- package/cli/agents/solver-story-qa.md +0 -39
- package/cli/agents/solver-story-security.json +0 -15
- package/cli/agents/solver-story-security.md +0 -39
- package/cli/agents/solver-story-solution-architect.json +0 -15
- package/cli/agents/solver-story-solution-architect.md +0 -39
- package/cli/agents/solver-story-test-architect.json +0 -15
- package/cli/agents/solver-story-test-architect.md +0 -39
- package/cli/agents/solver-story-ui.json +0 -15
- package/cli/agents/solver-story-ui.md +0 -39
- package/cli/agents/solver-story-ux.json +0 -15
- package/cli/agents/solver-story-ux.md +0 -39
- package/cli/agents/validator-epic-api.json +0 -93
- package/cli/agents/validator-epic-api.md +0 -137
- package/cli/agents/validator-epic-backend.json +0 -93
- package/cli/agents/validator-epic-backend.md +0 -130
- package/cli/agents/validator-epic-cloud.json +0 -93
- package/cli/agents/validator-epic-cloud.md +0 -137
- package/cli/agents/validator-epic-data.json +0 -93
- package/cli/agents/validator-epic-data.md +0 -130
- package/cli/agents/validator-epic-database.json +0 -93
- package/cli/agents/validator-epic-database.md +0 -137
- package/cli/agents/validator-epic-developer.json +0 -74
- package/cli/agents/validator-epic-developer.md +0 -153
- package/cli/agents/validator-epic-devops.json +0 -74
- package/cli/agents/validator-epic-devops.md +0 -153
- package/cli/agents/validator-epic-frontend.json +0 -74
- package/cli/agents/validator-epic-frontend.md +0 -153
- package/cli/agents/validator-epic-mobile.json +0 -93
- package/cli/agents/validator-epic-mobile.md +0 -130
- package/cli/agents/validator-epic-qa.json +0 -93
- package/cli/agents/validator-epic-qa.md +0 -130
- package/cli/agents/validator-epic-security.json +0 -74
- package/cli/agents/validator-epic-security.md +0 -154
- package/cli/agents/validator-epic-solution-architect.json +0 -74
- package/cli/agents/validator-epic-solution-architect.md +0 -156
- package/cli/agents/validator-epic-test-architect.json +0 -93
- package/cli/agents/validator-epic-test-architect.md +0 -130
- package/cli/agents/validator-epic-ui.json +0 -93
- package/cli/agents/validator-epic-ui.md +0 -130
- package/cli/agents/validator-epic-ux.json +0 -93
- package/cli/agents/validator-epic-ux.md +0 -130
- package/cli/agents/validator-story-api.json +0 -104
- package/cli/agents/validator-story-api.md +0 -152
- package/cli/agents/validator-story-backend.json +0 -104
- package/cli/agents/validator-story-backend.md +0 -152
- package/cli/agents/validator-story-cloud.json +0 -104
- package/cli/agents/validator-story-cloud.md +0 -152
- package/cli/agents/validator-story-data.json +0 -104
- package/cli/agents/validator-story-data.md +0 -152
- package/cli/agents/validator-story-database.json +0 -104
- package/cli/agents/validator-story-database.md +0 -152
- package/cli/agents/validator-story-developer.json +0 -104
- package/cli/agents/validator-story-developer.md +0 -152
- package/cli/agents/validator-story-devops.json +0 -104
- package/cli/agents/validator-story-devops.md +0 -152
- package/cli/agents/validator-story-frontend.json +0 -104
- package/cli/agents/validator-story-frontend.md +0 -152
- package/cli/agents/validator-story-mobile.json +0 -104
- package/cli/agents/validator-story-mobile.md +0 -152
- package/cli/agents/validator-story-qa.json +0 -104
- package/cli/agents/validator-story-qa.md +0 -152
- package/cli/agents/validator-story-security.json +0 -104
- package/cli/agents/validator-story-security.md +0 -152
- package/cli/agents/validator-story-solution-architect.json +0 -104
- package/cli/agents/validator-story-solution-architect.md +0 -152
- package/cli/agents/validator-story-test-architect.json +0 -104
- package/cli/agents/validator-story-test-architect.md +0 -152
- package/cli/agents/validator-story-ui.json +0 -104
- package/cli/agents/validator-story-ui.md +0 -152
- package/cli/agents/validator-story-ux.json +0 -104
- package/cli/agents/validator-story-ux.md +0 -152
- package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
- package/kanban/client/dist/assets/index-nLh0m82Q.css +0 -1
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* micro-check-fixer.js
|
|
3
|
+
*
|
|
4
|
+
* Handles atomic targeted fixes for failed micro-checks with regression revert.
|
|
5
|
+
* Each failed check is fixed individually, verified, and reverted if it doesn't pass.
|
|
6
|
+
* After all fixes, a regression scan ensures no previously-passing checks broke.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { runTier1Check, runTier2Check } from './micro-check-runner.js';
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Constants
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
const FIX_SYSTEM_INSTRUCTIONS =
|
|
16
|
+
'You are a precise work item editor. You fix exactly one issue at a time. ' +
|
|
17
|
+
'Make the minimum change needed to address the failed check. Never remove existing content. ' +
|
|
18
|
+
'Never add unrelated improvements.';
|
|
19
|
+
|
|
20
|
+
const SEVERITY_PRIORITY = { critical: 0, major: 1, minor: 2 };
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Prompt builder
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
function buildFixPrompt(workItemType, workItemText, check) {
|
|
27
|
+
const fieldsHint =
|
|
28
|
+
workItemType === 'epic'
|
|
29
|
+
? '- features: string[] (for epics)'
|
|
30
|
+
: '- acceptanceCriteria: string[] (for stories)';
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
'# Fix Required\n\n' +
|
|
34
|
+
`## Work Item (${workItemType})\n${workItemText}\n\n` +
|
|
35
|
+
'## Failed Check\n' +
|
|
36
|
+
`- **Check:** ${check.failDescription || check.id}\n` +
|
|
37
|
+
`- **Suggestion:** ${check.failSuggestion || 'N/A'}\n` +
|
|
38
|
+
`- **Evidence:** ${check.evidence || 'N/A'}\n\n` +
|
|
39
|
+
'## Instructions\n' +
|
|
40
|
+
'Modify the work item to address ONLY this specific issue. Do not change anything else.\n' +
|
|
41
|
+
'Return the complete updated work item as JSON with these fields:\n' +
|
|
42
|
+
'- description: string (the full updated description)\n' +
|
|
43
|
+
`${fieldsHint}\n` +
|
|
44
|
+
'- dependencies: string[] (keep unchanged unless the fix requires it)\n\n' +
|
|
45
|
+
'CRITICAL: Make the MINIMUM change necessary to pass this check. Do not add unrelated improvements.'
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Helper: deep clone a work item (plain object)
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
function cloneWorkItem(workItem) {
|
|
54
|
+
return JSON.parse(JSON.stringify(workItem));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Helper: merge work item fields from a fix into the original
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Merge fix fields into the original work item without removing existing content.
|
|
63
|
+
* @param {Object} original - The current work item
|
|
64
|
+
* @param {Object} fixed - The fix result from LLM
|
|
65
|
+
* @param {string} type - "epic" or "story"
|
|
66
|
+
* @returns {Object} Merged work item
|
|
67
|
+
*/
|
|
68
|
+
export function mergeWorkItemFields(original, fixed, type) {
|
|
69
|
+
const merged = cloneWorkItem(original);
|
|
70
|
+
|
|
71
|
+
// Update description from fix
|
|
72
|
+
if (fixed.description) {
|
|
73
|
+
merged.description = fixed.description;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (type === 'epic') {
|
|
77
|
+
const existingFeatures = Array.isArray(merged.features) ? merged.features : [];
|
|
78
|
+
const fixedFeatures = Array.isArray(fixed.features) ? fixed.features : [];
|
|
79
|
+
const featureSet = new Set(existingFeatures);
|
|
80
|
+
for (const f of fixedFeatures) {
|
|
81
|
+
featureSet.add(f);
|
|
82
|
+
}
|
|
83
|
+
merged.features = [...featureSet];
|
|
84
|
+
} else {
|
|
85
|
+
const existingCriteria = Array.isArray(merged.acceptanceCriteria) ? merged.acceptanceCriteria : [];
|
|
86
|
+
const fixedCriteria = Array.isArray(fixed.acceptanceCriteria) ? fixed.acceptanceCriteria : [];
|
|
87
|
+
const criteriaSet = new Set(existingCriteria);
|
|
88
|
+
for (const c of fixedCriteria) {
|
|
89
|
+
criteriaSet.add(c);
|
|
90
|
+
}
|
|
91
|
+
merged.acceptanceCriteria = [...criteriaSet];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Keep original dependencies, add new ones from fix if any
|
|
95
|
+
const existingDeps = Array.isArray(merged.dependencies) ? merged.dependencies : [];
|
|
96
|
+
const fixedDeps = Array.isArray(fixed.dependencies) ? fixed.dependencies : [];
|
|
97
|
+
const depSet = new Set(existingDeps);
|
|
98
|
+
for (const d of fixedDeps) {
|
|
99
|
+
depSet.add(d);
|
|
100
|
+
}
|
|
101
|
+
merged.dependencies = [...depSet];
|
|
102
|
+
|
|
103
|
+
return merged;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Helper: re-run a single check
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
async function rerunCheck(checkDef, workItemText, llmProvider, tier1Results = null) {
|
|
111
|
+
if (checkDef.tier === 2) {
|
|
112
|
+
// Tier 2 checks need tier1Results map for template variable resolution
|
|
113
|
+
return runTier2Check(checkDef, workItemText, tier1Results || new Map(), llmProvider);
|
|
114
|
+
}
|
|
115
|
+
return runTier1Check(checkDef, workItemText, llmProvider);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Helper: generate basic context text from a work item
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
function generateBasicContext(workItem, workItemType) {
|
|
123
|
+
const lines = [`# ${workItemType === 'epic' ? 'Epic' : 'Story'}: ${workItem.title || workItem.id || 'Untitled'}`];
|
|
124
|
+
if (workItem.description) {
|
|
125
|
+
lines.push('', workItem.description);
|
|
126
|
+
}
|
|
127
|
+
if (workItemType === 'epic' && Array.isArray(workItem.features)) {
|
|
128
|
+
lines.push('', '## Features');
|
|
129
|
+
for (const f of workItem.features) {
|
|
130
|
+
lines.push(`- ${f}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (workItemType === 'story' && Array.isArray(workItem.acceptanceCriteria)) {
|
|
134
|
+
lines.push('', '## Acceptance Criteria');
|
|
135
|
+
for (const c of workItem.acceptanceCriteria) {
|
|
136
|
+
lines.push(`- ${c}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (Array.isArray(workItem.dependencies) && workItem.dependencies.length > 0) {
|
|
140
|
+
lines.push('', '## Dependencies');
|
|
141
|
+
for (const d of workItem.dependencies) {
|
|
142
|
+
lines.push(`- ${d}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return lines.join('\n');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Main export
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Fix failed checks one at a time with regression detection.
|
|
154
|
+
* @param {Object} params - Named parameters
|
|
155
|
+
* @param {Object[]} params.failedChecks - Array of failed check results (from scorer), sorted by severity
|
|
156
|
+
* @param {Object[]} params.allCheckDefinitions - All check definitions (for re-running)
|
|
157
|
+
* @param {Object[]} params.allCheckResults - All check results from initial run (for regression comparison)
|
|
158
|
+
* @param {Object} params.workItem - The work item object (epic or story) to fix
|
|
159
|
+
* @param {string} params.workItemText - The work item context markdown
|
|
160
|
+
* @param {string} params.workItemType - "epic" or "story"
|
|
161
|
+
* @param {Object} params.llmProvider - LLM provider instance
|
|
162
|
+
* @param {number} [params.maxFixAttempts=3] - Max fix iterations
|
|
163
|
+
* @param {Function} [params.generateContextFn] - Regenerate context markdown from work item
|
|
164
|
+
* @param {Function} [params.progressCallback] - Progress reporting callback
|
|
165
|
+
* @param {number} [params.concurrency] - Concurrency limit (unused for now, fixes are sequential)
|
|
166
|
+
* @param {Map} [params.tier1Results] - Tier 1 results map for Tier 2 re-runs
|
|
167
|
+
* @returns {Object} { fixedWorkItem, fixedWorkItemText, fixResults[], rerunResults[], regressionDetected }
|
|
168
|
+
*/
|
|
169
|
+
export async function fixFailedChecks({
|
|
170
|
+
failedChecks,
|
|
171
|
+
allCheckDefinitions,
|
|
172
|
+
allCheckResults = [],
|
|
173
|
+
workItem,
|
|
174
|
+
workItemText,
|
|
175
|
+
workItemType,
|
|
176
|
+
llmProvider,
|
|
177
|
+
maxFixAttempts = 3,
|
|
178
|
+
generateContextFn = null,
|
|
179
|
+
progressCallback = null,
|
|
180
|
+
concurrency = 5,
|
|
181
|
+
tier1Results = null,
|
|
182
|
+
} = {}) {
|
|
183
|
+
|
|
184
|
+
// Sort by severity: critical first, then major. Skip minor.
|
|
185
|
+
const fixable = [...failedChecks]
|
|
186
|
+
.filter((c) => c.severity === 'critical' || c.severity === 'major')
|
|
187
|
+
.sort((a, b) => (SEVERITY_PRIORITY[a.severity] || 99) - (SEVERITY_PRIORITY[b.severity] || 99));
|
|
188
|
+
|
|
189
|
+
// Build a lookup map for check definitions by id
|
|
190
|
+
const checkDefMap = new Map();
|
|
191
|
+
for (const def of allCheckDefinitions) {
|
|
192
|
+
checkDefMap.set(def.id, def);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Working copies that accumulate fixes
|
|
196
|
+
let currentWorkItem = cloneWorkItem(workItem);
|
|
197
|
+
let currentText = workItemText;
|
|
198
|
+
const originalWorkItem = cloneWorkItem(workItem);
|
|
199
|
+
const originalText = workItemText;
|
|
200
|
+
|
|
201
|
+
const fixResults = [];
|
|
202
|
+
let fixCount = 0;
|
|
203
|
+
|
|
204
|
+
// 2. Fix each failed check individually
|
|
205
|
+
for (const failedCheck of fixable) {
|
|
206
|
+
if (fixCount >= maxFixAttempts) {
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const snapshotWorkItem = cloneWorkItem(currentWorkItem);
|
|
211
|
+
const snapshotText = currentText;
|
|
212
|
+
|
|
213
|
+
// 2a. Build prompt and call LLM for fix
|
|
214
|
+
const prompt = buildFixPrompt(workItemType, currentText, failedCheck);
|
|
215
|
+
let fixResponse;
|
|
216
|
+
try {
|
|
217
|
+
fixResponse = await llmProvider.generateJSON(prompt, FIX_SYSTEM_INSTRUCTIONS);
|
|
218
|
+
} catch (err) {
|
|
219
|
+
console.error(`[DEBUG] Fix LLM call failed for check ${failedCheck.id}:`, err.message);
|
|
220
|
+
fixResults.push({ checkId: failedCheck.id, attempted: true, fixed: false, reverted: false });
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Parse fix response (may already be an object from generateJSON)
|
|
225
|
+
let fixData;
|
|
226
|
+
if (fixResponse && typeof fixResponse === 'object') {
|
|
227
|
+
fixData = fixResponse;
|
|
228
|
+
} else {
|
|
229
|
+
try {
|
|
230
|
+
fixData = JSON.parse(String(fixResponse));
|
|
231
|
+
} catch {
|
|
232
|
+
console.error(`[DEBUG] Failed to parse fix response for check ${failedCheck.id}`);
|
|
233
|
+
fixResults.push({ checkId: failedCheck.id, attempted: true, fixed: false, reverted: false });
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 2b. Apply fix to working copy
|
|
239
|
+
currentWorkItem = mergeWorkItemFields(currentWorkItem, fixData, workItemType);
|
|
240
|
+
if (generateContextFn) {
|
|
241
|
+
currentText = await generateContextFn(currentWorkItem);
|
|
242
|
+
} else {
|
|
243
|
+
currentText = generateBasicContext(currentWorkItem, workItemType);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 2c. Re-run the specific check that was fixed
|
|
247
|
+
const checkDef = checkDefMap.get(failedCheck.id);
|
|
248
|
+
if (!checkDef) {
|
|
249
|
+
// Cannot verify without definition — accept optimistically
|
|
250
|
+
fixResults.push({ checkId: failedCheck.id, attempted: true, fixed: true, reverted: false });
|
|
251
|
+
fixCount++;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
let rerunResult;
|
|
256
|
+
try {
|
|
257
|
+
rerunResult = await rerunCheck(checkDef, currentText, llmProvider, tier1Results);
|
|
258
|
+
} catch (err) {
|
|
259
|
+
console.error(`[DEBUG] Re-run check failed for ${failedCheck.id}:`, err.message);
|
|
260
|
+
// Revert on verification failure
|
|
261
|
+
currentWorkItem = snapshotWorkItem;
|
|
262
|
+
currentText = snapshotText;
|
|
263
|
+
fixResults.push({ checkId: failedCheck.id, attempted: true, fixed: false, reverted: true });
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (rerunResult.passed) {
|
|
268
|
+
// Fix accepted
|
|
269
|
+
fixResults.push({ checkId: failedCheck.id, attempted: true, fixed: true, reverted: false });
|
|
270
|
+
fixCount++;
|
|
271
|
+
} else {
|
|
272
|
+
// Fix didn't work — revert
|
|
273
|
+
currentWorkItem = snapshotWorkItem;
|
|
274
|
+
currentText = snapshotText;
|
|
275
|
+
fixResults.push({ checkId: failedCheck.id, attempted: true, fixed: false, reverted: true });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// 3. Post-fix regression scan
|
|
280
|
+
// Tolerate minor noise from local models — only revert if regression rate > 20%
|
|
281
|
+
// of previously-passing checks (single flipped result on a noisy model ≠ true regression)
|
|
282
|
+
const previouslyPassing = allCheckResults.filter(
|
|
283
|
+
(r) => r.applicable !== false && r.passed === true
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
const rerunResults = [];
|
|
287
|
+
let regressionCount = 0;
|
|
288
|
+
|
|
289
|
+
for (const passingResult of previouslyPassing) {
|
|
290
|
+
const checkDef = checkDefMap.get(passingResult.id);
|
|
291
|
+
if (!checkDef) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let rerunResult;
|
|
296
|
+
try {
|
|
297
|
+
rerunResult = await rerunCheck(checkDef, currentText, llmProvider, tier1Results);
|
|
298
|
+
} catch {
|
|
299
|
+
// If we can't verify, treat as potential regression
|
|
300
|
+
rerunResult = { id: passingResult.id, passed: false, evidence: 'Re-run failed' };
|
|
301
|
+
}
|
|
302
|
+
rerunResults.push(rerunResult);
|
|
303
|
+
|
|
304
|
+
if (rerunResult.passed === false) {
|
|
305
|
+
regressionCount++;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Only revert if >20% of previously-passing checks now fail (accounts for LLM noise)
|
|
310
|
+
const regressionRate = previouslyPassing.length > 0 ? regressionCount / previouslyPassing.length : 0;
|
|
311
|
+
const regressionDetected = regressionRate > 0.2;
|
|
312
|
+
|
|
313
|
+
if (regressionDetected) {
|
|
314
|
+
console.warn(`[DEBUG] Regression detected during post-fix scan. ${regressionCount}/${previouslyPassing.length} (${(regressionRate * 100).toFixed(0)}%) checks flipped. Reverting all fixes.`);
|
|
315
|
+
return {
|
|
316
|
+
fixedWorkItem: originalWorkItem,
|
|
317
|
+
fixedWorkItemText: originalText,
|
|
318
|
+
fixResults,
|
|
319
|
+
rerunResults,
|
|
320
|
+
regressionDetected: true,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (regressionCount > 0) {
|
|
325
|
+
console.log(`[DEBUG] Post-fix scan: ${regressionCount}/${previouslyPassing.length} checks flipped (${(regressionRate * 100).toFixed(0)}%) — within noise tolerance, keeping fixes.`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return {
|
|
329
|
+
fixedWorkItem: currentWorkItem,
|
|
330
|
+
fixedWorkItemText: currentText,
|
|
331
|
+
fixResults,
|
|
332
|
+
rerunResults,
|
|
333
|
+
regressionDetected: false,
|
|
334
|
+
};
|
|
335
|
+
}
|