private ChainSpecification flatten(Resolver<ChainSpecification> allChainSpecifications,
                                             Deque<ComponentId> path) {
        path.push(componentId);

        //if this turns out to be a bottleneck(which I seriously doubt), please add memoization
        Map<String, ComponentSpecification> resultingComponents = componentsByName(componentReferences);
        Map<String, Phase> resultingPhases = new LinkedHashMap<>(phases);


        for (ComponentSpecification inheritedChainSpecification : inheritance.chainSpecifications) {
            ChainSpecification inheritedChain =
                    resolveChain(path, allChainSpecifications, inheritedChainSpecification).
                            flatten(allChainSpecifications, path);

            mergeInto(resultingComponents,
                    filterByComponentSpecification(
                            filterByName(inheritedChain.componentReferences, names(componentReferences)),
                            inheritance.excludedComponents));
            mergeInto(resultingPhases, inheritedChain.phases);
        }

        path.pop();
        return new ChainSpecification(componentId, inheritance.flattened(), resultingPhases.values(),
                new LinkedHashSet<>(resultingComponents.values()));
    }
@param allChainSpecifications resolves ChainSpecifications from ComponentSpecifications
                              as given in the inheritance fields.
@param path tracks which chains are used in each recursive invocation of flatten, used for detecting cycles.
@return ChainSpecification directly containing all the component references and phases of the inherited chains.
container-core/src/main/java/com/yahoo/component/chain/model/ChainSpecification.java