Skip to content

BACK-465 - Detect and warn about duplicate task IDs#632

Open
brooksc wants to merge 1 commit into
MrLesk:mainfrom
brooksc:back-465-duplicate-task-id-detection
Open

BACK-465 - Detect and warn about duplicate task IDs#632
brooksc wants to merge 1 commit into
MrLesk:mainfrom
brooksc:back-465-duplicate-task-id-detection

Conversation

@brooksc
Copy link
Copy Markdown
Contributor

@brooksc brooksc commented May 3, 2026

Summary

  • Adds duplicate task ID detection across web browser, TUI board, and MCP task_list
  • Duplicate IDs occur when two git branches independently create tasks with the same number and are later merged — one copy is silently dropped
  • New utility detectDuplicateTaskIds(tasks) + buildDuplicateCleanupPrompt(groups) in src/utils/duplicate-detection.ts

Web browser interface

  • Amber dismissible warning banner appears at the top when duplicates are present
  • Lists each duplicate group (ID + task titles)
  • "Copy AI fix prompt" button copies a ready-to-use prompt describing the duplicates and asking an AI to renumber them

TUI board

  • Startup warning message shown in the footer bar for 15 seconds listing the affected IDs

MCP task_list

  • Prepends a ⚠️ WARNING block to the tool output including the AI cleanup prompt when duplicates exist

Test plan

  • 9 unit tests in src/test/duplicate-detection.test.ts cover: empty input, all-unique, two duplicates, multiple groups, case-insensitivity, 3-way duplicates, prompt content
  • bunx tsc --noEmit passes
  • biome check passes on all changed files
  • bun test passes (1 pre-existing flaky failure in parallel-loading.test.ts unrelated to this change)

🤖 Generated with Claude Code

…MCP interfaces

When two git branches independently create tasks with the same numeric ID
and are then merged, the duplicate is silently dropped. This adds detection
and user-facing warnings across all three surfaces:

- Web browser: amber dismissible banner listing duplicate groups with a
  "Copy AI fix prompt" button that provides a ready-to-use prompt
- TUI board: 15-second startup warning in the footer listing affected IDs
- MCP task_list: prepends a ⚠️ warning block with the AI cleanup prompt

Detection runs against the raw filesystem task list (before Map dedup)
so duplicates aren't lost before they can be reported.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@brooksc
Copy link
Copy Markdown
Contributor Author

brooksc commented May 3, 2026

Context: how this actually happened

I was working on a separate project that uses Backlog.md for task management with multiple AI agents. The project has a GitHub remote and I work on it from one machine. I usually use Parallel Code, but briefly used Conductor which updates the origin vs. Paralell Code updating local main.

The exact sequence that caused the duplicates:

  1. At 10:53am, one AI session created TASK-123 "In-app LLM setup guidance..." directly on the remote main branch and pushed it to GitHub.
  2. At 12:11pm, a separate local AI session — which hadn't pulled from GitHub recently — computed the next available task ID by scanning the local filesystem, saw that TASK-122 was the highest, and created TASK-123 "Fix handlePermissionLost..." locally.
  3. At 12:49pm, a git merge of remote main brought both files into the working tree. Because the filenames are different (task-123 - In-app-LLM...md vs task-123 - Fix-handlePermissionLost...md), git merged them without conflict. Both files now exist on disk.

Why it went unnoticed for a while:

Backlog.md's Core.loadTasks() uses a Map<string, Task> keyed by task ID, so one of the two TASK-123 files is silently dropped on every load. The AI agents working via MCP only ever saw one of the tasks. The other existed on disk but was invisible.

How I eventually noticed:

I opened backlog browser (the web UI) and saw a task state that didn't match what my AI assistant had been reporting through MCP — tasks the AI thought were "To Do" appeared differently, and one task the AI had been referencing seemed to not exist in the board. After some confusion I ran find .backlog/tasks -name "task-123*" and found two files with the same ID.

The same situation affected TASK-081 (two separate agents had created tasks with that number at different points before a merge).

Why Backlog.md's existing dedup-prevention didn't catch it:

Backlog.md already has a proper-lockfile locking mechanism and scans remote git branches when generating new task IDs — both of which prevent concurrent creation within a single machine. But neither helps when two completely independent git histories diverge and are later merged: each session legitimately believed it was assigning the next available ID at the time.

@brooksc
Copy link
Copy Markdown
Contributor Author

brooksc commented May 3, 2026

The failing test (ContentStore > removes decisions when files are deleted) is unrelated to this PR.

Our changes touch: src/utils/duplicate-detection.ts, src/server/index.ts, src/ui/board.ts, src/ui/unified-view.ts, src/web/App.tsx, src/web/components/DuplicateIdWarning.tsx, src/web/components/Layout.tsx, src/web/lib/api.ts, src/mcp/tools/tasks/handlers.ts. None of these files are ContentStore, the decisions subsystem, or the file watcher.

The test itself deletes a file on disk and then waits for a filesystem watch event to propagate within a platform-dependent timeout. It failed at 5026ms, which is right at the timeout boundary — a classic sign of CI environment I/O latency rather than a code regression. The test passes consistently when run locally and in isolation (bun test src/test/content-store.test.ts).

lenucksi added a commit to lenucksi/Backlog.md that referenced this pull request May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant