Skip to content

Dedupe same-fingerprint investigation tasks across federated peers#2818

Merged
atomantic merged 4 commits into
mainfrom
next/issue-2628
Jul 20, 2026
Merged

Dedupe same-fingerprint investigation tasks across federated peers#2818
atomantic merged 4 commits into
mainfrom
next/issue-2628

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Two federated peers can each create an investigation task for the same metadata.investigationFingerprint before the next sync sweep. The per-process fingerprint dedup added in #2615 is serialized on a module-level promise tail, so a single install never mints two open investigations for one failure cause — but cosTaskMerge.js unions cross-peer records by id, so both peers' rows survive synchronization.

This adds a deterministic, side-independent dedup pass at the peer-merge boundary in server/services/cosTaskMerge.js (a new rule 4, run after the existing per-id union). For each investigationFingerprint group with more than one OPEN copy it:

  • Picks one survivor deterministically so both peers converge on the same active row: an in_progress copy wins outright (an agent is running it — never orphan an in-flight investigation); otherwise the lower-id / older copy wins. When more than one copy is in_progress, the collapse is skipped for that sweep (both run to completion and the group self-heals as each turns terminal).
  • Unions metadata.affectedTasks (deduped, sorted) onto the survivor, and mirrors the peer-contributed ids into the survivor's description (idempotent, deterministic) so the investigation agent/user — and the isReapableInvestigation reaper — see every task blocked on the cause, matching the local same-fingerprint path in agentErrorAnalysis.
  • Flips the other open copies to completed with a supersededBy marker rather than deleting them (LWW sync never propagates deletions; a terminal status converges via the existing rule-2 status rank). The supersededBy marker keeps the pass idempotent and lets a mid-propagation partial survivor re-fold the full union.

The no-orphan guard keys on the in_progress status (which replicates via rule-2 rank) rather than lease liveness, so a peer whose lease timestamp is stale still recognizes an actively-worked copy. "Open" matches agentErrorAnalysis.OPEN_INVESTIGATION_STATUSES (pending/in_progress/challenged/blocked), so two blocked same-cause copies are collapsed too. The residual pre-claim-snapshot race across ≥3 peers is documented and accepted (investigation tasks are approval-gated diagnostics that execute nothing on their own; the storm is already bounded to one per peer per cause).

Test plan

  • cd server && npm test -- cosTaskMerge — 43 tests pass, including new coverage proving two same-fingerprint tasks from two peers converge to one active row (both sweep directions), the in_progress-survivor no-orphan case (including a stale/expired-lease copy), both-in-progress skip, affectedTasks union dedupe, blocked+blocked and blocked+pending collapse, description mirroring + idempotency, and re-fold after a partial per-id revert.
  • cd server && npm test -- cosTask agentErrorAnalysis peerSync — 606 related federation/task tests pass (no regression).

Reviewed locally with claude, ollama, and codex (series). claude flagged that keying the no-orphan guard on lease liveness was stale-prone across 3+ peers (fixed → status-based); codex flagged that blocked investigations escaped the terminal filter and that merged affected tasks weren't surfaced in the survivor's description (both fixed).

Closes #2628

@atomantic
atomantic merged commit a04dae9 into main Jul 20, 2026
2 checks passed
@atomantic
atomantic deleted the next/issue-2628 branch July 20, 2026 02:24
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.

Investigation-task fingerprint dedup does not hold across federated peers

1 participant