Problem
CollisionResolvedTechPack (in DestinationCollisionResolver.swift) is a decorator that wraps any TechPack and overrides components while forwarding all other protocol members to inner.
If TechPack gains a new requirement without a default implementation, the compiler catches it — CollisionResolvedTechPack won't compile until it forwards the new member. This is safe.
However, if TechPack gains a new requirement with a default implementation (in a protocol extension), CollisionResolvedTechPack silently uses the default instead of forwarding to inner. If the wrapped pack overrides that default, the override is lost.
This is an inherent limitation of the decorator pattern in Swift — there is no auto-forwarding mechanism.
Mitigation Options
- Convention: Add a comment in
TechPack.swift reminding contributors to update CollisionResolvedTechPack when adding new protocol members with defaults
- Test: Add a compile-time or runtime check that
CollisionResolvedTechPack forwards all protocol members (e.g., a test that creates a mock with non-default values and verifies they survive wrapping)
- Alternative design: Replace the decorator with a mutable property on
ComponentDefinition or a post-processing step that doesn't require wrapping
Current State
TechPack has 3 members with default implementations:
templateSectionIdentifiers — explicitly forwarded in wrapper ✓
templateValues(context:) — explicitly forwarded in wrapper ✓
declaredPrompts(context:) — explicitly forwarded in wrapper ✓
All defaults are currently forwarded, so there is no bug today. The risk is future additions.
References
Sources/mcs/Install/DestinationCollisionResolver.swift:131-177 — CollisionResolvedTechPack
Sources/mcs/TechPack/TechPack.swift:51-89 — TechPack protocol + extensions
Problem
CollisionResolvedTechPack(inDestinationCollisionResolver.swift) is a decorator that wrapsany TechPackand overridescomponentswhile forwarding all other protocol members toinner.If
TechPackgains a new requirement without a default implementation, the compiler catches it —CollisionResolvedTechPackwon't compile until it forwards the new member. This is safe.However, if
TechPackgains a new requirement with a default implementation (in a protocol extension),CollisionResolvedTechPacksilently uses the default instead of forwarding toinner. If the wrapped pack overrides that default, the override is lost.This is an inherent limitation of the decorator pattern in Swift — there is no auto-forwarding mechanism.
Mitigation Options
TechPack.swiftreminding contributors to updateCollisionResolvedTechPackwhen adding new protocol members with defaultsCollisionResolvedTechPackforwards all protocol members (e.g., a test that creates a mock with non-default values and verifies they survive wrapping)ComponentDefinitionor a post-processing step that doesn't require wrappingCurrent State
TechPackhas 3 members with default implementations:templateSectionIdentifiers— explicitly forwarded in wrapper ✓templateValues(context:)— explicitly forwarded in wrapper ✓declaredPrompts(context:)— explicitly forwarded in wrapper ✓All defaults are currently forwarded, so there is no bug today. The risk is future additions.
References
Sources/mcs/Install/DestinationCollisionResolver.swift:131-177—CollisionResolvedTechPackSources/mcs/TechPack/TechPack.swift:51-89—TechPackprotocol + extensions