# Deep diagnosis - AI Coding Pricing residual launch issues

- URL: https://aicodingpricing.com
- Commit checked: d40f5d8e32612bc634f0d88e7ae6037cbd32ad73
- Owner gate: t_b76bcb40
- Date: 2026-05-21 UTC

## Verdict

The remaining launch risk is narrower than the owner gate wording suggests:

1. Mobile LCP is a real flaky/perf-risk item, but not consistently failing. A fresh Lighthouse run once passed at 2159 ms, then three repeat mobile runs failed at 3580-3636 ms. Treat as unstable P1, not a deterministic P0.
2. support@ is configured correctly at DNS + Cloudflare Email Routing level. The only missing proof is an end-to-end real inbox receipt, which requires sending a test email and checking xjtumj@gmail.com.
3. Newsletter is intentionally frontend-only. There is a committed API/data contract, but no implementation route/function/backend storage. Treat as scope gap, not a broken feature, if launch scope is SEO/content validation.
4. Re-run Lighthouse also exposed small non-blocking hygiene issues: newsletter provider select lacks accessible label, mobile menu summary accessible name mismatch, llms.txt lacks markdown links per Lighthouse's new llms check.

## Evidence artifacts

- Existing Re-QA Lighthouse: `reports/final-reqa-lighthouse-home.json`
- Existing Re-QA summary: `reports/final-reqa-lighthouse-summary.json`
- Fresh diagnostic Lighthouse run: `reports/deep-diagnosis-lighthouse-home-mobile.json`
- Repeat runs: `reports/deep-diagnosis-lighthouse-repeat-1.json`, `reports/deep-diagnosis-lighthouse-repeat-2.json`, `reports/deep-diagnosis-lighthouse-repeat-3.json`

## 1. P1 Mobile LCP

### Observed numbers

- Existing Re-QA: LCP 3582.932 ms, Performance 0.87, FCP 1812.594 ms, TBT 50 ms, CLS 0.
- Fresh run: LCP 2159.0075 ms, Performance 0.99, FCP 964.0075 ms.
- Repeat run 1: LCP 3635.5635 ms, Performance 0.87, FCP 1839.526 ms.
- Repeat run 2: LCP 3588 ms class, Performance 0.87.
- Repeat run 3: LCP 3580 ms class, Performance 0.87.

### LCP element

Lighthouse identifies the LCP node as the homepage H1:

- selector: `main.page > header#main > div > h1`
- node label: `Compare AI coding tool costs before you upgrade`
- bounding box at mobile 412px: left 16, right 396, top 159, bottom 275, 380 x 116

This is not an image problem. It is above-the-fold text render timing.

### Timing breakdown

Failing Re-QA run:

- TTFB: 36.881 ms
- Element render delay: 2227.327 ms
- CSS render-blocking saving estimate: ~150 ms
- Total transfer: ~249 KiB
- Main thread: ~1.0s, with Style/Layout ~397 ms and script evaluation ~261 ms

Repeat failing run:

- TTFB: ~48 ms
- Element render delay: ~2299 ms

Passing fresh run:

- TTFB: ~48 ms
- Element render delay: ~240 ms

Conclusion: network/server is not the bottleneck. The variance is mostly browser-side render delay for the H1.

### Likely root causes

- H1 uses `Space Grotesk` via `next/font/google`:
  - `src/app/layout.tsx` imports `Space_Grotesk` and sets `display: "optional"`.
  - `src/app/globals.css` uses `font:700 76px/.92 var(--font-display),'Space Grotesk'` for `.hero h1`, reduced to 42px at <=430px.
  - Output HTML preloads two font files before CSS/JS.
- The page ships multiple Next scripts and a client-side calculator above the fold:
  - Largest unused JS finding: `_next/static/chunks/0m_p1bxtorv5i.js`, ~70 KiB transferred, ~28 KiB unused.
  - `CostCalculator` is a client component rendered inside the hero, so hydration/JS is part of the critical path even though the LCP element is text.
- CSS is a single render-blocking stylesheet. Savings are only ~150 ms, so inlining CSS alone will not fix the 1.0s+ gap.
- H1 is large/tight on mobile: 42px, line-height .92, letter-spacing -.055em. This is visually okay but makes the H1 the stable LCP candidate.

### Recommended fix path

Minimum safe fix:

1. Make hero H1 use a system font stack on mobile or globally for LCP text, e.g. avoid `Space Grotesk` for `.hero h1` at mobile.
2. Remove or reduce `Space_Grotesk` above-fold dependency, or stop preloading display font if it remains non-critical.
3. Consider splitting/defer the calculator client bundle below initial paint:
   - render a static calculator shell first, hydrate controls after idle; or
   - move the interactive calculator below the first viewport on mobile; or
   - dynamically import the calculator with a lightweight SSR fallback.
4. Keep mobile H1 under the current 116px height; do not increase text size.
5. Re-test with 5 mobile Lighthouse runs and require p75 < 2500 ms, not a single lucky pass.

Expected impact:

- Font/system-stack change should remove most H1 render-delay variance.
- Calculator deferral reduces JS/layout work and improves p75 stability.

## 2. P2 support@ real receipt proof

### Verified

Cloudflare Email Routing is configured and ready:

- zone: `aicodingpricing.com`
- routing enabled: true
- status: ready
- synced: true
- DNS MX:
  - `route1.mx.cloudflare.net`, priority 32
  - `route3.mx.cloudflare.net`, priority 52
  - `route2.mx.cloudflare.net`, priority 62
- SPF TXT: `v=spf1 include:_spf.mx.cloudflare.net ~all`
- DKIM TXT exists at `cf2024-1._domainkey.aicodingpricing.com`
- rule enabled:
  - matcher: literal `to = support@aicodingpricing.com`
  - action: forward to `xjtumj@gmail.com`

### Not verified

No real message has been sent through the full path:

external sender -> Cloudflare MX -> Cloudflare Email Routing -> xjtumj@gmail.com inbox/spam

### Why this remains P2

DNS/API can prove configuration, not inbox delivery. Gmail can still classify to spam, delay, or reject a forwarded test under specific sender/auth conditions.

### Recommended verification

Needs owner approval because this is an external email send/check:

- Send one test email to `support@aicodingpricing.com` with unique subject, e.g. `AICP support routing test 2026-05-21 <timestamp>`.
- Check `xjtumj@gmail.com` inbox and spam for the unique subject.
- Record screenshot/message headers if available.

## 3. P2 newsletter capture-shell

### Current implementation

File: `src/components/NewsletterForm.tsx`

- Prevents default submit.
- Validates email locally.
- Tracks `newsletter_submit` events.
- Stores only `{ provider, email_domain, ts }` in browser `localStorage` key `aicp_newsletter_requests`.
- Displays success copy explicitly saying backend is not connected.

There is no server route:

- `src/app/api/**/route.ts`: not present.
- No Pages Function found.
- No provider integration found for Resend/Mailchimp/Beehiiv/etc.

### Existing contract but no backend

File: `src/data/newsletter-schema.json`

- Defines intended `POST /api/newsletter/subscribe` and `POST /api/newsletter/unsubscribe` contract.
- Defines possible `newsletter_subscribers` SQL schema.

File: `src/data/frontend-contract.json`

- says backend is optional for P0: `Static JSON + client-side calculator + optional Pages Function for newsletter subscribe. D1 only if newsletter/changelog admin route is implemented; no auth/payment.`

### Why this remains P2

The UX is honest and no longer misleading, but it cannot collect subscribers across users/devices. It only stores a local browser validation queue.

### Recommended fix if we want real capture before launch

Implement a minimal Cloudflare Pages Function or Next route compatible with static export deployment:

- endpoint: `/api/newsletter/subscribe`
- storage: Cloudflare D1 table `newsletter_subscribers`
- fields: email hash or email, provider interest, source path, consent text, subscribed_at, status
- privacy: update Privacy Policy with storage/provider details
- anti-abuse: basic rate limit / honeypot / turnstile later if spam starts
- frontend: submit to API, show `subscribed` / `already_subscribed` / error states

If we do not want backend before launch, keep it as a clearly scoped validation CTA and do not present it as a real mailing list.

## 4. Extra hygiene found during deeper Lighthouse run

These are not in the owner gate summary but are cheap to fix while touching the frontend:

1. `src/components/NewsletterForm.tsx`: provider `<select name="provider">` lacks accessible label. Add `aria-label="Provider interest"` or wrap it in a label.
2. `src/components/SiteChrome.tsx`: mobile menu summary has visible text `Menu` but accessible name `Toggle navigation`, triggering label-content-name-mismatch. Change aria-label to include `Menu`, e.g. `aria-label="Menu / toggle navigation"`, or remove aria-label.
3. `/llms.txt`: Lighthouse says file has no links. The file is 200 and content exists, but add Markdown links to canonical/sitemap/core routes to satisfy recommendation.

## Recommended owner decision after diagnosis

- If this is a soft SEO/content launch: `APPROVE_WITH_WAIVER` is still acceptable, but record that LCP is unstable and newsletter is not a real subscriber backend.
- If this is going to broad outreach / paid distribution: choose `FIX_BEFORE_LAUNCH` focused on:
  1. mobile H1/font/calculator LCP stabilization,
  2. newsletter provider select accessibility label,
  3. llms.txt markdown links,
  4. optional real newsletter API if subscriber capture matters.

Support@ should not block launch if DNS/API config is enough; it only needs a one-email live receipt confirmation before publishing support address broadly.
