Files
waggle-os/docs/audits/2026-07-08-launch-funnel-t13-analysis.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

361 lines
25 KiB
Markdown

# T13 Public Launch Funnel UX Analysis
Status: focused local fixes implemented for signed-out checkout continuation, checkout cancel recovery, the public-site hydration issue badge, legal placeholder/stale-tier copy, the empty-release download dead-end, mobile download label honesty, and the public-site deployment workflow target. Canonical DNS, real signed installer publication, deployed Vercel/DNS proof, deployed Clerk/Stripe proof, and formal legal sign-off remain open launch gates.
Scope: `apps/www`, public download, public pricing, auth handoff, Stripe checkout handoff, checkout cancel recovery, account redirect, legal/trust pages, and launch deployment.
## Why This Matters
The installed cockpit can score well and still fail the complete-product UX goal if a founder, buyer, reviewer, or mobile executive cannot get from the public site to a trustworthy download, account, or checkout path. T13 therefore remains a final-product gate unless the user explicitly scopes the public launch funnel out of the five-persona score.
## Current Evidence
| Check | Result | Notes |
|---|---|---|
| `npm run test -w apps/www -- --reporter=dot` | Pass | Current focused coverage is 7 files / 19 tests: `BrandPersonasCard`, Pricing checkout links/recovery, Stripe checkout route cancel URL, layout hydration contract, legal launch-copy guard, controlled download path, mobile/desktop download label detection, and public-site deployment workflow guard. |
| `npx tsc --noEmit --project apps/www/tsconfig.json` | Pass | No TypeScript errors. |
| `npm run build:www` | Pass | Next.js 15.5.18 build succeeds. Routes include static public pages plus dynamic `/account`, `/api/stripe/checkout`, `/api/webhooks/stripe`, `/sign-in`, and `/sign-up`. Build warns that the Next.js ESLint plugin is not detected. |
| Build/deploy artifact shape | Improved locally | `Test-Path apps/www/dist` = `False`; `Test-Path apps/www/.next` = `True`; `Test-Path apps/www/out` = `False`. `.github/workflows/deploy-www.yml` now uses Vercel production `pull`, `build`, and `deploy --prebuilt --prod` instead of GitHub Pages static artifact upload. Deployed Vercel/DNS proof remains open. |
| Live public domain smoke | Fail | Current external refresh on 2026-07-08: all checked `https://waggle-os.ai/*` URLs failed DNS resolution from this environment; `nslookup waggle-os.ai` returned `Non-existent domain`. |
| Local prod route/API smoke | Improved | Current post-fix `next start --hostname localhost --port 34205` returned 200 for `/`, `/?checkout=cancelled`, and `/docs/methodology`; signed-out `GET /api/stripe/checkout?tier=teams&billing=monthly` returned 303 to sign-in with a checkout redirect target. Historical `/pricing?checkout=cancelled` remains a non-route, but the app no longer emits it from Stripe cancel recovery. |
| Signed-out checkout API/UI smoke | Improved | Pricing now uses the canonical GET checkout route instead of POST, so signed-out users enter the route's auth redirect flow. POST remains a backward-compat JSON shim for older clients. |
| Download target | Improved | Public Download CTAs and footer Product > Download now route to `/download`, a controlled status page that explains Windows/macOS installers are being prepared and links to source/contact instead of an empty GitHub Releases page. Mobile/tablet OS detection now keeps CTAs generic instead of labeling iOS/Android as desktop installers. The release workflow now builds packages before Windows/macOS sidecar packaging, but real signed installer publication remains open. Current production smoke returned 200 for `/download` and found no `releases/latest` target in `/` or `/download`. |
| Fresh rendered Browser smoke | Improved | In-app Browser verified `http://localhost:34204/?checkout=cancelled#pricing`: pricing rendered, cancelled-checkout recovery notice appeared, monthly Team CTA and retry link used `/api/stripe/checkout?tier=teams&billing=monthly`, annual toggle updated both links to annual, the Next dev issue badge disappeared after the layout fix, and console warnings/errors were empty. Browser DOM snapshot still failed with the known `incrementalAriaSnapshot` mismatch, so evidence used targeted DOM evaluation plus screenshots. |
| Web Interface Guidelines lens | Mixed | Latest guideline source checked on 2026-07-08: <https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md>. Public page has skip link, focus-visible outline, reduced-motion handling, semantic sections, explicit image dimensions in key inspected paths, fixed checkout recovery next steps, and guarded legal placeholder copy. Download/release truth, deployed checkout proof, and formal legal sign-off remain outside the local UI copy fix. |
Local smoke output summary:
```text
/ -> 200
/#pricing -> 200
/privacy -> 200
/terms -> 200
/cookies -> 200
/eu-ai-act -> 200
/sign-in -> 200
/sign-up -> 200
/docs/methodology -> 200
/account -> 307 location=/sign-in
/pricing?checkout=cancelled -> 404
/methodology -> 404
GET checkout signed-out -> 303 location=http://localhost:3426/sign-in?redirect_url=%2Fapi%2Fstripe%2Fcheckout%3Ftier%3Dteams%26billing%3Dmonthly
POST checkout signed-out -> 401 body={"message":"Sign in required","signInUrl":"http://localhost:3426/sign-in?redirect_url=%2Fapi%2Fstripe%2Fcheckout%3Ftier%3Dteams%26billing%3Dmonthly"}
```
Live external refresh summary:
```text
https://waggle-os.ai/ -> DNS resolution failed
https://waggle-os.ai/#pricing -> DNS resolution failed
https://waggle-os.ai/pricing?checkout=cancelled -> DNS resolution failed
https://waggle-os.ai/docs/methodology -> DNS resolution failed
https://waggle-os.ai/privacy -> DNS resolution failed
https://waggle-os.ai/terms -> DNS resolution failed
https://waggle-os.ai/cookies -> DNS resolution failed
https://waggle-os.ai/eu-ai-act -> DNS resolution failed
https://waggle-os.ai/sign-in -> DNS resolution failed
https://waggle-os.ai/sign-up -> DNS resolution failed
https://waggle-os.ai/account -> DNS resolution failed
https://api.github.com/repos/marolinik/waggle-os/releases/latest -> 404
https://api.github.com/repos/marolinik/waggle-os/releases -> []
```
Rendered Browser smoke summary:
```text
Build: npm run build:www -> pass; .next dynamic app generated, Next ESLint plugin warning remains
Server: npm run start -w apps/www -- --hostname localhost --port 3491
Browser page identity: http://localhost:3491/ -> title "Waggle — The AI workspace that remembers"
Console health: homepage 0 warnings/errors; pricing checkout-error state 0; mobile menu state 0
Desktop screenshot: output/playwright/www-t13-3491/www-t13-home-desktop.png
Pricing screenshot: output/playwright/www-t13-3491/www-t13-pricing-checkout-error-desktop.png
Mobile screenshots: output/playwright/www-t13-3491/www-t13-home-mobile.png and www-t13-mobile-menu-open.png
Summary JSON: output/playwright/www-t13-3491/www-t13-rendered-summary.json
/pricing?checkout=cancelled -> 404
/methodology -> 404
/docs/methodology -> rendered
Signed-out pricing CTA -> stays on / and shows only "Sign in required"
GET checkout monthly/annual -> 303 to /sign-in with redirect_url
Download CTAs -> https://github.com/marolinik/waggle-os/releases/latest
External refresh: waggle-os.ai and www.waggle-os.ai NXDOMAIN; GitHub latest release 404; releases list []
```
Post-fix focused evidence:
```text
Pricing route contract:
npm run test -w apps/www -- __tests__/Pricing.test.tsx __tests__/stripe-checkout-route.test.ts --reporter=dot
-> 2 files / 3 tests passed
Hydration contract:
npm run test -w apps/www -- __tests__/layout.test.tsx --reporter=dot
-> 1 file / 1 test passed
Public-site suite:
npm run test -w apps/www -- --reporter=dot
-> 7 files / 19 tests passed
TypeScript:
npx tsc --noEmit --project apps/www/tsconfig.json
-> pass
Build:
npm run build:www
-> pass; .next output generated; /download route included; Next ESLint plugin warning remains
Rendered Browser:
http://localhost:34204/?checkout=cancelled#pricing
-> recovery notice visible; monthly Team CTA + retry href = /api/stripe/checkout?tier=teams&billing=monthly
-> annual toggle updates both hrefs to /api/stripe/checkout?tier=teams&billing=annual
-> no Next issue badge after layout suppressHydrationWarning; no console warnings/errors
Local production smoke:
next start --hostname localhost --port 34205
/ -> 200
/?checkout=cancelled -> 200
/docs/methodology -> 200
/api/stripe/checkout?tier=teams&billing=monthly -> 303 to /sign-in?redirect_url=...
Legal copy guard:
npm run test -w apps/www -- __tests__/legal-copy.test.ts --reporter=dot
-> 1 file / 1 test passed
rg -n "Day-0|\[Day-0 launch date\]|Pro or Teams|to be filled before public launch|\[to be designated" 'apps/www/app/(legal)'
-> no matches
Download path:
npm run test -w apps/www -- __tests__/download-path.test.tsx --reporter=dot
-> 1 file / 3 tests passed
rg -n "releases/latest|https://github.com/marolinik/waggle-os/releases" apps/www/app apps/www/messages/en.json apps/www/__tests__
-> no matches
next start --hostname localhost --port 34206
/download -> 200, contains installer-status copy, no releases/latest target
/ -> 200, no releases/latest target
Deployment workflow:
npm run test -w apps/www -- __tests__/deployment-workflow.test.ts --reporter=dot
-> 1 file / 1 test passed
.github/workflows/deploy-www.yml now uses Vercel production pull/build/deploy and no longer references GitHub Pages or apps/www/dist.
Desktop release workflow:
npx vitest run packages/server/tests/tauri-config.test.ts --reporter=dot
-> 1 file / 19 tests passed
.github/workflows/release.yml now runs npm run build:packages before both Windows and macOS sidecar bundle steps.
```
## What Is Already Working
- Homepage IA is coherent: hero, problem, how it works, memory, proof, features, trust, persona brand moment, open source, pricing, and final CTA.
- `page.tsx` includes a skip link and a real `<main id="main">`.
- Navbar anchors use absolute section URLs, so legal pages can navigate back to homepage sections.
- Global CSS provides `:focus-visible`, heading `scroll-margin-top`, and reduced-motion handling.
- Pricing copy now uses Solo/Teams/Enterprise in the main pricing component.
- The newer checkout GET route can redirect signed-out users into sign-in with a return target.
- Pricing now uses that GET route directly for Team checkout, preserving monthly/annual billing in the URL.
- Cancelled checkout returns to the homepage pricing section with an inline recovery notice and retry link.
- Public legal pages no longer expose Day-0 launch placeholders, bracketed launch-date placeholders, retired "Pro or Teams" copy, or the named pre-launch address/representative placeholders caught by the launch-copy guard.
- Public download CTAs no longer send visitors directly to an empty GitHub Releases page; `/download` is a controlled status page until signed installers exist.
- Account page redirects signed-out users before mounting Clerk account UI.
- Fresh rendered desktop/mobile localhost smoke shows no current-page console errors or warnings for homepage, mobile menu, or signed-out checkout-error state.
## Correction Candidates
### T13-0: Public domain does not currently resolve
Evidence:
- Current external smoke from this environment on 2026-07-08 could not resolve `waggle-os.ai`.
- `nslookup waggle-os.ai` returned `Non-existent domain`.
- Fresh refresh also shows `www.waggle-os.ai` has no A or CNAME record from this environment.
- `apps/www/app/layout.tsx:137-141`, `apps/www/app/docs/methodology/page.tsx:36`, `apps/www/app/robots.ts:17`, and `apps/www/app/sitemap.ts:3` treat `https://waggle-os.ai` as canonical production.
Impact:
- A founder, buyer, reviewer, or mobile executive cannot reach the public acquisition, pricing, legal, download, auth, or account surfaces at the canonical domain.
- Local build success does not prove the public launch funnel exists.
Correction:
- Configure DNS for `waggle-os.ai` and deploy the chosen public-site hosting target.
- Run public smoke against the canonical domain after DNS propagation.
- Keep the local `localhost` smoke as a pre-deploy check, not as final launch evidence.
Acceptance:
- `https://waggle-os.ai/`, legal pages, `/docs/methodology`, `/sign-in`, `/sign-up`, `/account`, checkout handoff, and download CTA resolve from a normal network.
- The canonical metadata, sitemap, and robots URL match the deployed host.
### T13-1: Download path is currently broken
Status: empty-release dead-end focused fixed locally; real signed installer publication remains open.
Evidence:
- Historical evidence: `DownloadCTA` and footer Product > Download pointed directly to GitHub Releases latest.
- GitHub currently reports no releases for `marolinik/waggle-os`; live 2026-07-08 refresh confirms `/releases/latest` returns no latest release and the GitHub API releases list is empty.
- Current source evidence: public Download CTAs and the footer Download link route to `/download`.
- Current route evidence: `/download` is a controlled status page explaining that Windows and macOS installers are being prepared, with source/contact actions instead of a direct empty release link.
- Current scan evidence: no `releases/latest` target remains in `apps/www/app`, `apps/www/messages/en.json`, or `apps/www/__tests__`.
- Current source evidence: `apps/www/app/_lib/os-detection.ts` returns `null` for mobile/tablet user agents, `macOS` for desktop Mac, `Windows` for desktop Windows, and `Linux` only for desktop Linux.
- `apps/www/messages/en.json:39` says the product platforms are Windows and macOS.
Impact:
- A founder no longer reaches an empty release page, but still cannot download a signed installer until releases are published.
- Mobile/tablet visitors keep a generic Download CTA, avoiding a false desktop-installer promise.
- A desktop Linux visitor can still see a Linux-specific label even though the public copy says Windows and macOS; this is less damaging now that the CTA leads to a status page, but should be revisited before artifact-specific downloads go live.
Correction:
- Completed locally: point the CTA/footer to a controlled download/status page and add a release-link guard.
- Completed locally: harden the tag release workflow so desktop artifacts build workspace packages before sidecar bundling, matching the PR Tauri verification lane.
- Remaining launch work: publish real signed Windows/macOS release assets and switch `/download` from status page to artifact-aware download page.
- Remaining polish: decide whether desktop Linux should stay generic or be shown as unsupported before signed installers go live.
Acceptance:
- Focused local acceptance met: fresh smoke proves the public CTA leads to a deliberate download landing page, and no supported persona reaches an empty GitHub Releases page from the public CTA.
- Full launch acceptance still requires valid Windows/macOS artifacts and final unsupported-OS copy for non-Windows/non-macOS desktops.
### T13-2: Deployment workflow does not match the current Next app shape
Status: focused fixed locally; deployed Vercel/DNS smoke remains open.
Evidence:
- Historical evidence: `.github/workflows/deploy-www.yml` ran the www build and uploaded `apps/www/dist` to GitHub Pages.
- `apps/www/next.config.mjs:6-13` has no `output: 'export'`.
- Current build output is `.next`, not `dist` or `out`.
- The built app includes dynamic auth/API routes and middleware.
- Current source evidence: `.github/workflows/deploy-www.yml` now installs with `npm ci`, pulls the Vercel production environment, runs public-site tests/typecheck/build, then runs Vercel `build --prod` and `deploy --prebuilt --prod`.
- Current test evidence: `deployment-workflow.test.ts` guards that the workflow contains Vercel production deployment commands and does not reference `upload-pages-artifact`, `deploy-pages`, or `apps/www/dist`.
Impact:
- The prior GitHub Pages workflow could not serve the current app as configured.
- Local source now has a coherent Next-capable deployment path, but external Vercel secrets, DNS, and deployed smoke are not proved by this local fix.
Correction:
- Completed locally: move the workflow to the existing Vercel production architecture for the dynamic Clerk/Stripe Next app.
- Remaining external launch work: configure `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID`, production env vars, domain DNS, and run deployed smoke against `https://waggle-os.ai`.
Acceptance:
- Focused local acceptance met: the checked-in deploy workflow no longer targets GitHub Pages/static artifacts for a dynamic Next app.
- Full launch acceptance still requires a successful production deploy and public smoke covering `/`, legal pages, auth/account routing, checkout route behavior, webhook reachability, and download CTA.
### T13-3: Signed-out Team checkout dead-ends in the pricing UI
Status: focused fixed locally.
Evidence:
- `apps/www/app/api/stripe/checkout/route.ts:213-240` has a GET flow that redirects signed-out users to sign-in.
- `apps/www/app/api/stripe/checkout/route.ts:242-284` keeps a POST compatibility flow returning JSON.
- `apps/www/app/api/stripe/checkout/route.ts:273-276` returns `{ message: 'Sign in required', signInUrl }` for signed-out POST.
- Historical source evidence: the old pricing UI used POST, read only `message` on non-OK responses, and ignored `signInUrl`.
- Historical rendered smoke clicked Annual then Get Team while signed out; the page stayed at `/`, showed only a small `Sign in required` alert, and exposed no sign-in recovery link in the pricing state.
- Current source evidence: `apps/www/app/_components/Pricing.tsx` renders the Team CTA as a link to `/api/stripe/checkout?tier=teams&billing={monthly|annual}`.
- Current rendered Browser evidence: monthly and annual Team links update correctly and signed-out users enter the route-level GET flow.
Impact:
- A buyer clicking Get Team before auth sees implementation-shaped error text instead of continuing to sign-in/sign-up and checkout.
Correction:
- Completed locally: pricing CTA migrated to the canonical GET redirect flow.
- Remaining launch evidence: verify return-to-checkout after a real Clerk sign-in/sign-up session and real Stripe checkout session.
Acceptance:
- Focused local acceptance met: signed-out Get Team starts the auth route instead of showing a dead-end POST error; billing period is preserved in the route URL.
- Full launch acceptance still requires a real signed-in checkout run against deployed auth/Stripe config.
### T13-4: Checkout cancel recovery points to a dead route
Status: focused fixed locally.
Evidence:
- Historical source evidence: `cancel_url` pointed to `/pricing?checkout=cancelled`, but pricing is a section on `/`.
- Historical local and rendered Browser smokes confirmed `/pricing?checkout=cancelled -> 404`.
- Current source evidence: the Stripe cancel URL is `/?checkout=cancelled#pricing`.
- Current test evidence: `stripe-checkout-route.test.ts` verifies the cancel URL passed to Stripe.
- Current rendered Browser evidence: `/?checkout=cancelled#pricing` renders pricing, shows a cancelled-checkout recovery notice, and exposes a retry link that tracks the selected billing period.
Impact:
- A buyer who cancels Stripe checkout can land on a 404 instead of a recoverable pricing state.
Correction:
- Completed locally: use `/?checkout=cancelled#pricing` plus an inline recovery notice and retry action.
Acceptance:
- Focused local acceptance met: cancelled checkout returns to a visible pricing recovery state, not a 404.
- Full launch acceptance still requires a real Stripe cancellation redirect on the deployed site.
### T13-5: Legal and trust pages are not launch-ready
Status: placeholder/stale-tier copy focused fixed locally; formal legal approval remains open.
Evidence:
- Historical evidence: legal pages contained "Day-0 placeholder text", `[Day-0 launch date]`, launch/address placeholders, and Privacy said "upgrade to Pro or Teams".
- Current source evidence: terms/privacy/cookies/EU AI Act pages use July 8, 2026 effective/updated dates, current Solo/Team language, non-placeholder contact/representative wording, and no named launch placeholder patterns.
- Current test evidence: `legal-copy.test.ts` guards against Day-0 placeholder text, launch-date placeholders, pre-launch address placeholders, retired "Pro or Teams" copy, and bracketed representative placeholders.
Impact:
- Team admins, enterprise reviewers, and privacy-conscious founders lose trust before installing when public legal pages expose placeholders or retired tier language.
Correction:
- Completed locally: replaced the named placeholders/stale-tier copy and added a legal-copy guard.
- Remaining launch/legal process: obtain formal Egzakta legal approval for the current text, registered details, and representative wording before treating these pages as legally final.
Acceptance:
- Focused local acceptance met: `legal-copy.test.ts` passes and the targeted `rg` launch-placeholder scan returns no matches.
- Full launch acceptance still requires legal sign-off.
### T13-6: Production smoke needs a stable browser lane
Evidence:
- Current HTTP route/API smoke passes for core routes when using `--hostname localhost`.
- Earlier rendered smoke found `127.0.0.1` binding failures and Clerk development/session-loop warning noise.
- The fresh Browser smoke exercises homepage, mobile menu, signed-out pricing CTA, checkout redirect API, and route recovery. It does not exercise Clerk modal browser behavior, signed-in checkout, or real Stripe return.
Impact:
- A route-only smoke can miss the exact UI failures buyers hit: modal auth, return-to-checkout, console warning loops, mobile nav, and visual layout.
Correction:
- Add a repeatable public-site Playwright/browser smoke using the known-good `localhost` host binding.
- Cover desktop and mobile: homepage, mobile menu, download CTA, sign-in/sign-up pages, account redirect, signed-out checkout, checkout cancel, legal pages, and methodology.
Acceptance:
- Fresh screenshots and route/API logs are attached with no unexpected 404, 500, timeout, or auth-loop noise.
### T13-7: Coverage is too narrow for a launch funnel
Evidence:
- `apps/www/__tests__` currently covers only `BrandPersonasCard`.
- Historical coverage gap: no checked-in route E2E, checkout-recovery test, legal placeholder guard, release/download target guard, or deployment artifact guard was found.
- Current local improvement: checkout recovery, legal placeholder/stale-tier, release/download target, mobile download-label, and deployment workflow guards now exist. Deployed-domain smoke, real checkout, signed installer publication, and formal legal sign-off remain open.
Impact:
- The public site can regress in the exact flows needed for acquisition and purchase while tests stay green.
Correction:
- Add focused tests/guards:
- Download CTA target and platform labels.
- Signed-out checkout auth continuation.
- Checkout cancel recovery route.
- Legal placeholder/stale-tier grep.
- Deployment artifact/hosting mode consistency.
- Public route smoke in CI or release checklist.
Acceptance:
- `npm run test -w apps/www`, www typecheck, www build, and the public funnel smoke all pass from a clean checkout.
## Five-Persona Impact
| Persona | Cap Until Fixed | Why |
|---|---:|---|
| Solo founder/operator | 5/10 | Canonical public domain does not resolve; local Download no longer dead-ends, but there is still no signed installer artifact to obtain. |
| Team admin/security reviewer | 5/10 | Public legal/pricing/account pages are unreachable at the canonical domain; deployment target, formal legal sign-off, and real signed-in checkout evidence remain launch blockers. |
| Mobile executive | 5/10 | Mobile cannot inspect the canonical public site; mobile download labels are honest locally, but signed download/release truth still needs fixing after deploy. |
| Engineer/power user | 6/10 | Local site is credible, but NXDOMAIN plus no signed release artifact and deploy mismatch make the product look unreleasable. |
| Privacy/compliance reviewer | 6/10 | Public legal pages no longer expose the named placeholder/stale-tier copy locally, but canonical-domain reachability and formal legal sign-off still block launch trust. |
## Approval Recommendation
Keep T13 outside Phase 1 implementation, but do not treat it as optional for the final 9/10 complete-UX goal. After the installed-app P0s are approved and fixed, run T13 as a launch-readiness slice with this order:
1. Make `waggle-os.ai` resolve and deploy the selected public-site target.
2. Publish signed installer artifacts behind the controlled `/download` path.
3. Fix deploy target or hosting architecture.
4. Verify real deployed Clerk sign-in/sign-up return-to-checkout and Stripe cancel/success redirects.
5. Complete formal legal sign-off for public legal/trust copy.
6. Add the public funnel smoke and remaining minimal guards.
T13 can be deferred only if the user explicitly says the five-persona judge score is limited to the installed desktop cockpit and excludes the public acquisition/payment/legal funnel.