# PHASE 13: PERFORMANCE PASS

Read `CLAUDE.md` section 5 and `docs/05-TECHNICAL-ARCHITECTURE.md` section 5.

## Scope

Measure, then fix. Do not tune blind. This phase is a measurement discipline, not a list of tricks.

**Run this on staging, not locally** (decision D-24). LiteSpeed does not exist on a Docker container, and items 9 through 12 are meaningless without it.

## Build

1. **Baseline first.** Lighthouse mobile, throttled 4G, on homepage, a category page and a product page. Record LCP, CLS, INP, total transfer, CSS, JS and request count. Write the numbers into `docs/PROGRESS.md`. Every later claim in this phase is measured against these.
2. Verify the dequeues from phase 3 actually took effect in production conditions: no `wp-block-library`, no `wc-blocks-style`, no WooCommerce layout CSS, no `wc-cart-fragments`, no jQuery on non-Woo pages, no `zoom`, `flexslider` or `photoswipe`.
3. Confirm the cart-count REST call fires zero times for an empty-cart visitor.
4. Images: verify exactly four registered sizes exist, `srcset` and `sizes` are correct on cards and gallery, WebP is being served, the hero and first gallery image are eager with `fetchpriority="high"` and preloaded, and everything below the fold is lazy. Every image has explicit `width` and `height` or an aspect-ratio wrapper.
5. Critical CSS: confirm the right file inlines per template and that the main stylesheet loads non-blocking.
6. Fonts: two families, four faces, WOFF2, Latin subset, self-hosted, `font-display: swap`, only two preloaded, under 60 KB total. No `fonts.gstatic.com` request.
7. Database: audit autoloaded options (`SELECT SUM(LENGTH(option_value)) FROM wp_options WHERE autoload='yes'`), must be under 800 KB. Confirm `WP_POST_REVISIONS` and `EMPTY_TRASH_DAYS`. Confirm Action Scheduler retention is shortened to 14 days.
8. Query count per page. If any template runs more than 60 queries, find and cache the offender. All homepage rails and category counts should be behind 12 hour transients purged on `save_post`.
9. **LiteSpeed Cache configuration**, exactly as specified in technical architecture section 5. Turn the aggressive options on **one at a time and retest checkout after each**. Combine off. UCSS off. Guest Mode and Guest Optimization on.
10. Verify cache exclusions: `/cart`, `/checkout`, `/my-account`, `/track-order`, `/wc-api`, and the two WooCommerce cookies.
11. Cache warming: **do not rely on the LiteSpeed crawler.** Namecheap shared plans disable it at the server level and the plugin will show it greyed out. Write a short PHP script run by cPanel cron nightly that reads the sitemap and `wp_remote_get`s the top 100 URLs, one every two seconds.
12. Set up Cloudflare free in front, proxied, with page rules that bypass cache on `/checkout`, `/cart`, `/my-account` and `/wp-admin`.
    **Note what this does to DNS**: once Cloudflare is authoritative, the SPF, DKIM and DMARC records in launch runbook step 9 are added at Cloudflare, not in the Namecheap DNS panel. Decide before launch whether Cloudflare goes in at phase 13 on the staging domain or at phase 15 on the live one, and record the choice, because the runbook wording assumes Namecheap DNS.
13. Re-run Lighthouse. Record the after numbers next to the before.

## Acceptance criteria

- [ ] Homepage: LCP under 2.5s, CLS under 0.05, INP under 200ms, transfer under 900 KB, CSS under 60 KB, JS under 90 KB
- [ ] Product page: LCP under 2.5s, CLS under 0.05, transfer under 800 KB, CSS under 60 KB, JS under 110 KB
- [ ] Category page within budget
- [ ] Zero `admin-ajax.php` requests on a normal page load
- [ ] Zero cart-count requests for an empty-cart visitor
- [ ] Autoloaded options under 800 KB
- [ ] No template exceeds 60 queries
- [ ] A cached page returns an `x-litespeed-cache: hit` header, and `/checkout` never does
- [ ] Checkout still works with every LiteSpeed option enabled. Test it after each one.
- [ ] Before and after numbers recorded in `docs/PROGRESS.md`

## Stop

If a fix would break checkout or variation behaviour, do not ship it. Report it instead. A fast site that cannot take an order is worth nothing.
