[backport] Discard only cache entries that predate a tag revalidation, and reuse completed entries (#97314)
Backports #96726 ("Discard only cache entries that predate a tag
revalidation") and #96727 ("Reuse completed cache entries for the rest
of a request") to `next-16-3`.
Calling `updateTag()` in a server action made every later read of a
cache carrying that tag regenerate for the remainder of the request,
including reads of an entry that had just been generated after the
invalidation and therefore already reflected it. Two sequential reads of
the same cache function during the re-render produced two different
values within a single render, and each one repeated the work.
`isRecentlyRevalidatedTag` only asked whether a tag appeared in
`pendingRevalidatedTags`, and that array lives for the whole
`WorkStore`, which spans a server action and the render that follows it.
Each pending revalidated tag now records a `revalidatedAt` timestamp
taken from the same clock as `CacheEntry.timestamp`, and the renamed
`isRevalidatedAfter` reports an entry as stale only when the
revalidation is newer than the entry.
The second change fixes a `'use cache: private'` function executing its
body twice when it is called twice in one request, which defeats the
preload-then-read shape that motivates a preload in the first place. The
intra-request dedupe map dropped an entry as soon as its fill completed,
so it only ever covered concurrent invocations, and private caches have
no cache handler in production to fall back to. Completed invocations
now move into `completedCacheInvocations` on the work store instead of
being dropped.
The two are backported together because #96727 builds on the discard
checks that #96726 restructures. They were stacked in this order on
canary, and #96727 conflicts in
`test/e2e/app-dir/use-cache/use-cache.test.ts` when applied alone.
### Verification on this branch
Cherry-picked from `5da1c1ae03` and `1ff6a80358` in that order, with no
conflicts. All source files are byte-identical to canary. Behavioral
verification is left to CI on this branch; the changes carry the
`action-dedupe`, `dedup-sequential` and `private-dedup-sequential`
fixtures in the `use-cache` suite, and a handler-call count assertion in
`use-cache-custom-handler`.
<!-- NEXT_JS_LLM -->