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