Find Duplicate Ownership
Overview
Audit the codebase for multiply-owned rules instead of blindly grepping normalize.
Classify each case as real SSOT drift, local dedupe cleanup, legitimate boundary work, or legitimate domain constraint.
Workflow
Define the audit target before searching.
Narrow by feature, contract, package, service, or file slice when possible.
Good targets: session state, persistence contracts, runtime geometry, provider options, path helpers, JSON canonicalization.
Build a taxonomy first.
Use these buckets:
architecture / SSOT bug: same business rule owned in more than one layer
local dedupe cleanup: same helper semantics copied nearby
legitimate boundary adapter: wire, vendor, or untrusted input transformation with one clear owner
legitimate domain constraint: runtime clamp, math, security, or path logic that cannot be removed architecturally
Search for ownership smells, not words.
Look for:
- validation, defaults, or clamps duplicated across frontend and backend
- generated bindings or shared type aliases hiding the real contract owner
- runtime mutators calling boundary repair or coercion
- persisted shape differing from runtime shape and requiring glue
- query, store, or cache logic re-owning domain policy
- two helpers with the same semantics but different names
- thin wrapper functions that hide a second path
- copied deterministic serializers or hash inputs
- local component, hook, or service helper clones instead of one domain owner
Separate true duplicates from valid boundaries.
Do not flag these by default:
- pure UI formatting or presentation transforms
- provider or protocol adapters with one clear boundary owner
- security or path canonicalization with one clear security owner
- runtime-only clamp or math logic with one clear runtime owner
For each finding, name the winning owner.
Always answer:
- what exact rule is multiply owned
- who owns it today
- who should own it
- what gets deleted in a hard cut
- whether anything remains as real boundary adapter code
Heuristics
- Be suspicious when frontend and backend both shape or repair the same contract.
- Be suspicious when trusted runtime state is "normalized" after every mutation.
- Be suspicious when query glue, cache glue, or store glue maps between two supposedly canonical state shapes.
- Be suspicious when multiple languages or services define the same min, max, enum, or default constants independently.
- Be suspicious when a helper exists in a domain library and again in a hook, component, controller, or service.
Subagent Use
Only use subagents when the user explicitly asks for them or asks for parallel exploration.
Reusable read-only agent definitions live in this skill's agents/ directory:
ownership-taxonomy-mapper.toml
Use first for broad slice mapping and taxonomy.
duplicate-ownership-explorer.toml
Use one per independent slice: persistence, runtime state, contracts, helpers, adapters.
ssot-judge.toml
Use after explorers when you need one strict verdict on winning owner and hard-cut cleanup.
Recommended fan-out:
- 1 taxonomy mapper
- 2 to 5 explorers for disjoint slices
- 1 SSOT judge to merge and challenge findings
Tell subagents:
- stay read-only
- cite files and symbols
- do not propose compatibility shims
- distinguish duplicate ownership from legitimate boundary work
- return winner owner plus delete or keep plan
Output Contract
For each finding, return:
- severity
- rule or contract being multiply owned
- competing owners
- why it is a duplicate-owner bug or why it is legitimate boundary work
- exact files or symbols
- recommended single owner
- hard-cut cleanup:
- classification:
- architecture / SSOT bug
- local dedupe cleanup
- legitimate boundary adapter
- legitimate domain constraint
Order findings by severity, then finish with a prioritized backlog by impact versus effort.
Prompting
Use prompt patterns from references/audit-prompts.md.
Guardrails
- Do not reduce the audit to
rg normalize.
- Do not flag every adapter or clamp as bad architecture.
- Do not recommend wrappers, fallbacks, shims, or dual paths.
- Prefer deleting the losing owner, not introducing a mediator.
- If ownership is ambiguous because the diff is mixed or the contract is unclear, say so explicitly.
1---2name: find-duplicate-ownership3description: Find duplicate ownership, hidden second sources of truth, and contract drift in layered codebases. Use when reviewing normalization, validation, defaulting, canonicalization, persistence mapping, runtime-vs-durable state, duplicated helpers, query or cache ownership, or any "who owns this rule?" architecture question. Especially useful for SSOT audits across frontend, backend, shared core, and adapter layers, and when the user explicitly asks for duplicate-ownership exploration with subagents.4---5
6# Find Duplicate Ownership
7
8## Overview
9
10Audit the codebase for multiply-owned rules instead of blindly grepping `normalize`.
11Classify each case as real SSOT drift, local dedupe cleanup, legitimate boundary work, or legitimate domain constraint.
12
13## Workflow
14
151. Define the audit target before searching.
16 Narrow by feature, contract, package, service, or file slice when possible.
17 Good targets: session state, persistence contracts, runtime geometry, provider options, path helpers, JSON canonicalization.
18
192. Build a taxonomy first.
20 Use these buckets:
21 - `architecture / SSOT bug`: same business rule owned in more than one layer
22 - `local dedupe cleanup`: same helper semantics copied nearby
23 - `legitimate boundary adapter`: wire, vendor, or untrusted input transformation with one clear owner
24 - `legitimate domain constraint`: runtime clamp, math, security, or path logic that cannot be removed architecturally
25
263. Search for ownership smells, not words.
27 Look for:
28 - validation, defaults, or clamps duplicated across frontend and backend
29 - generated bindings or shared type aliases hiding the real contract owner
30 - runtime mutators calling boundary repair or coercion
31 - persisted shape differing from runtime shape and requiring glue
32 - query, store, or cache logic re-owning domain policy
33 - two helpers with the same semantics but different names
34 - thin wrapper functions that hide a second path
35 - copied deterministic serializers or hash inputs
36 - local component, hook, or service helper clones instead of one domain owner
37
384. Separate true duplicates from valid boundaries.
39 Do not flag these by default:
40 - pure UI formatting or presentation transforms
41 - provider or protocol adapters with one clear boundary owner
42 - security or path canonicalization with one clear security owner
43 - runtime-only clamp or math logic with one clear runtime owner
44
455. For each finding, name the winning owner.
46 Always answer:
47 - what exact rule is multiply owned
48 - who owns it today
49 - who should own it
50 - what gets deleted in a hard cut
51 - whether anything remains as real boundary adapter code
52
53## Heuristics
54
55- Be suspicious when frontend and backend both shape or repair the same contract.
56- Be suspicious when trusted runtime state is "normalized" after every mutation.
57- Be suspicious when query glue, cache glue, or store glue maps between two supposedly canonical state shapes.
58- Be suspicious when multiple languages or services define the same min, max, enum, or default constants independently.
59- Be suspicious when a helper exists in a domain library and again in a hook, component, controller, or service.
60
61## Subagent Use
62
63Only use subagents when the user explicitly asks for them or asks for parallel exploration.
64
65Reusable read-only agent definitions live in this skill's `agents/` directory:
66
67- `ownership-taxonomy-mapper.toml`
68 Use first for broad slice mapping and taxonomy.
69- `duplicate-ownership-explorer.toml`
70 Use one per independent slice: persistence, runtime state, contracts, helpers, adapters.
71- `ssot-judge.toml`
72 Use after explorers when you need one strict verdict on winning owner and hard-cut cleanup.
73
74Recommended fan-out:
75
76- 1 taxonomy mapper
77- 2 to 5 explorers for disjoint slices
78- 1 SSOT judge to merge and challenge findings
79
80Tell subagents:
81
82- stay read-only
83- cite files and symbols
84- do not propose compatibility shims
85- distinguish duplicate ownership from legitimate boundary work
86- return winner owner plus delete or keep plan
87
88## Output Contract
89
90For each finding, return:
91
921. severity
932. rule or contract being multiply owned
943. competing owners
954. why it is a duplicate-owner bug or why it is legitimate boundary work
965. exact files or symbols
976. recommended single owner
987. hard-cut cleanup:
99 - delete
100 - keep
101 - rename
1028. classification:
103 - architecture / SSOT bug
104 - local dedupe cleanup
105 - legitimate boundary adapter
106 - legitimate domain constraint
107
108Order findings by severity, then finish with a prioritized backlog by impact versus effort.
109
110## Prompting
111
112Use prompt patterns from [references/audit-prompts.md](references/audit-prompts.md).
113
114## Guardrails
115
116- Do not reduce the audit to `rg normalize`.
117- Do not flag every adapter or clamp as bad architecture.
118- Do not recommend wrappers, fallbacks, shims, or dual paths.
119- Prefer deleting the losing owner, not introducing a mediator.
120- If ownership is ambiguous because the diff is mixed or the contract is unclear, say so explicitly.