# Issue Families — Cross-Agent Dedup Map

When the same underlying issue is flagged by multiple sub-agents under different rule IDs, the orchestrator collapses them in **Phase C2 Pass 2**. This file is the source of truth for that mapping.

Each family lists the canonical name plus the member rule IDs that should be treated as the same issue when they apply to the same file. (Line numbers can differ — the same PK-missing problem might point to the YAML line for one agent and the SQL line for another.)

## Family table

| Family | Member rules | Notes |
|---|---|---|
| `pk-test-missing` | `logic-pk-test-missing`, `primary-key-tests`, `target-structure-testing-rule-violation` (when about a fact/dim PK), `kimball-dim-surrogate-key` (when about a missing surrogate key on a fact/dim) | The single most common multi-agent overlap. Four different rule IDs for "this fact/dim has no `unique`+`not_null` test on its grain". |
| `non-additive-on-fact` | `kimball-non-additive-measure-stored`, `kimball-facts-not-flagged-additivity` | Non-additive measure stored as a fact column AND missing additivity annotation are the same root issue. |
| `dim-pluralization-vs-kimball` | `consistent-pluralization` (when about dim tables), `kimball-dim-naming`, `kimball-vs-style-conflict` | Style guide ↔ Kimball naming conflict. |
| `cross-layer-skip` | `no-cross-layer-skip` (Gemma), `kimball-reporting-skips-analytics-layer` | Reporting/marts model selecting from base/staging directly. |
| `freshness-deprecated` | `logic-deprecated-source-freshness-property`, `source-freshness` (when the violation is specifically the dbt 1.10+ top-level `freshness:` deprecation, not a missing freshness block) | dbt 1.10+ top-level `freshness:` migration. |

## How the orchestrator applies the table

For each family:

1. Collect all findings whose `rule` matches a member of that family AND whose `file` matches another finding's `file`.
2. Pick the highest-severity finding as canonical.
3. Append a line to its `details`: `"Also reported as: <rule-id> (<agent>) at <file>:<line>"` for each related finding.
4. Remove the related findings from the rendered report. Keep them in the raw findings JSON for traceability.

If a finding's rule appears in the table but no other finding in the same family matches its `file`, leave it alone — it's a genuine standalone finding.

## Extending this table

This table will grow as new sub-agents land or new validators are added. When you add a new rule that overlaps with an existing one:

1. Add the new rule to the appropriate family row, OR
2. Add a new family row if no existing family captures the issue.

Keep family names kebab-case and short. The `Notes` column should explain the family's scope so future contributors don't accidentally pull in unrelated rules.

## What this table is NOT

- **Not a severity-override map.** Each agent picks its own severity. The orchestrator uses the highest one when collapsing; it does not re-grade.
- **Not a way to suppress findings.** A collapsed finding is still in the report — just consolidated. To suppress a check, use `skipped_checks` from within the sub-agent.
- **Not a substitute for the defer-rule overlap (C2 Pass 3).** Pass 3 handles naming-vs-grain overlaps that aren't a true issue-family match.
