feat(CF-450): Check completed tasks on task creation to avoid circular work
Enhanced task_add to search both open AND completed tasks when checking for duplicates. Previously only checked non-completed tasks. **Changes:** - Removed `status != 'completed'` filter from similarity search - Increased search limit from 3 to 5 tasks - Separated display: open tasks vs previously completed - Show 150-char context snippet from completed task descriptions - Suggest using "task show <id>" to see full solution **Benefits:** - Prevents recreating already-solved tasks - Surfaces solutions from previous attempts - Reduces circular work on recurring issues - Maintains context from closed tasks **Example output:** ``` ⚠️ Similar tasks found: **Open/In Progress:** - CF-442: Next.js cache issue (92% match, open) **Previously Completed:** - CF-378: Pre-test validation (85% match) Context: "Created comprehensive pre-test quality validation workflow..." 💡 Use "task show <id>" to see full solution before recreating work ``` Fixes: CF-450 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -95,14 +95,15 @@ export async function taskAdd(args: TaskAddArgs): Promise<string> {
|
||||
const embeddingValue = embedding ? formatEmbedding(embedding) : null;
|
||||
|
||||
// Check for similar/duplicate tasks (only if embedding succeeded)
|
||||
// CF-450: Check both open AND completed tasks to avoid circular work
|
||||
let duplicateWarning = '';
|
||||
if (embeddingValue) {
|
||||
const similarTasks = await query<{ id: string; title: string; status: string; similarity: number }>(
|
||||
`SELECT id, title, status, 1 - (embedding <=> $1) as similarity
|
||||
const similarTasks = await query<{ id: string; title: string; status: string; description: string; similarity: number }>(
|
||||
`SELECT id, title, status, description, 1 - (embedding <=> $1) as similarity
|
||||
FROM tasks
|
||||
WHERE project = $2 AND embedding IS NOT NULL AND status != 'completed'
|
||||
WHERE project = $2 AND embedding IS NOT NULL
|
||||
ORDER BY embedding <=> $1
|
||||
LIMIT 3`,
|
||||
LIMIT 5`,
|
||||
[embeddingValue, projectKey]
|
||||
);
|
||||
|
||||
@@ -110,11 +111,35 @@ export async function taskAdd(args: TaskAddArgs): Promise<string> {
|
||||
const highSimilarity = similarTasks.filter(t => t.similarity > 0.70);
|
||||
if (highSimilarity.length > 0) {
|
||||
duplicateWarning = '\n\n⚠️ Similar tasks found:\n';
|
||||
for (const t of highSimilarity) {
|
||||
|
||||
const openTasks = highSimilarity.filter(t => t.status !== 'completed');
|
||||
const completedTasks = highSimilarity.filter(t => t.status === 'completed');
|
||||
|
||||
if (openTasks.length > 0) {
|
||||
duplicateWarning += '\n**Open/In Progress:**\n';
|
||||
for (const t of openTasks) {
|
||||
const pct = Math.round(t.similarity * 100);
|
||||
duplicateWarning += ` - ${t.id}: ${t.title} (${pct}% match, ${t.status})\n`;
|
||||
}
|
||||
duplicateWarning += '\nConsider linking with: task link <from> <to> relates_to';
|
||||
}
|
||||
|
||||
if (completedTasks.length > 0) {
|
||||
duplicateWarning += '\n**Previously Completed:**\n';
|
||||
for (const t of completedTasks) {
|
||||
const pct = Math.round(t.similarity * 100);
|
||||
duplicateWarning += ` - ${t.id}: ${t.title} (${pct}% match)\n`;
|
||||
|
||||
// Show snippet of solution/outcome from description
|
||||
if (t.description) {
|
||||
const snippet = t.description.substring(0, 150).replace(/\n/g, ' ').replace(/"/g, '\\"');
|
||||
const ellipsis = t.description.length > 150 ? '...' : '';
|
||||
duplicateWarning += ` Context: "${snippet}${ellipsis}"\n`;
|
||||
}
|
||||
}
|
||||
duplicateWarning += '\n 💡 Use "task show <id>" to see full solution before recreating work\n';
|
||||
}
|
||||
|
||||
duplicateWarning += '\nConsider linking with: task link <new-id> <related-id> relates_to';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user