From a6db53f8353b43762960d5a5bceeba343b14638d Mon Sep 17 00:00:00 2001 From: haelyra <49814733+haelyra@users.noreply.github.com> Date: Tue, 20 Oct 2026 18:41:19 -0400 Subject: [PATCH] fix(inspection): normalize diagnostic-looking Windows filenames --- scripts/lib/inspection.js | 2 +- tests/lib/inspection.test.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/lib/inspection.js b/scripts/lib/inspection.js index 1e24df064..931af086a 100644 --- a/scripts/lib/inspection.js +++ b/scripts/lib/inspection.js @@ -27,7 +27,7 @@ function normalizeFailureReason(reason) { // Directories may contain spaces, but trailing whitespace separates diagnostic prose. // Unquoted spaced leaves allow one final dotted token; longer prose stays diagnostic. // Quote paths with multiple spaces in the final filename to remove ambiguity. - .replace(/(?:\b[a-z]:|\\)[\\/](?:[^\\/:*?"<>|\r\n]*[^\s\\/:*?"<>|][\\/])*[^\s\\/:*?"<>|(),;]+(?: (?!failed\b|timed\b|could\b|cannot\b|unable\b|error\b)[^\s\\/:*?"<>|]+\.[^\s\\/:*?"<>|]+(?=:))?[\\/]*/gu, '') + .replace(/(?:\b[a-z]:|\\)[\\/](?:[^\\/:*?"<>|\r\n]*[^\s\\/:*?"<>|][\\/])*[^\s\\/:*?"<>|(),;]+(?: [^\s\\/:*?"<>|]+\.[^\s\\/:*?"<>|]+(?=:))?[\\/]*/gu, '') // Strip remaining file paths .replace(/(?:\b[a-z]:)?[\\/][\w./\\-]+/g, '') // Collapse whitespace diff --git a/tests/lib/inspection.test.js b/tests/lib/inspection.test.js index 80082b25b..7ded26cd1 100644 --- a/tests/lib/inspection.test.js +++ b/tests/lib/inspection.test.js @@ -185,6 +185,24 @@ async function runTests() { assert.strictEqual(groupFailures(runs).size, 2); })) passed += 1; else failed += 1; + if (await test('groups Windows filenames with diagnostic-looking words', async () => { + const reasons = [ + String.raw`Command C:\work\app error.log: permission denied`, + String.raw`Command D:\work\app output.log: permission denied`, + String.raw`Command E:\work\my failed-test.js: permission denied`, + ]; + assert.deepStrictEqual(reasons.map(normalizeFailureReason), [ + 'command : permission denied', + 'command : permission denied', + 'command : permission denied', + ]); + const runs = reasons.map((failureReason, index) => makeSkillRun({ id: `filename-${index}`, failureReason })); + assert.strictEqual(groupFailures(runs).size, 1); + const patterns = detectPatterns(runs); + assert.strictEqual(patterns.length, 1); + assert.strictEqual(patterns[0].count, 3); + })) passed += 1; else failed += 1; + if (await test('groupFailures handles mixed outcome casing', async () => { const runs = [ makeSkillRun({ id: 'r1', outcome: 'FAILURE', failureReason: 'timeout' }),