fileCacheValidator: hasYdoc && !isLive rows now validate as
y<YDOC_CONVERT_EPOCH>:<ydocTag> (revision-0 collab-only rows included); live
rows and untagged older backends stay uncacheable. The remote source caches
the CONVERTED KiCad text — a warm load skips the download and the measured
~2s-class ydoc→s-expr conversion — and the unconvertible-ydoc plain fallback
is cached under the same tag, ending the stale-ydoc double-fetch. A ydoc
response under a revision-form validator (room appeared mid-listing) stays
uncached, preserving the old race guard exactly.
Measured (Arduino Leonardo, dev stack): cold 52 file GETs → warm reload 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLSht9cadprtT2mhynawWu
Step 1: warm platform loads stop re-downloading every project file. New
project-file-cache.ts (raw IDB, best-effort) keyed by the listing's
revision:updatedAt validator — the pair, not revision alone, because the resave
equivalent-body swap keeps revision but touches updatedAt. Listing row threaded
through fetchFileBytes(slug, path, meta?); ydoc-backed and revision-0 files are
never cached; prune runs on every fresh listing.
Step 2: cdnLibsSource marks its tag-pinned static layers immutable — warm demo
loads skip all ~155 per-lib manifest GETs (bumps pcbjam-shared for the
LayerDescriptor.immutable flag).
docs/features/load-path-rework/0001 steps 1-2.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLSht9cadprtT2mhynawWu