Reuse completed cache entries for the rest of a request (#96727)
Calling the same `'use cache: private'` function twice in one request
executed its body twice in production. Preloading at the top of a
segment and reading the same function again lower down for
composability, which is the shape that motivates a preload in the first
place, therefore did the work twice instead of once.
The intra-request dedupe map dropped an entry as soon as its fill
completed, so it only ever covered concurrent invocations. A later
invocation fell through to the cache handler, and the `React.cache` memo
wrapping every cache function missed whenever the arguments were not
reference-equal. Public caches got a handler hit out of that, but
private caches have no handler in production and their entries are
excluded from the immutable Resume Data Cache of a dynamic request, so
nothing had stored the entry.
Completed invocations now move into `completedCacheInvocations` on the
work store instead of being dropped, and a later invocation joins that
entry. The pending map keeps its previous semantics untouched, because a
concurrent joiner shares a fill that is genuinely in flight and must not
re-run the discard checks against it, whereas a completed entry is a
stored value and is only reused when the caller has not asked to bypass
caches and nothing has invalidated it since. Private caches still get no
cache handler, so the map is what backs them, and it lives on the work
store and so cannot carry request-derived data beyond the request that
produced it.
Retention is limited to the kinds where it saves real work: private
caches, and kinds whose handler came from the platform or from
`cacheHandlers` config, where a read can be a network round trip.
`isBuiltInCacheHandler` answers that by tracking the handler instances
`initializeCacheHandlers` constructs itself. Recording instances rather
than kinds is what keeps aliasing right, since a self-hosted `remote`
resolves to the very same in-memory handler as `default` and retaining
its entries would duplicate that cache for nothing, while a
platform-supplied `remote` does not.
The `use-cache-custom-handler` suite covers the mechanism rather than
the observable value, counting `::get` calls to assert that two
sequential reads reach the handler once. Value equality alone cannot
distinguish a retained entry from a handler hit, which is also why the
new `dedup-sequential` fixture passes without this change and serves
only as a regression pin next to `private-dedup-sequential`.