Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions web/src/kernel/scheduled/issue-watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ const LABEL_TO_CATEGORY: Record<string, { category: string; authority: 'auto_saf
refactor: { category: 'refactor', authority: 'proposed' },
};

// Labels that signal multi-session scope — these issues are human-driven
// and should NOT be auto-queued as single-session taskrunner tasks.
// See aegis-daemon/artifacts/taskrunner-scope-process.md for the scope gate.
const SKIP_LABELS = new Set(['wishlist', 'roadmap', 'epic']);
// Labels that signal the issue should NOT be auto-queued as a single-session taskrunner task:
// - wishlist / roadmap / epic: multi-session, human-driven scope (see aegis-daemon/artifacts/taskrunner-scope-process.md)
// - blocked: cannot proceed until listed blockers close; operator removes the label when unblocked
const SKIP_LABELS = new Set(['wishlist', 'roadmap', 'epic', 'blocked']);

function classifyIssue(labels: string[]): { category: string; authority: 'auto_safe' | 'proposed' } | null {
for (const label of labels) {
Expand Down
12 changes: 12 additions & 0 deletions web/tests/issue-watcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,18 @@ describe('runIssueWatcher scope label filter', () => {
expect(insertCalls).toHaveLength(0);
});

it('skips issue with blocked label', async () => {
const db = createMockDb();
const issue = makeIssue({ labels: ['refactor', 'blocked'] });
mockListIssues.mockResolvedValueOnce([issue]);

await runIssueWatcher(makeEnv(db));

const insertCalls = (db.prepare as ReturnType<typeof vi.fn>).mock.calls
.filter((c: string[]) => typeof c[0] === 'string' && c[0].includes('INSERT INTO cc_tasks'));
expect(insertCalls).toHaveLength(0);
});

it('skip label filter is case-insensitive', async () => {
const db = createMockDb();
const issue = makeIssue({ labels: ['bug', 'WISHLIST'] });
Expand Down
Loading