@agile-vibe-coding/avc 0.2.3 → 0.3.1

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.
Files changed (261) hide show
  1. package/cli/agents/agent-selector.md +23 -0
  2. package/cli/agents/code-implementer.md +117 -0
  3. package/cli/agents/code-validator.md +80 -0
  4. package/cli/agents/context-reviewer-epic.md +101 -0
  5. package/cli/agents/context-reviewer-story.md +92 -0
  6. package/cli/agents/context-writer-epic.md +145 -0
  7. package/cli/agents/context-writer-story.md +111 -0
  8. package/cli/agents/doc-writer-epic.md +42 -0
  9. package/cli/agents/doc-writer-story.md +43 -0
  10. package/cli/agents/duplicate-detector.md +110 -0
  11. package/cli/agents/epic-story-decomposer.md +318 -39
  12. package/cli/agents/mission-scope-generator.md +68 -4
  13. package/cli/agents/mission-scope-validator.md +40 -6
  14. package/cli/agents/project-context-extractor.md +21 -6
  15. package/cli/agents/scaffolding-generator.md +99 -0
  16. package/cli/agents/seed-validator.md +71 -0
  17. package/cli/agents/story-scope-reviewer.md +147 -0
  18. package/cli/agents/story-splitter.md +83 -0
  19. package/cli/agents/validator-documentation.json +31 -0
  20. package/cli/agents/validator-documentation.md +3 -1
  21. package/cli/api-reference-tool.js +368 -0
  22. package/cli/checks/catalog.json +76 -0
  23. package/cli/checks/code/quality.json +26 -0
  24. package/cli/checks/code/testing.json +14 -0
  25. package/cli/checks/code/traceability.json +26 -0
  26. package/cli/checks/cross-refs/epic.json +171 -0
  27. package/cli/checks/cross-refs/story.json +149 -0
  28. package/cli/checks/epic/api.json +114 -0
  29. package/cli/checks/epic/backend.json +126 -0
  30. package/cli/checks/epic/cloud.json +126 -0
  31. package/cli/checks/epic/data.json +102 -0
  32. package/cli/checks/epic/database.json +114 -0
  33. package/cli/checks/epic/developer.json +182 -0
  34. package/cli/checks/epic/devops.json +174 -0
  35. package/cli/checks/epic/frontend.json +162 -0
  36. package/cli/checks/epic/mobile.json +102 -0
  37. package/cli/checks/epic/qa.json +90 -0
  38. package/cli/checks/epic/security.json +184 -0
  39. package/cli/checks/epic/solution-architect.json +192 -0
  40. package/cli/checks/epic/test-architect.json +90 -0
  41. package/cli/checks/epic/ui.json +102 -0
  42. package/cli/checks/epic/ux.json +90 -0
  43. package/cli/checks/fixes/epic-fix-template.md +10 -0
  44. package/cli/checks/fixes/story-fix-template.md +10 -0
  45. package/cli/checks/story/api.json +186 -0
  46. package/cli/checks/story/backend.json +102 -0
  47. package/cli/checks/story/cloud.json +102 -0
  48. package/cli/checks/story/data.json +210 -0
  49. package/cli/checks/story/database.json +102 -0
  50. package/cli/checks/story/developer.json +168 -0
  51. package/cli/checks/story/devops.json +102 -0
  52. package/cli/checks/story/frontend.json +174 -0
  53. package/cli/checks/story/mobile.json +102 -0
  54. package/cli/checks/story/qa.json +210 -0
  55. package/cli/checks/story/security.json +198 -0
  56. package/cli/checks/story/solution-architect.json +230 -0
  57. package/cli/checks/story/test-architect.json +210 -0
  58. package/cli/checks/story/ui.json +102 -0
  59. package/cli/checks/story/ux.json +102 -0
  60. package/cli/coding-order.js +401 -0
  61. package/cli/dependency-checker.js +72 -0
  62. package/cli/epic-story-validator.js +284 -799
  63. package/cli/index.js +0 -0
  64. package/cli/init-model-config.js +17 -10
  65. package/cli/init.js +514 -92
  66. package/cli/kanban-server-manager.js +1 -2
  67. package/cli/llm-claude.js +98 -31
  68. package/cli/llm-gemini.js +29 -5
  69. package/cli/llm-local.js +493 -0
  70. package/cli/llm-openai.js +262 -41
  71. package/cli/llm-provider.js +147 -8
  72. package/cli/llm-token-limits.js +113 -4
  73. package/cli/llm-verifier.js +209 -1
  74. package/cli/llm-xiaomi.js +143 -0
  75. package/cli/message-constants.js +3 -12
  76. package/cli/messaging-api.js +6 -12
  77. package/cli/micro-check-fixer.js +335 -0
  78. package/cli/micro-check-runner.js +449 -0
  79. package/cli/micro-check-scorer.js +148 -0
  80. package/cli/micro-check-validator.js +538 -0
  81. package/cli/model-pricing.js +23 -0
  82. package/cli/model-selector.js +3 -2
  83. package/cli/prompt-logger.js +57 -0
  84. package/cli/repl-ink.js +106 -346
  85. package/cli/repl-old.js +1 -2
  86. package/cli/seed-processor.js +194 -24
  87. package/cli/sprint-planning-processor.js +2638 -289
  88. package/cli/template-processor.js +50 -3
  89. package/cli/token-tracker.js +50 -23
  90. package/cli/tools/generate-story-validators.js +1 -1
  91. package/cli/validation-router.js +70 -8
  92. package/cli/worktree-runner.js +654 -0
  93. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  94. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  95. package/kanban/client/dist/index.html +2 -2
  96. package/kanban/client/src/App.jsx +43 -14
  97. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
  98. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
  99. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
  100. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  101. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
  102. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
  103. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
  104. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
  105. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
  106. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
  107. package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
  108. package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
  109. package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
  110. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
  111. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  112. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  113. package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
  114. package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
  115. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
  116. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  117. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
  118. package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
  119. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  120. package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
  121. package/kanban/client/src/components/stats/CostModal.jsx +34 -3
  122. package/kanban/client/src/hooks/useGrouping.js +59 -0
  123. package/kanban/client/src/lib/api.js +118 -4
  124. package/kanban/client/src/lib/status-grouping.js +10 -0
  125. package/kanban/client/src/store/kanbanStore.js +8 -0
  126. package/kanban/server/index.js +23 -2
  127. package/kanban/server/routes/ceremony.js +153 -4
  128. package/kanban/server/routes/costs.js +9 -3
  129. package/kanban/server/routes/openai-oauth.js +366 -0
  130. package/kanban/server/routes/settings.js +447 -14
  131. package/kanban/server/routes/websocket.js +7 -2
  132. package/kanban/server/routes/work-items.js +141 -1
  133. package/kanban/server/services/CeremonyService.js +275 -24
  134. package/kanban/server/services/TaskRunnerService.js +261 -0
  135. package/kanban/server/workers/run-task-worker.js +121 -0
  136. package/kanban/server/workers/seed-worker.js +94 -0
  137. package/kanban/server/workers/sponsor-call-worker.js +14 -6
  138. package/kanban/server/workers/sprint-planning-worker.js +94 -12
  139. package/package.json +2 -3
  140. package/cli/agents/solver-epic-api.json +0 -15
  141. package/cli/agents/solver-epic-api.md +0 -39
  142. package/cli/agents/solver-epic-backend.json +0 -15
  143. package/cli/agents/solver-epic-backend.md +0 -39
  144. package/cli/agents/solver-epic-cloud.json +0 -15
  145. package/cli/agents/solver-epic-cloud.md +0 -39
  146. package/cli/agents/solver-epic-data.json +0 -15
  147. package/cli/agents/solver-epic-data.md +0 -39
  148. package/cli/agents/solver-epic-database.json +0 -15
  149. package/cli/agents/solver-epic-database.md +0 -39
  150. package/cli/agents/solver-epic-developer.json +0 -15
  151. package/cli/agents/solver-epic-developer.md +0 -39
  152. package/cli/agents/solver-epic-devops.json +0 -15
  153. package/cli/agents/solver-epic-devops.md +0 -39
  154. package/cli/agents/solver-epic-frontend.json +0 -15
  155. package/cli/agents/solver-epic-frontend.md +0 -39
  156. package/cli/agents/solver-epic-mobile.json +0 -15
  157. package/cli/agents/solver-epic-mobile.md +0 -39
  158. package/cli/agents/solver-epic-qa.json +0 -15
  159. package/cli/agents/solver-epic-qa.md +0 -39
  160. package/cli/agents/solver-epic-security.json +0 -15
  161. package/cli/agents/solver-epic-security.md +0 -39
  162. package/cli/agents/solver-epic-solution-architect.json +0 -15
  163. package/cli/agents/solver-epic-solution-architect.md +0 -39
  164. package/cli/agents/solver-epic-test-architect.json +0 -15
  165. package/cli/agents/solver-epic-test-architect.md +0 -39
  166. package/cli/agents/solver-epic-ui.json +0 -15
  167. package/cli/agents/solver-epic-ui.md +0 -39
  168. package/cli/agents/solver-epic-ux.json +0 -15
  169. package/cli/agents/solver-epic-ux.md +0 -39
  170. package/cli/agents/solver-story-api.json +0 -15
  171. package/cli/agents/solver-story-api.md +0 -39
  172. package/cli/agents/solver-story-backend.json +0 -15
  173. package/cli/agents/solver-story-backend.md +0 -39
  174. package/cli/agents/solver-story-cloud.json +0 -15
  175. package/cli/agents/solver-story-cloud.md +0 -39
  176. package/cli/agents/solver-story-data.json +0 -15
  177. package/cli/agents/solver-story-data.md +0 -39
  178. package/cli/agents/solver-story-database.json +0 -15
  179. package/cli/agents/solver-story-database.md +0 -39
  180. package/cli/agents/solver-story-developer.json +0 -15
  181. package/cli/agents/solver-story-developer.md +0 -39
  182. package/cli/agents/solver-story-devops.json +0 -15
  183. package/cli/agents/solver-story-devops.md +0 -39
  184. package/cli/agents/solver-story-frontend.json +0 -15
  185. package/cli/agents/solver-story-frontend.md +0 -39
  186. package/cli/agents/solver-story-mobile.json +0 -15
  187. package/cli/agents/solver-story-mobile.md +0 -39
  188. package/cli/agents/solver-story-qa.json +0 -15
  189. package/cli/agents/solver-story-qa.md +0 -39
  190. package/cli/agents/solver-story-security.json +0 -15
  191. package/cli/agents/solver-story-security.md +0 -39
  192. package/cli/agents/solver-story-solution-architect.json +0 -15
  193. package/cli/agents/solver-story-solution-architect.md +0 -39
  194. package/cli/agents/solver-story-test-architect.json +0 -15
  195. package/cli/agents/solver-story-test-architect.md +0 -39
  196. package/cli/agents/solver-story-ui.json +0 -15
  197. package/cli/agents/solver-story-ui.md +0 -39
  198. package/cli/agents/solver-story-ux.json +0 -15
  199. package/cli/agents/solver-story-ux.md +0 -39
  200. package/cli/agents/validator-epic-api.json +0 -93
  201. package/cli/agents/validator-epic-api.md +0 -137
  202. package/cli/agents/validator-epic-backend.json +0 -93
  203. package/cli/agents/validator-epic-backend.md +0 -130
  204. package/cli/agents/validator-epic-cloud.json +0 -93
  205. package/cli/agents/validator-epic-cloud.md +0 -137
  206. package/cli/agents/validator-epic-data.json +0 -93
  207. package/cli/agents/validator-epic-data.md +0 -130
  208. package/cli/agents/validator-epic-database.json +0 -93
  209. package/cli/agents/validator-epic-database.md +0 -137
  210. package/cli/agents/validator-epic-developer.json +0 -74
  211. package/cli/agents/validator-epic-developer.md +0 -153
  212. package/cli/agents/validator-epic-devops.json +0 -74
  213. package/cli/agents/validator-epic-devops.md +0 -153
  214. package/cli/agents/validator-epic-frontend.json +0 -74
  215. package/cli/agents/validator-epic-frontend.md +0 -153
  216. package/cli/agents/validator-epic-mobile.json +0 -93
  217. package/cli/agents/validator-epic-mobile.md +0 -130
  218. package/cli/agents/validator-epic-qa.json +0 -93
  219. package/cli/agents/validator-epic-qa.md +0 -130
  220. package/cli/agents/validator-epic-security.json +0 -74
  221. package/cli/agents/validator-epic-security.md +0 -154
  222. package/cli/agents/validator-epic-solution-architect.json +0 -74
  223. package/cli/agents/validator-epic-solution-architect.md +0 -156
  224. package/cli/agents/validator-epic-test-architect.json +0 -93
  225. package/cli/agents/validator-epic-test-architect.md +0 -130
  226. package/cli/agents/validator-epic-ui.json +0 -93
  227. package/cli/agents/validator-epic-ui.md +0 -130
  228. package/cli/agents/validator-epic-ux.json +0 -93
  229. package/cli/agents/validator-epic-ux.md +0 -130
  230. package/cli/agents/validator-story-api.json +0 -104
  231. package/cli/agents/validator-story-api.md +0 -152
  232. package/cli/agents/validator-story-backend.json +0 -104
  233. package/cli/agents/validator-story-backend.md +0 -152
  234. package/cli/agents/validator-story-cloud.json +0 -104
  235. package/cli/agents/validator-story-cloud.md +0 -152
  236. package/cli/agents/validator-story-data.json +0 -104
  237. package/cli/agents/validator-story-data.md +0 -152
  238. package/cli/agents/validator-story-database.json +0 -104
  239. package/cli/agents/validator-story-database.md +0 -152
  240. package/cli/agents/validator-story-developer.json +0 -104
  241. package/cli/agents/validator-story-developer.md +0 -152
  242. package/cli/agents/validator-story-devops.json +0 -104
  243. package/cli/agents/validator-story-devops.md +0 -152
  244. package/cli/agents/validator-story-frontend.json +0 -104
  245. package/cli/agents/validator-story-frontend.md +0 -152
  246. package/cli/agents/validator-story-mobile.json +0 -104
  247. package/cli/agents/validator-story-mobile.md +0 -152
  248. package/cli/agents/validator-story-qa.json +0 -104
  249. package/cli/agents/validator-story-qa.md +0 -152
  250. package/cli/agents/validator-story-security.json +0 -104
  251. package/cli/agents/validator-story-security.md +0 -152
  252. package/cli/agents/validator-story-solution-architect.json +0 -104
  253. package/cli/agents/validator-story-solution-architect.md +0 -152
  254. package/cli/agents/validator-story-test-architect.json +0 -104
  255. package/cli/agents/validator-story-test-architect.md +0 -152
  256. package/cli/agents/validator-story-ui.json +0 -104
  257. package/cli/agents/validator-story-ui.md +0 -152
  258. package/cli/agents/validator-story-ux.json +0 -104
  259. package/cli/agents/validator-story-ux.md +0 -152
  260. package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
  261. 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
+ }