# Cache-First Anti-Pattern Audit Instructions ## Goal Scan the codebase for places where `ndkFetchEvents` is called in a way that blocks rendering or user-visible UI when cached data could be used instead. Report each finding so a developer can apply the cache-first fix. --- ## Background Read `docs/cache-first-page-patterns.md` first. It explains the three data APIs: - `queryCache(filters)` — fast, local IndexedDB, 5s timeout - `ndkFetchEvents(filters)` — slow, relay network, 15s timeout - `subscribe(filters, opts)` — live streaming, no timeout The rule: **never `await ndkFetchEvents(...)` in the critical render path if the data could exist in cache.** Instead, use `queryCache` first, render immediately, then fire-and-forget `ndkFetchEvents` for background hydration. --- ## What to Search For ### Pattern 1: `await ndkFetchEvents(...)` in page HTML files Search all `www/*.html` files for: ``` await ndkFetchEvents( ``` For each match, determine: - Is this in the main initialization flow (inside `main()` or the top-level IIFE)? - Is there a `queryCache` call before it for the same or similar filter? - Could the data plausibly exist in IndexedDB cache (i.e., it was fetched before on a previous page load)? **Report as a finding if**: `await ndkFetchEvents` is called without a preceding `queryCache` for the same data, and the result is used to render UI that the user sees. **Exclude**: Cases where `ndkFetchEvents` is used with `void` (fire-and-forget) or inside a `.then()` chain — those are already non-blocking. ### Pattern 2: `await ndkFetchEvents(...)` in shared modules Search all `www/js/*.mjs` files for: ``` await ndkFetchEvents ``` or ``` await ndkFetchEventsFn ``` For each match, determine: - Is this function called during page initialization or rendering? - Does the module have access to a `queryCache` / `queryCacheFn` function? - If not, is `queryCache` being passed through the dependency chain from the page? **Report as a finding if**: A module-level function awaits `ndkFetchEvents` without first trying cache, AND the module does not have `queryCacheFn` available. ### Pattern 3: Missing `queryCache` in dependency threading Search all `www/js/*.mjs` files for functions that accept a deps/options object containing `ndkFetchEvents`: ``` ndkFetchEvents ``` in destructuring patterns like `const { ndkFetchEvents, ... } = deps;` For each match, check: - Does the same destructuring also include `queryCache`? - If the function forwards deps to another module, does it forward `queryCache` too? **Report as a finding if**: A function destructures `ndkFetchEvents` from a deps object but does NOT also destructure `queryCache`. ### Pattern 4: Pages that import `ndkFetchEvents` but not `queryCache` Search all `www/*.html` files for import statements from `init-ndk.mjs`: ``` import { ``` Check whether the import includes both `ndkFetchEvents` and `queryCache`. **Report as a finding if**: A page imports `ndkFetchEvents` but does NOT import `queryCache`. --- ## Files to Scan ### HTML pages (check all): - `www/*.html` ### JavaScript modules (check all): - `www/js/*.mjs` ### Specifically check these known integration points: - `www/js/post-interactions.mjs` — embed hydration, interaction fetching - `www/js/post-interactions2.mjs` — dependency forwarding - `www/js/mute-list.mjs` — mute list loading - `www/js/profile-cache.mjs` — profile resolution - `www/js/blossom-ui.mjs` — blossom server loading - `www/js/relay-ui.mjs` — relay status loading - `www/js/zaps.mjs` — zap-related fetches - `www/js/utilities.mjs` — utility functions that may fetch --- ## Output Format For each finding, report: ``` FILE: www/example.html (or www/js/example.mjs) LINE: 123 PATTERN: [1|2|3|4] — [brief description] CODE: `await ndkFetchEvents({ kinds: [1], ... })` CONTEXT: [What this code does — e.g., "fetches user's kind 1 posts for feed render"] SEVERITY: [HIGH if it blocks visible UI, MEDIUM if it blocks secondary content, LOW if it's a dep threading gap] FIX HINT: [e.g., "Add queryCache call before this, render from cache, make this fire-and-forget"] ``` --- ## What NOT to Flag - `void ndkFetchEvents(...)` — already fire-and-forget, correct pattern - `ndkFetchEvents(...)` inside `.then()` chains — already non-blocking - `await ndkFetchEvents(...)` for `publishEvent` confirmation — must await - `ndkFetchEvents` used only in background refresh intervals (e.g., `setInterval`) - `subscribe(...)` calls — these are already event-driven