# Capability Spec: dedup **Package**: `@suaveplan/dedup` **Version**: 0.0.0 (genesis) **Status**: ADDED --- ## ADDED Requirements ### DD-01 — Match keys `MatchKey` MUST be `{ field, extract?, normaliser?, weight }`. The engine MUST support multiple match keys per config and combine their contributions by weighted sum, normalised to `[0, 1]`. ### DD-02 — Similarity primitives `exactMatch(a, b)` MUST be `a === b`. `levenshteinDistance` MUST compute edit distance in O(|a|·|b|). `jaroWinklerSimilarity` MUST return a value in `[0, 1]`. `computeSimilarity(a, b, rules)` MUST apply the configured `ScoringRule[]` and return a composite score in `[0, 1]`. ### DD-03 — Detect contract `DedupEngine.detect(entities, config)` MUST return `DuplicateGroup[]` where each group has `{ representative, members, scores }`. Every entity MUST belong to at most one group. Entities below `config.threshold` MUST NOT be grouped. ### DD-04 — Merge strategies `latestWinsStrategy` MUST pick the entity with the most recent `updatedAt`. `manualStrategy` MUST defer to the caller via a resolver callback. `scoredMergeStrategy` MUST merge fields per-field using the highest-scored source. All strategies MUST return `MergeResult { merged, sources }`. ### DD-05 — Observability Every `detect` call MUST record `dedup.detect.duration_ms` histogram and `dedup.groups.total` counter. Every merge MUST record `dedup.merge.total{strategy}`. ### DD-06 — Configuration validation `DedupConfig` MUST be validated via Zod. Invalid configs MUST surface as `DEDUP.INVALID_CONFIG`.