Merge pull request #3684 from Tibsfox/fix/mark-note-captures-executed

fix(gsd): mark note captures as executed in triage resolution
This commit is contained in:
Jeremy McSpadden 2026-04-07 07:04:52 -05:00 committed by GitHub
commit 864c8e7c2a
3 changed files with 58 additions and 1 deletions

View file

@ -0,0 +1,46 @@
/**
* Regression test for #3578 note captures marked as executed
*
* Note-classified captures were stuck in "resolved but not executed" limbo
* because executeTriageResolutions only handled inject/replan/defer. The fix
* adds a filter for classification === "note" and calls markCaptureExecuted
* for each matching capture.
*
* Structural verification test reads source to confirm the note filter
* and markCaptureExecuted call exist.
*/
import { describe, test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const source = readFileSync(join(__dirname, '..', 'triage-resolution.ts'), 'utf-8');
describe('note captures executed in triage resolution (#3578)', () => {
test('markCaptureExecuted is imported', () => {
assert.match(source, /markCaptureExecuted/,
'markCaptureExecuted should be imported');
});
test('note classification filter exists', () => {
assert.match(source, /classification\s*===\s*"note"/,
'filter should check classification === "note"');
});
test('note filter checks resolved status and not-executed', () => {
assert.match(source, /status\s*===\s*"resolved"\s*&&\s*!c\.executed\s*&&\s*c\.classification\s*===\s*"note"/,
'filter should check resolved + not-executed + note classification');
});
test('markCaptureExecuted is called for note captures', () => {
// The source should call markCaptureExecuted for note captures
const noteSection = source.slice(source.indexOf('classification === "note"'));
assert.match(noteSection, /markCaptureExecuted\(basePath,\s*cap\.id\)/,
'markCaptureExecuted should be called for note captures');
});
});

View file

@ -387,7 +387,8 @@ test("resolution: executeTriageResolutions handles mixed classifications", () =>
assert.strictEqual(result.injected, 1, "should inject 1 task");
assert.strictEqual(result.replanned, 0);
assert.strictEqual(result.quickTasks.length, 1, "should queue 1 quick-task");
assert.strictEqual(result.actions.length, 2, "should have 2 action entries (note/defer excluded)");
// inject + quick-task + note acknowledged = 3 actions (defer still excluded)
assert.strictEqual(result.actions.length, 3, "should have 3 action entries (defer excluded, note now included)");
} finally {
rmSync(tmp, { recursive: true, force: true });
}

View file

@ -510,6 +510,16 @@ export function executeTriageResolutions(
}
}
// Mark note captures as executed — they're informational only, no action
// needed. Without this they stay in "resolved but not executed" limbo (#3578).
const notes = loadAllCaptures(basePath).filter(
c => c.status === "resolved" && !c.executed && c.classification === "note",
);
for (const cap of notes) {
markCaptureExecuted(basePath, cap.id);
result.actions.push(`Note acknowledged: ${cap.id} — "${cap.text}"`);
}
if (actionable.length === 0) return result;
for (const capture of actionable) {