For example, a pre-fetch linked to a speculative execution would be tagged with a CPU-specific speculative execution identifier such that the pre-fetched data would only be accessible in that pipeline. If that speculative execution becomes realized then the tag would be updated (perhaps to zero?) to show it was actually executed and visible to all other CPUs and caches. In all other cases, the speculative execution is abandoned and the tagged cache cells become marked as available and undefined. Circuitry similar to register renaming could be used to handle tagging in the caches at the cost of effectively halving cache sizes.
In a more macro sense, imagine git branches that get merged back into main. The speculative execution only occurs on the branch. When the CPU realizes the prediction was good and doesn't need to rolled back, the branch is merged into the trunk and becomes visible to all other systems having access to the trunk.