@yasserkhanorg/impact-gate 2.1.1 → 2.1.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/dist/esm/qa-agent/finding_taxonomy.js +6 -1
- package/dist/esm/qa-agent/phase2/agent_loop.js +2 -1
- package/dist/esm/qa-agent/phase2/tools.js +2 -2
- package/dist/esm/qa-agent/phase25/fix_loop.js +16 -5
- package/dist/esm/qa-agent/phase25/fix_tools.js +15 -5
- package/dist/esm/qa-agent/regression/baseline.js +12 -5
- package/dist/qa-agent/finding_taxonomy.d.ts.map +1 -1
- package/dist/qa-agent/finding_taxonomy.js +6 -1
- package/dist/qa-agent/phase2/agent_loop.d.ts.map +1 -1
- package/dist/qa-agent/phase2/agent_loop.js +2 -1
- package/dist/qa-agent/phase2/tools.js +2 -2
- package/dist/qa-agent/phase25/fix_loop.d.ts.map +1 -1
- package/dist/qa-agent/phase25/fix_loop.js +16 -5
- package/dist/qa-agent/phase25/fix_tools.d.ts +4 -0
- package/dist/qa-agent/phase25/fix_tools.d.ts.map +1 -1
- package/dist/qa-agent/phase25/fix_tools.js +15 -5
- package/dist/qa-agent/regression/baseline.d.ts +0 -3
- package/dist/qa-agent/regression/baseline.d.ts.map +1 -1
- package/dist/qa-agent/regression/baseline.js +12 -5
- package/dist/qa-agent/types.d.ts +1 -1
- package/dist/qa-agent/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ const LEGACY_TO_CATEGORY = {
|
|
|
10
10
|
'ux-issue': 'ux',
|
|
11
11
|
};
|
|
12
12
|
const CANONICAL_CATEGORIES = new Set([
|
|
13
|
-
'visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility',
|
|
13
|
+
'visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility', 'links',
|
|
14
14
|
]);
|
|
15
15
|
/**
|
|
16
16
|
* Normalize any FindingType (legacy or canonical) to a canonical FindingCategory.
|
|
@@ -46,6 +46,11 @@ export const SEVERITY_DEFINITIONS = {
|
|
|
46
46
|
// Category definitions
|
|
47
47
|
// ---------------------------------------------------------------------------
|
|
48
48
|
export const CATEGORY_DEFINITIONS = {
|
|
49
|
+
links: {
|
|
50
|
+
label: 'Links',
|
|
51
|
+
description: 'Broken links (404), wrong destinations, dead anchors, external links that fail.',
|
|
52
|
+
examples: ['404 on nav link', 'Link goes to wrong page', 'Anchor target missing', 'External link returns 500'],
|
|
53
|
+
},
|
|
49
54
|
visual: {
|
|
50
55
|
label: 'Visual/UI',
|
|
51
56
|
description: 'Layout breaks, broken images, z-index issues, font/color inconsistencies, animation glitches, alignment issues, dark mode problems.',
|
|
@@ -49,7 +49,8 @@ Pick dimensions that matter for THIS flow. Example: for "channel settings" → p
|
|
|
49
49
|
## Finding Categories
|
|
50
50
|
When reporting findings, use the most specific category:
|
|
51
51
|
- **visual** — Layout breaks, broken images, z-index issues, alignment, animation glitches, dark mode problems
|
|
52
|
-
- **
|
|
52
|
+
- **links** — Broken links (404), wrong destinations, dead anchors, external links that fail
|
|
53
|
+
- **functional** — Dead buttons, form validation failures, incorrect redirects, race conditions, state not persisting
|
|
53
54
|
- **ux** — Confusing navigation, missing loading indicators, slow interactions (>500ms), unclear error messages, no confirmation before destructive actions
|
|
54
55
|
- **content** — Typos, grammar errors, placeholder/lorem ipsum left in, truncated text, wrong labels
|
|
55
56
|
- **performance** — Slow page loads (>3s), janky scrolling, layout shifts (CLS), excessive network requests
|
|
@@ -99,7 +99,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
99
99
|
input_schema: {
|
|
100
100
|
type: 'object',
|
|
101
101
|
properties: {
|
|
102
|
-
type: { type: 'string', enum: ['visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility', 'bug', 'visual-regression', 'ux-issue', 'gap'] },
|
|
102
|
+
type: { type: 'string', enum: ['visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility', 'links', 'bug', 'visual-regression', 'ux-issue', 'gap'] },
|
|
103
103
|
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'info'] },
|
|
104
104
|
summary: { type: 'string', description: 'What you found' },
|
|
105
105
|
repro_steps: {
|
|
@@ -217,7 +217,7 @@ export function executeTool(ctx, name, input) {
|
|
|
217
217
|
}
|
|
218
218
|
case 'report_finding': {
|
|
219
219
|
const VALID_TYPES = new Set([
|
|
220
|
-
'visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility',
|
|
220
|
+
'visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility', 'links',
|
|
221
221
|
'bug', 'visual-regression', 'ux-issue', 'gap',
|
|
222
222
|
]);
|
|
223
223
|
const VALID_SEVERITIES = new Set(['critical', 'high', 'medium', 'low', 'info']);
|
|
@@ -91,6 +91,7 @@ export async function runFixLoop(config, findings, browser, projectRoot) {
|
|
|
91
91
|
baseUrl: config.baseUrl,
|
|
92
92
|
screenshotDir,
|
|
93
93
|
screenshotCounter: 100, // Start at 100 to avoid collisions with Phase 2 screenshots
|
|
94
|
+
qaCommitHashes: new Set(),
|
|
94
95
|
};
|
|
95
96
|
for (const finding of fixable) {
|
|
96
97
|
if (wtf.shouldStop()) {
|
|
@@ -111,7 +112,10 @@ export async function runFixLoop(config, findings, browser, projectRoot) {
|
|
|
111
112
|
costUSD += result.costUSD;
|
|
112
113
|
wtf.recordAttempt(result.fix.status, result.fix.filesChanged?.length || 0);
|
|
113
114
|
}
|
|
114
|
-
|
|
115
|
+
// Exclude verified fixes from the post-fix score so it reflects actual remaining issues
|
|
116
|
+
const verifiedIds = new Set(fixes.filter((f) => f.status === 'verified').map((f) => f.findingId));
|
|
117
|
+
const remainingFindings = findings.filter((f) => !verifiedIds.has(f.id));
|
|
118
|
+
const healthScoreAfter = computeHealthScore(remainingFindings);
|
|
115
119
|
return {
|
|
116
120
|
fixes,
|
|
117
121
|
fixesAttempted: fixes.filter((f) => f.status !== 'skipped').length,
|
|
@@ -134,6 +138,7 @@ async function fixSingleFinding(client, model, config, finding, toolCtx) {
|
|
|
134
138
|
let filesChanged = [];
|
|
135
139
|
let beforeScreenshot;
|
|
136
140
|
let afterScreenshot;
|
|
141
|
+
let verifiedFixed = false;
|
|
137
142
|
let status = 'skipped';
|
|
138
143
|
// Take "before" screenshot
|
|
139
144
|
try {
|
|
@@ -176,9 +181,10 @@ async function fixSingleFinding(client, model, config, finding, toolCtx) {
|
|
|
176
181
|
// If no tool use, the agent is done
|
|
177
182
|
const toolUseBlocks = assistantContent.filter((b) => b.type === 'tool_use');
|
|
178
183
|
if (toolUseBlocks.length === 0) {
|
|
179
|
-
// Determine status
|
|
184
|
+
// Determine status: 'verified' requires both a commit and explicit confirmation
|
|
185
|
+
// from verify_in_browser that the bug is gone. A screenshot alone is not proof.
|
|
180
186
|
if (commitHash) {
|
|
181
|
-
status =
|
|
187
|
+
status = verifiedFixed ? 'verified' : 'best-effort';
|
|
182
188
|
}
|
|
183
189
|
break;
|
|
184
190
|
}
|
|
@@ -194,8 +200,13 @@ async function fixSingleFinding(client, model, config, finding, toolCtx) {
|
|
|
194
200
|
if (result.filesChanged) {
|
|
195
201
|
filesChanged = [...filesChanged, ...result.filesChanged];
|
|
196
202
|
}
|
|
197
|
-
if (
|
|
198
|
-
|
|
203
|
+
if (block.name === 'verify_in_browser') {
|
|
204
|
+
if (result.screenshotPath) {
|
|
205
|
+
afterScreenshot = result.screenshotPath;
|
|
206
|
+
}
|
|
207
|
+
if (result.verifiedFixed === true) {
|
|
208
|
+
verifiedFixed = true;
|
|
209
|
+
}
|
|
199
210
|
}
|
|
200
211
|
if (block.name === 'git_revert') {
|
|
201
212
|
status = 'reverted';
|
|
@@ -82,14 +82,15 @@ export const FIX_TOOL_DEFINITIONS = [
|
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
name: 'verify_in_browser',
|
|
85
|
-
description: 'Navigate to a URL
|
|
85
|
+
description: 'Navigate to a URL, take a screenshot, and report whether the fix resolved the issue. You MUST set fixed=true only if the original bug is no longer present. Set fixed=false if the bug still reproduces or if you cannot confirm.',
|
|
86
86
|
input_schema: {
|
|
87
87
|
type: 'object',
|
|
88
88
|
properties: {
|
|
89
89
|
url: { type: 'string', description: 'URL to navigate to for verification' },
|
|
90
90
|
label: { type: 'string', description: 'Label for the screenshot (e.g. "after-fix-001")' },
|
|
91
|
+
fixed: { type: 'boolean', description: 'true if the original bug is gone, false if it still reproduces or uncertain' },
|
|
91
92
|
},
|
|
92
|
-
required: ['url', 'label'],
|
|
93
|
+
required: ['url', 'label', 'fixed'],
|
|
93
94
|
},
|
|
94
95
|
},
|
|
95
96
|
];
|
|
@@ -216,6 +217,7 @@ export function executeFixTool(ctx, name, input) {
|
|
|
216
217
|
execFileSync('git', ['add', ...files], { cwd: ctx.projectRoot, encoding: 'utf-8' });
|
|
217
218
|
execFileSync('git', ['commit', '-m', message], { cwd: ctx.projectRoot, encoding: 'utf-8' });
|
|
218
219
|
const hash = execFileSync('git', ['rev-parse', '--short', 'HEAD'], { cwd: ctx.projectRoot, encoding: 'utf-8' }).trim();
|
|
220
|
+
ctx.qaCommitHashes.add(hash);
|
|
219
221
|
return { output: `Committed: ${hash} — ${message}`, commitHash: hash, filesChanged: files };
|
|
220
222
|
}
|
|
221
223
|
catch (err) {
|
|
@@ -224,10 +226,16 @@ export function executeFixTool(ctx, name, input) {
|
|
|
224
226
|
}
|
|
225
227
|
}
|
|
226
228
|
case 'git_revert': {
|
|
229
|
+
// Safety: only revert commits created by the fix loop
|
|
230
|
+
const currentHead = execFileSync('git', ['rev-parse', '--short', 'HEAD'], { cwd: ctx.projectRoot, encoding: 'utf-8' }).trim();
|
|
231
|
+
if (!ctx.qaCommitHashes.has(currentHead)) {
|
|
232
|
+
return { output: `Blocked: HEAD (${currentHead}) was not created by the fix loop. Refusing to revert a user commit.` };
|
|
233
|
+
}
|
|
227
234
|
try {
|
|
228
235
|
execFileSync('git', ['revert', '--no-edit', 'HEAD'], { cwd: ctx.projectRoot, encoding: 'utf-8' });
|
|
229
|
-
|
|
230
|
-
|
|
236
|
+
ctx.qaCommitHashes.delete(currentHead);
|
|
237
|
+
const newHash = execFileSync('git', ['rev-parse', '--short', 'HEAD'], { cwd: ctx.projectRoot, encoding: 'utf-8' }).trim();
|
|
238
|
+
return { output: `Reverted ${currentHead}. New HEAD: ${newHash}`, commitHash: newHash };
|
|
231
239
|
}
|
|
232
240
|
catch (err) {
|
|
233
241
|
const error = err;
|
|
@@ -254,7 +262,9 @@ export function executeFixTool(ctx, name, input) {
|
|
|
254
262
|
catch {
|
|
255
263
|
// Not available
|
|
256
264
|
}
|
|
257
|
-
|
|
265
|
+
const fixed = input.fixed === true;
|
|
266
|
+
const verdict = fixed ? 'Bug appears resolved.' : 'Bug still reproduces or unconfirmed.';
|
|
267
|
+
return { output: `Screenshot saved: ${screenshotPath}. ${verdict}${consoleErrors}`, screenshotPath, verifiedFixed: fixed };
|
|
258
268
|
}
|
|
259
269
|
default:
|
|
260
270
|
return { output: `Unknown fix tool: ${name}` };
|
|
@@ -55,18 +55,25 @@ export function loadBaseline(outputDir) {
|
|
|
55
55
|
/**
|
|
56
56
|
* Compare current findings against a saved baseline.
|
|
57
57
|
*/
|
|
58
|
+
/**
|
|
59
|
+
* Build a fingerprint for a finding that includes flow, type, and summary
|
|
60
|
+
* to avoid collapsing distinct issues with the same generic summary.
|
|
61
|
+
*/
|
|
62
|
+
function issueFingerprint(issue) {
|
|
63
|
+
return `${issue.flow}|${issue.type}|${issue.summary}`.toLowerCase();
|
|
64
|
+
}
|
|
58
65
|
export function compareBaselines(currentScore, currentFindings, baseline) {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
66
|
+
const baselineFingerprints = new Set(baseline.issues.map((i) => issueFingerprint(i)));
|
|
67
|
+
const currentFingerprints = new Set(currentFindings
|
|
61
68
|
.filter((f) => f.type !== 'verified-ok')
|
|
62
|
-
.map((f) => f
|
|
69
|
+
.map((f) => issueFingerprint(f)));
|
|
63
70
|
// Issues in baseline but not in current = fixed
|
|
64
71
|
const fixedIssues = baseline.issues
|
|
65
|
-
.filter((i) => !
|
|
72
|
+
.filter((i) => !currentFingerprints.has(issueFingerprint(i)))
|
|
66
73
|
.map((i) => `${i.id}: ${i.summary}`);
|
|
67
74
|
// Issues in current but not in baseline = new
|
|
68
75
|
const newIssues = currentFindings
|
|
69
|
-
.filter((f) => f.type !== 'verified-ok' && !
|
|
76
|
+
.filter((f) => f.type !== 'verified-ok' && !baselineFingerprints.has(issueFingerprint(f)))
|
|
70
77
|
.map((f) => `${f.id}: ${f.summary}`);
|
|
71
78
|
// Category deltas
|
|
72
79
|
const categoryDeltas = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finding_taxonomy.d.ts","sourceRoot":"","sources":["../../src/qa-agent/finding_taxonomy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,mBAAmB,EAAC,MAAM,YAAY,CAAC;AAiBrH;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAKjE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,WAAW,GAAG,mBAAmB,CAK/E;AAMD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAMhE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,eAAe,EAAE;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAC,
|
|
1
|
+
{"version":3,"file":"finding_taxonomy.d.ts","sourceRoot":"","sources":["../../src/qa-agent/finding_taxonomy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,mBAAmB,EAAC,MAAM,YAAY,CAAC;AAiBrH;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAKjE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,WAAW,GAAG,mBAAmB,CAK/E;AAMD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAMhE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,eAAe,EAAE;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAC,CAyClH,CAAC;AAYF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAKlE"}
|
|
@@ -16,7 +16,7 @@ const LEGACY_TO_CATEGORY = {
|
|
|
16
16
|
'ux-issue': 'ux',
|
|
17
17
|
};
|
|
18
18
|
const CANONICAL_CATEGORIES = new Set([
|
|
19
|
-
'visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility',
|
|
19
|
+
'visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility', 'links',
|
|
20
20
|
]);
|
|
21
21
|
/**
|
|
22
22
|
* Normalize any FindingType (legacy or canonical) to a canonical FindingCategory.
|
|
@@ -52,6 +52,11 @@ exports.SEVERITY_DEFINITIONS = {
|
|
|
52
52
|
// Category definitions
|
|
53
53
|
// ---------------------------------------------------------------------------
|
|
54
54
|
exports.CATEGORY_DEFINITIONS = {
|
|
55
|
+
links: {
|
|
56
|
+
label: 'Links',
|
|
57
|
+
description: 'Broken links (404), wrong destinations, dead anchors, external links that fail.',
|
|
58
|
+
examples: ['404 on nav link', 'Link goes to wrong page', 'Anchor target missing', 'External link returns 500'],
|
|
59
|
+
},
|
|
55
60
|
visual: {
|
|
56
61
|
label: 'Visual/UI',
|
|
57
62
|
description: 'Layout breaks, broken images, z-index issues, font/color inconsistencies, animation glitches, alignment issues, dark mode problems.',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent_loop.d.ts","sourceRoot":"","sources":["../../../src/qa-agent/phase2/agent_loop.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAA2C,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"agent_loop.d.ts","sourceRoot":"","sources":["../../../src/qa-agent/phase2/agent_loop.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAA2C,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAC,MAAM,aAAa,CAAC;AAwJ9G,wBAAsB,YAAY,CAC9B,MAAM,EAAE,QAAQ,EAChB,KAAK,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,YAAY,CAAC,CAyOvB"}
|
|
@@ -55,7 +55,8 @@ Pick dimensions that matter for THIS flow. Example: for "channel settings" → p
|
|
|
55
55
|
## Finding Categories
|
|
56
56
|
When reporting findings, use the most specific category:
|
|
57
57
|
- **visual** — Layout breaks, broken images, z-index issues, alignment, animation glitches, dark mode problems
|
|
58
|
-
- **
|
|
58
|
+
- **links** — Broken links (404), wrong destinations, dead anchors, external links that fail
|
|
59
|
+
- **functional** — Dead buttons, form validation failures, incorrect redirects, race conditions, state not persisting
|
|
59
60
|
- **ux** — Confusing navigation, missing loading indicators, slow interactions (>500ms), unclear error messages, no confirmation before destructive actions
|
|
60
61
|
- **content** — Typos, grammar errors, placeholder/lorem ipsum left in, truncated text, wrong labels
|
|
61
62
|
- **performance** — Slow page loads (>3s), janky scrolling, layout shifts (CLS), excessive network requests
|
|
@@ -103,7 +103,7 @@ exports.TOOL_DEFINITIONS = [
|
|
|
103
103
|
input_schema: {
|
|
104
104
|
type: 'object',
|
|
105
105
|
properties: {
|
|
106
|
-
type: { type: 'string', enum: ['visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility', 'bug', 'visual-regression', 'ux-issue', 'gap'] },
|
|
106
|
+
type: { type: 'string', enum: ['visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility', 'links', 'bug', 'visual-regression', 'ux-issue', 'gap'] },
|
|
107
107
|
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'info'] },
|
|
108
108
|
summary: { type: 'string', description: 'What you found' },
|
|
109
109
|
repro_steps: {
|
|
@@ -221,7 +221,7 @@ function executeTool(ctx, name, input) {
|
|
|
221
221
|
}
|
|
222
222
|
case 'report_finding': {
|
|
223
223
|
const VALID_TYPES = new Set([
|
|
224
|
-
'visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility',
|
|
224
|
+
'visual', 'functional', 'ux', 'content', 'performance', 'console', 'accessibility', 'links',
|
|
225
225
|
'bug', 'visual-regression', 'ux-issue', 'gap',
|
|
226
226
|
]);
|
|
227
227
|
const VALID_SEVERITIES = new Set(['critical', 'high', 'medium', 'low', 'info']);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix_loop.d.ts","sourceRoot":"","sources":["../../../src/qa-agent/phase25/fix_loop.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,OAAO,EAAqC,aAAa,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AACrG,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,4BAA4B,CAAC;AAuD7D,wBAAsB,UAAU,CAC5B,MAAM,EAAE,QAAQ,EAChB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"fix_loop.d.ts","sourceRoot":"","sources":["../../../src/qa-agent/phase25/fix_loop.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,OAAO,EAAqC,aAAa,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AACrG,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,4BAA4B,CAAC;AAuD7D,wBAAsB,UAAU,CAC5B,MAAM,EAAE,QAAQ,EAChB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,CAAC,CA4FxB"}
|
|
@@ -97,6 +97,7 @@ async function runFixLoop(config, findings, browser, projectRoot) {
|
|
|
97
97
|
baseUrl: config.baseUrl,
|
|
98
98
|
screenshotDir,
|
|
99
99
|
screenshotCounter: 100, // Start at 100 to avoid collisions with Phase 2 screenshots
|
|
100
|
+
qaCommitHashes: new Set(),
|
|
100
101
|
};
|
|
101
102
|
for (const finding of fixable) {
|
|
102
103
|
if (wtf.shouldStop()) {
|
|
@@ -117,7 +118,10 @@ async function runFixLoop(config, findings, browser, projectRoot) {
|
|
|
117
118
|
costUSD += result.costUSD;
|
|
118
119
|
wtf.recordAttempt(result.fix.status, result.fix.filesChanged?.length || 0);
|
|
119
120
|
}
|
|
120
|
-
|
|
121
|
+
// Exclude verified fixes from the post-fix score so it reflects actual remaining issues
|
|
122
|
+
const verifiedIds = new Set(fixes.filter((f) => f.status === 'verified').map((f) => f.findingId));
|
|
123
|
+
const remainingFindings = findings.filter((f) => !verifiedIds.has(f.id));
|
|
124
|
+
const healthScoreAfter = (0, health_score_js_1.computeHealthScore)(remainingFindings);
|
|
121
125
|
return {
|
|
122
126
|
fixes,
|
|
123
127
|
fixesAttempted: fixes.filter((f) => f.status !== 'skipped').length,
|
|
@@ -140,6 +144,7 @@ async function fixSingleFinding(client, model, config, finding, toolCtx) {
|
|
|
140
144
|
let filesChanged = [];
|
|
141
145
|
let beforeScreenshot;
|
|
142
146
|
let afterScreenshot;
|
|
147
|
+
let verifiedFixed = false;
|
|
143
148
|
let status = 'skipped';
|
|
144
149
|
// Take "before" screenshot
|
|
145
150
|
try {
|
|
@@ -182,9 +187,10 @@ async function fixSingleFinding(client, model, config, finding, toolCtx) {
|
|
|
182
187
|
// If no tool use, the agent is done
|
|
183
188
|
const toolUseBlocks = assistantContent.filter((b) => b.type === 'tool_use');
|
|
184
189
|
if (toolUseBlocks.length === 0) {
|
|
185
|
-
// Determine status
|
|
190
|
+
// Determine status: 'verified' requires both a commit and explicit confirmation
|
|
191
|
+
// from verify_in_browser that the bug is gone. A screenshot alone is not proof.
|
|
186
192
|
if (commitHash) {
|
|
187
|
-
status =
|
|
193
|
+
status = verifiedFixed ? 'verified' : 'best-effort';
|
|
188
194
|
}
|
|
189
195
|
break;
|
|
190
196
|
}
|
|
@@ -200,8 +206,13 @@ async function fixSingleFinding(client, model, config, finding, toolCtx) {
|
|
|
200
206
|
if (result.filesChanged) {
|
|
201
207
|
filesChanged = [...filesChanged, ...result.filesChanged];
|
|
202
208
|
}
|
|
203
|
-
if (
|
|
204
|
-
|
|
209
|
+
if (block.name === 'verify_in_browser') {
|
|
210
|
+
if (result.screenshotPath) {
|
|
211
|
+
afterScreenshot = result.screenshotPath;
|
|
212
|
+
}
|
|
213
|
+
if (result.verifiedFixed === true) {
|
|
214
|
+
verifiedFixed = true;
|
|
215
|
+
}
|
|
205
216
|
}
|
|
206
217
|
if (block.name === 'git_revert') {
|
|
207
218
|
status = 'reverted';
|
|
@@ -7,12 +7,16 @@ export interface FixToolContext {
|
|
|
7
7
|
baseUrl: string;
|
|
8
8
|
screenshotDir: string;
|
|
9
9
|
screenshotCounter: number;
|
|
10
|
+
/** Commit hashes created by the fix loop. Only these can be reverted. */
|
|
11
|
+
qaCommitHashes: Set<string>;
|
|
10
12
|
}
|
|
11
13
|
export interface FixToolResult {
|
|
12
14
|
output: string;
|
|
13
15
|
filesChanged?: string[];
|
|
14
16
|
commitHash?: string;
|
|
15
17
|
screenshotPath?: string;
|
|
18
|
+
/** Explicit verification signal from verify_in_browser */
|
|
19
|
+
verifiedFixed?: boolean;
|
|
16
20
|
}
|
|
17
21
|
export declare function executeFixTool(ctx: FixToolContext, name: string, input: Record<string, unknown>): FixToolResult;
|
|
18
22
|
//# sourceMappingURL=fix_tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix_tools.d.ts","sourceRoot":"","sources":["../../../src/qa-agent/phase25/fix_tools.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,4BAA4B,CAAC;AAM7D,eAAO,MAAM,oBAAoB,EAAE,SAAS,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"fix_tools.d.ts","sourceRoot":"","sources":["../../../src/qa-agent/phase25/fix_tools.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,4BAA4B,CAAC;AAM7D,eAAO,MAAM,oBAAoB,EAAE,SAAS,CAAC,IAAI,EAuFhD,CAAC;AAMF,MAAM,WAAW,cAAc;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AA2CD,wBAAgB,cAAc,CAC1B,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,aAAa,CAoJf"}
|
|
@@ -86,14 +86,15 @@ exports.FIX_TOOL_DEFINITIONS = [
|
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
name: 'verify_in_browser',
|
|
89
|
-
description: 'Navigate to a URL
|
|
89
|
+
description: 'Navigate to a URL, take a screenshot, and report whether the fix resolved the issue. You MUST set fixed=true only if the original bug is no longer present. Set fixed=false if the bug still reproduces or if you cannot confirm.',
|
|
90
90
|
input_schema: {
|
|
91
91
|
type: 'object',
|
|
92
92
|
properties: {
|
|
93
93
|
url: { type: 'string', description: 'URL to navigate to for verification' },
|
|
94
94
|
label: { type: 'string', description: 'Label for the screenshot (e.g. "after-fix-001")' },
|
|
95
|
+
fixed: { type: 'boolean', description: 'true if the original bug is gone, false if it still reproduces or uncertain' },
|
|
95
96
|
},
|
|
96
|
-
required: ['url', 'label'],
|
|
97
|
+
required: ['url', 'label', 'fixed'],
|
|
97
98
|
},
|
|
98
99
|
},
|
|
99
100
|
];
|
|
@@ -220,6 +221,7 @@ function executeFixTool(ctx, name, input) {
|
|
|
220
221
|
(0, child_process_1.execFileSync)('git', ['add', ...files], { cwd: ctx.projectRoot, encoding: 'utf-8' });
|
|
221
222
|
(0, child_process_1.execFileSync)('git', ['commit', '-m', message], { cwd: ctx.projectRoot, encoding: 'utf-8' });
|
|
222
223
|
const hash = (0, child_process_1.execFileSync)('git', ['rev-parse', '--short', 'HEAD'], { cwd: ctx.projectRoot, encoding: 'utf-8' }).trim();
|
|
224
|
+
ctx.qaCommitHashes.add(hash);
|
|
223
225
|
return { output: `Committed: ${hash} — ${message}`, commitHash: hash, filesChanged: files };
|
|
224
226
|
}
|
|
225
227
|
catch (err) {
|
|
@@ -228,10 +230,16 @@ function executeFixTool(ctx, name, input) {
|
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
case 'git_revert': {
|
|
233
|
+
// Safety: only revert commits created by the fix loop
|
|
234
|
+
const currentHead = (0, child_process_1.execFileSync)('git', ['rev-parse', '--short', 'HEAD'], { cwd: ctx.projectRoot, encoding: 'utf-8' }).trim();
|
|
235
|
+
if (!ctx.qaCommitHashes.has(currentHead)) {
|
|
236
|
+
return { output: `Blocked: HEAD (${currentHead}) was not created by the fix loop. Refusing to revert a user commit.` };
|
|
237
|
+
}
|
|
231
238
|
try {
|
|
232
239
|
(0, child_process_1.execFileSync)('git', ['revert', '--no-edit', 'HEAD'], { cwd: ctx.projectRoot, encoding: 'utf-8' });
|
|
233
|
-
|
|
234
|
-
|
|
240
|
+
ctx.qaCommitHashes.delete(currentHead);
|
|
241
|
+
const newHash = (0, child_process_1.execFileSync)('git', ['rev-parse', '--short', 'HEAD'], { cwd: ctx.projectRoot, encoding: 'utf-8' }).trim();
|
|
242
|
+
return { output: `Reverted ${currentHead}. New HEAD: ${newHash}`, commitHash: newHash };
|
|
235
243
|
}
|
|
236
244
|
catch (err) {
|
|
237
245
|
const error = err;
|
|
@@ -258,7 +266,9 @@ function executeFixTool(ctx, name, input) {
|
|
|
258
266
|
catch {
|
|
259
267
|
// Not available
|
|
260
268
|
}
|
|
261
|
-
|
|
269
|
+
const fixed = input.fixed === true;
|
|
270
|
+
const verdict = fixed ? 'Bug appears resolved.' : 'Bug still reproduces or unconfirmed.';
|
|
271
|
+
return { output: `Screenshot saved: ${screenshotPath}. ${verdict}${consoleErrors}`, screenshotPath, verifiedFixed: fixed };
|
|
262
272
|
}
|
|
263
273
|
default:
|
|
264
274
|
return { output: `Unknown fix tool: ${name}` };
|
|
@@ -7,8 +7,5 @@ export declare function saveBaseline(outputDir: string, healthScore: HealthScore
|
|
|
7
7
|
* Load a previously saved baseline. Returns null if no baseline exists.
|
|
8
8
|
*/
|
|
9
9
|
export declare function loadBaseline(outputDir: string): RegressionBaseline | null;
|
|
10
|
-
/**
|
|
11
|
-
* Compare current findings against a saved baseline.
|
|
12
|
-
*/
|
|
13
10
|
export declare function compareBaselines(currentScore: HealthScore, currentFindings: Finding[], baseline: RegressionBaseline): RegressionComparison;
|
|
14
11
|
//# sourceMappingURL=baseline.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../../src/qa-agent/regression/baseline.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,oBAAoB,EAAsB,MAAM,aAAa,CAAC;AAKrH;;GAEG;AACH,wBAAgB,YAAY,CACxB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,GAAG,EAAE,MAAM,GACZ,IAAI,CA2BN;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAazE;
|
|
1
|
+
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../../src/qa-agent/regression/baseline.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,oBAAoB,EAAsB,MAAM,aAAa,CAAC;AAKrH;;GAEG;AACH,wBAAgB,YAAY,CACxB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,GAAG,EAAE,MAAM,GACZ,IAAI,CA2BN;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAazE;AAaD,wBAAgB,gBAAgB,CAC5B,YAAY,EAAE,WAAW,EACzB,eAAe,EAAE,OAAO,EAAE,EAC1B,QAAQ,EAAE,kBAAkB,GAC7B,oBAAoB,CAqCtB"}
|
|
@@ -60,18 +60,25 @@ function loadBaseline(outputDir) {
|
|
|
60
60
|
/**
|
|
61
61
|
* Compare current findings against a saved baseline.
|
|
62
62
|
*/
|
|
63
|
+
/**
|
|
64
|
+
* Build a fingerprint for a finding that includes flow, type, and summary
|
|
65
|
+
* to avoid collapsing distinct issues with the same generic summary.
|
|
66
|
+
*/
|
|
67
|
+
function issueFingerprint(issue) {
|
|
68
|
+
return `${issue.flow}|${issue.type}|${issue.summary}`.toLowerCase();
|
|
69
|
+
}
|
|
63
70
|
function compareBaselines(currentScore, currentFindings, baseline) {
|
|
64
|
-
const
|
|
65
|
-
const
|
|
71
|
+
const baselineFingerprints = new Set(baseline.issues.map((i) => issueFingerprint(i)));
|
|
72
|
+
const currentFingerprints = new Set(currentFindings
|
|
66
73
|
.filter((f) => f.type !== 'verified-ok')
|
|
67
|
-
.map((f) => f
|
|
74
|
+
.map((f) => issueFingerprint(f)));
|
|
68
75
|
// Issues in baseline but not in current = fixed
|
|
69
76
|
const fixedIssues = baseline.issues
|
|
70
|
-
.filter((i) => !
|
|
77
|
+
.filter((i) => !currentFingerprints.has(issueFingerprint(i)))
|
|
71
78
|
.map((i) => `${i.id}: ${i.summary}`);
|
|
72
79
|
// Issues in current but not in baseline = new
|
|
73
80
|
const newIssues = currentFindings
|
|
74
|
-
.filter((f) => f.type !== 'verified-ok' && !
|
|
81
|
+
.filter((f) => f.type !== 'verified-ok' && !baselineFingerprints.has(issueFingerprint(f)))
|
|
75
82
|
.map((f) => `${f.id}: ${f.summary}`);
|
|
76
83
|
// Category deltas
|
|
77
84
|
const categoryDeltas = {};
|
package/dist/qa-agent/types.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export interface BrowserAction {
|
|
|
31
31
|
timestamp: number;
|
|
32
32
|
}
|
|
33
33
|
/** Canonical finding categories (v1.1) */
|
|
34
|
-
export type FindingCategory = 'visual' | 'functional' | 'ux' | 'content' | 'performance' | 'console' | 'accessibility';
|
|
34
|
+
export type FindingCategory = 'visual' | 'functional' | 'ux' | 'content' | 'performance' | 'console' | 'accessibility' | 'links';
|
|
35
35
|
/** Legacy finding types kept for backward compatibility */
|
|
36
36
|
export type LegacyFindingType = 'bug' | 'visual-regression' | 'ux-issue' | 'gap' | 'verified-ok';
|
|
37
37
|
/** Accepts both canonical categories and legacy type names */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/qa-agent/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAMpD,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;AAMxD,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAMD,MAAM,MAAM,iBAAiB,GACvB,UAAU,GACV,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,GACP,WAAW,GACX,QAAQ,GACR,MAAM,GACN,SAAS,GACT,YAAY,GACZ,iBAAiB,GACjB,UAAU,GACV,SAAS,GACT,WAAW,GACX,UAAU,GACV,MAAM,GACN,gBAAgB,GAChB,gBAAgB,GAChB,aAAa,GACb,UAAU,GACV,YAAY,CAAC;AAEnB,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACrB;AAMD,0CAA0C;AAC1C,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,GAAG,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/qa-agent/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yasserkhanorg/impact-gate",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Diff-aware E2E impact analysis and coverage gating for Playwright/Cypress teams. Optional AI features can suggest, generate, and heal tests once your project has a route-families.json manifest.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|