Patch families were introduced in Windows Installer 3.0 as a means to sequence patches even if applied in any order, and to supersede previous patches. Supersedence allows for easier delta patching and allows more patches to be installed than the 127 limit.
When we started developing the new patch build support in Windows Installer XML (WiX) 3.0, we overloaded the concept of patch families to filter resources in a transform. By adding references to symbols to a PatchFamily element, that symbol and all other elements in the same fragment are left in the authoring transform. Every other difference between the target and upgrade products are removed. Effectively, this is like removing everything you didn’t specify in the target and upgrade products, then building a transform between the two databases. Using tools like PatchWiz.dll, this was the only way to create a patch that included only a subset of changes.
Patch families at build time are used as a logical grouping of resources. But once the patch is built, resources really belong to all patch families. Remember that a patch package is really just a collection of transforms and zero or more cabinets; and that when applying a patch to a product, the first applicable authoring transform is applied to a product individually. Even if a patch applies to multiple products, each product is transformed separately. If taking advantage of the multi-product transaction feature shipping in Windows Installer 4.5, installation scripts are still generated per-product and merely executed sequentially in a single transaction.
So because patches are applied to a product individually and sequenced and superseded all in relation to that product, all patch families affect sequencing and supersedence with other patches applied to that product. Patch families are attributes of a patch, and there is no relationship in a patch package to resource changes in a transform.
Consider product MSIa which contains a.dll, and product MSIb which contains b.dll. A patch is built that applies to both products. In the patch source file, file resource a.dll is added to patch family PFa, and file resource b.dll is added to patch family PFb. The resulting .msp patch package contains both patch families PFa and PFb. Now when that patch is applied to product MSIa, both patch families PFa and PFb are considered when sequencing and superseding. In a debug Windows Installer log, you can see this at the top of the log before the requested ACTION is even started.
To put it another way, the resource changes are defined in a transform to a product while the patch families are defined in a patch. Patches are sequenced with other patches for an individual product, and once the patch applicability and order are determined then the applicable transforms within those remaining patches are applied to the product in the order of the patches.
Why is this important?
For one reason, if you build a multi-product patch like in the example above but later build a single-product patch with just one of the patch families, the newer single-product patch will not supersede the older multi-product patch. You have to supersede all patch families in previously sequenced patches to supersede that patch. Now, effectively you’ve updated the same resources in the target product but both patches are still registered. This will likely only be a problem if you install so many patches you exceed the 127 patch limit or are trying to apply delta patches to the same file resources.
Another reason is that if you moved a.dll to patch family PFb and installed the same multi-product patch to product MSIa, a previous patch containing only patch family PFa will not sequence correctly with the new patch containing only patch family PFb. At least one patch family must be common between patches for them to sequence correctly in relationship to each other. Moving a resource from one patch family to another effectively shrinks one patch family, and patch families should only ever grow; though, defining new, unique patch families is recommended for flexibility.
So remember that patch family definitions at build time affect what changes are kept in a transform, while all patch families in a patch at install time affect sequencing and supersedence with other patches applied to a single product.