# E2e

> Forensic end-to-end test of an entire Next.js + Clerk + Convex SaaS application. Inventories all dashboard pages, maps each to its feature spec (docs/FEATURES/F-XXX-*.md), runs Playwright tests with authenticated Clerk sessions (sign-in-token + ticket strategy), captures screenshots per workflow step, identifies placeholder pages (DeferredFeatureShell detection), optionally dispatches dev workers to ship MVP UI for placeholders, re-tests, and produces a comprehensive markdown report with verdicts per page + workflow. Re-invocable: each call relaunches the full pipeline (recon -> tests -> dev -> re-test -> report). Use ONLY for whole-app validation, never a single page/endpoint (route those to /debugaudit, /uiuxaudit, /apiaudit). Use when user says "/e2e", "fais un test complet de l'application", "teste toute l'app", "big test avant lancement", "test toute l'application", "final pre-launch test", "test complet", "full app test", "valide que tout marche", "validate everything works", "pre-launch QA", "QA avant

- Skill: `agentik-os/e2e` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add agentik-os/e2e`
- Raw SKILL.md: https://api.skillmd.com/api/skills/agentik-os/e2e/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: agentik-os (https://skillmd.com/u/agentik-os)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/agentik-os/e2e

---


# /e2e — Forensic Pre-Launch Test Pipeline

> **One command. Six phases. Full app validation.**
> Re-invocable: each call relaunches the entire pipeline. State lives in `.audit/test-complet-<date>/`.

---

## When to use

Invoke at major checkpoints:
- Before a production launch
- After a milestone is marked complete (M1, M2, ...)
- After a large refactor that touched many pages
- Weekly QA cadence during pre-launch phase
- When the user says: "fais un test complet de l'application", "big test", "test toute l'app"

## When NOT to use

- For a single bug fix → use `/debugaudit` or direct Playwright
- For a single page UX review → use `/uiuxaudit --url=<page>`
- For a single API endpoint → use `/apiaudit --files=<path>`

---

## Dynamic Workflow orchestration

`/e2e` is a fan-out audit pipeline, not a linear script. The natural unit of
parallelism is the **auto-detected domain** (Phase 1). Orchestrate it as a
Dynamic Workflow:

1. **Plan** — Phase 1 inventories pages and emits `domains.txt`. Domain count is
   unknown until recon runs, so this is a **loop-until-dry discovery**: never
   hardcode a domain list, never assume project shape. `.expected-workers` (=
   domain count) is the sweep marker — every detected domain MUST yield a worker
   before `done_clean` is legal (the Kommu/Causio premature-done gate).
2. **Fan out** — Phase 4 dispatches ONE `/debugaudit` worker per domain in
   parallel (load-aware via `omega-dispatch-budget.sh`). Workers are
   file-disjoint by route, so they run concurrently (R-SCOPE).
3. **Adversarially verify** — a single worker's per-page verdict is an *input,
   never the verdict* (R-VERIFY). Before Phase 6 accepts a domain as `pass`,
   re-grade each `e2e-<domain>.json` through **≥3 independent skeptic lenses**
   and require **2-of-3 consensus**:
   - **Runtime lens** — does the screenshot + console + network log actually show
     the workflow completing? (First Law: runtime over claim.)
   - **Spec lens** — does the page satisfy its `docs/FEATURES/F-XXX-*.md` spec, or
     only render without function?
   - **Regression lens** — did any previously-passing page silently break?
   A domain passes only on 2-of-3 agreement; a 1-of-3 or split → downgrade to
   `pending` with the dissenting evidence cited, never averaged away.
4. **Synthesize yourself** — Phase 6 is YOUR synthesis, not a paste of worker
   summaries. Merge verdicts, compute the `/100` score, rank next-steps. The
   report owner reconciles disagreements with cited evidence.

**No-hallucination guardrail:** every verdict in `final-report.md` carries
evidence — a screenshot path, a console/network log line, or a `file:line`
(R-CITE). A page with no captured artifact is `untested`, never `pass`. A 403 /
401 / auth-blocked surface is an **ABORT**, never a silent PASS (L5).

---

## CLI

```bash
/e2e                          # full pipeline (READ-ONLY — no code changes)
/e2e --full-arsenal           # all 17 Quality Arsenal audits/domain (vs /debugaudit only)
/e2e --auto-dev               # also dev MVP UI for placeholders (Phase 5)
/e2e --resume                 # continue from last completed phase
/e2e --domain=safety          # only one auto-detected domain
/e2e --page=cast-availability # single page
/e2e --project-dir=/path      # override project root
```

**Default is read-only.** Phases 0-4 + 6 inventory, test, and report without
touching code. Phase 5 (dev placeholders) is **opt-in** via `--auto-dev` — it
dispatches dev workers that commit + push. This reversal (was opt-out `--skip-dev`
in v1.0.0) follows Karpathy "surgical changes": a test command must not silently
mutate the codebase. `--skip-dev` is still accepted as a deprecated no-op.

Default project dir: `$PWD` (the directory Claude is invoked from).

---

## Output layout

```
.audit/test-complet-<YYYY-MM-DD>/
├── preflight.json             # Phase 0: stack + env check
├── page-inventory.json        # Phase 1: routes + states + auto-detected domain
├── page-inventory.md          # Phase 1: human-readable summary
├── domains.txt                # Phase 1: auto-detected domains (one per line)
├── .expected-workers          # Phase 1: sweep-completeness marker (int)
├── .last-phase                # --resume marker (last completed phase number)
├── e2e-<domain>.json          # Phase 4: per-domain test results
├── screenshots/<page>/        # Phase 4: per-workflow PNGs
├── dev-placeholders.json      # Phase 5: dispatched dev workers + commits
└── final-report.md            # Phase 6: /100 score + grade + ranked next-steps
```

---

## Protocol — 6 phases (0 → 6, no dead phase)

Each phase is one bash script in `scripts/`. Phases run sequentially.
If a phase fails, the pipeline halts and reports `pending`. `--resume`
reads `.last-phase` and continues from the next phase.

### Phase 0 — Preflight (scripts/00-preflight.sh) — NEW in v1.1.0

**Goal:** Fail fast if the stack/env is wrong, before any heavy work.

Hard checks (abort on fail): `package.json`, `next` dependency, a
`app/dashboard` or `src/app/dashboard` directory.
Soft checks (warn, continue): `convex/`, `@clerk/nextjs`, `components/ui`,
Playwright installed, `.env.local`, and 5 required env vars.
Writes `preflight.json` with detected prod URL for downstream phases.

### Phase 1 — Recon (scripts/01-recon-pages.sh)

**Goal:** Inventory every dashboard page, classify state, **auto-detect domains**.

Steps:
1. Find `(src/)?app/dashboard/**/page.tsx` (both layouts supported)
2. For each page extract: route, file, **domain = first route segment**
   (auto-detected — no hardcoded project-specific list), state,
   feature_id (matched to `docs/FEATURES/F-*-<slug>.md`), spec path, slug.
3. **State detection** — `placeholder` if the file matches any pattern in
   `.audit-placeholder-pattern.txt` (project-overridable; default set
   includes `DeferredFeatureShell`, `en cours d'assemblage`, `ComingSoon`,
   `PlaceholderPage`, `WorkInProgress`, `NotImplementedYet`);
   `partial_impl` if no data hook (`useQuery|useMutation|useAction|fetch|axios`);
   else `full_impl`.
4. Write `page-inventory.json` (jq-pure, no fragile string building),
   `page-inventory.md`, `domains.txt`, and `.expected-workers`
   (= domain count → consumed by `oracle-mark-done.sh` sweep gate so a
   premature `done_clean` is downgraded to `pending`).

### Phase 3 — Test infra (scripts/02-test-infra-setup.sh)

**Goal:** Install Playwright + axe-core, set up auth helper and seed data helper.

Steps:
1. `npm install -D @playwright/test @axe-core/playwright` (idempotent — skip if installed)
2. `npx playwright install chromium` (idempotent)
3. Create `e2e/dashboard-test-suite/clerk-auth.ts` — uses Clerk Backend API sign-in-token + Frontend API ticket strategy (mirrors `~/.claude/lib/clerk-auth-browse.sh`). Sets `__session` + `__client_uat` cookies on the Playwright context. Reads admin user ID from `E2E_CLERK_USER_ID` env var.
4. Create `e2e/dashboard-test-suite/seed-test-data.ts` — Convex client that creates a test production + 5 scenes + 10 cast + 5 crew + 3 locations + 1 callsheet. Idempotent (uses `upsertByIndex`).
5. Create `playwright.config.ts` if missing — viewports: mobile `iPhone 13` + desktop `1440x900`. Reporter: `json` + `html`.

### Phase 4 — E2E tests per domain (scripts/03-run-e2e-tests.sh)

**Goal:** Run real forensic audits per auto-detected domain.

Steps:
1. Read `domains.txt` (auto-detected in Phase 1 — NOT a hardcoded list)
2. For each domain, dispatch ONE worker via `~/.aisb/lib/dispatch-to-session.sh`.
   **The worker prompt's first line is `/debugaudit --scope=...`** — it invokes
   the real 18-phase forensic skill, never paraphrased prose steps (per
   CLAUDE.md AUDIT KEYWORD DETECTION mandate). The prompt passes the exact
   route list, prod URL (from `preflight.json`), and a strict scope boundary.
   The worker authenticates via `clerk-auth.ts`, screenshots each workflow
   step, runs axe-core, captures console + network failures, and writes
   `e2e-<domain>.json` with per-page verdict.
3. Workers run in parallel (CPU Guard auto-queues if VPS saturated).
4. Wait loop up to 60min for all `.done.json`. `.last-phase` set to 4.

### Phase 5 — Dev placeholders (scripts/04-dev-placeholders.sh) — OPT-IN

**Goal:** Ship MVP UI for every placeholder page.

**Disabled by default.** Runs only with `--auto-dev` (sets `AUTO_DEV=1`).
A pure test command must not silently mutate the codebase — this is the
Karpathy "surgical changes" reversal from v1.0.0's opt-out `--skip-dev`.

Steps (when `--auto-dev`):
1. `jq` filter `state == "placeholder"` from inventory (no regex fragility)
2. For each placeholder, dispatch ONE dev worker (parallelism 3, CPU Guard):
   - Read `docs/FEATURES/F-XXX-*.md`
   - Scaffold MVP UI: spec sections, shadcn/ui, Convex `useQuery`/`useMutation`
   - Create `convex/<feature>.ts` if missing; `convex/schema.ts` += tables (`.bak` first)
   - Build via `~/.aisb/lib/safe-npm-build.sh` (CPU mutex)
   - Commit + push (auto-deploy)
3. Wait for all dev workers `.done.json`. `.last-phase` set to 5.

### Phase 6 — Aggregate report (scripts/05-aggregate-report.sh)

**Goal:** Merge all results, produce a normalized `/100` scored report.

Steps:
1. Merge all `e2e-<domain>.json` (auto-detected domains from `domains.txt`)
2. Compute **normalized /100 score** (Quality Arsenal canon — weighted axes):
   - Functional coverage (% pages passing E2E) — **50%**
   - Completeness (full_impl / total) — **25%**
   - Domain coverage (domains tested / detected) — **15%**
   - Placeholder ratio (inverted: fewer = better) — **10%**
3. Assign grade (F/D/C/B/A/A+) + verdict (needs work / acceptable / launch ready)
4. Write `final-report.md`: score breakdown table, executive summary,
   per-domain breakdown, **ranked next-steps** (failing pages → placeholders
   → untested domains → re-run), artifacts. `.last-phase` set to 6.

---

## Failure handling

| Phase | If it fails | Action |
|---|---|---|
| 0 (preflight) | hard check fails | Abort with exit 2 + `preflight.json` diagnosis |
| 1 (recon) | `page-inventory.json` not written | Halt — manual intervention |
| 3 (infra) | `npm install` fails | Halt — check `package.json` permissions |
| 4 (e2e) | One worker fails | Others continue. Report flags partial coverage. |
| 5 (dev) | One dev worker fails | Others continue. Phase 6 reports unshipped. |
| 6 (report) | Aggregation fails | Halt — `pending` with diagnosis |

**Resumable:** each phase writes `.last-phase`. `--resume` skips completed
phases. **Idempotent:** without `--resume`, re-invoking re-runs all phases;
outputs are date-stamped so runs coexist.

**Sweep-completeness gate:** Phase 1 writes `.expected-workers` (= domain
count). `oracle-mark-done.sh` reads this; if fewer audit workers completed,
a premature `done_clean` is auto-downgraded to `pending`. This is the
direct fix for the Kommu/Causio incident (2026-05-17) where an oracle
self-declared done on an under-dimensioned plan.

---

## Expected runtime

| Project size | P0 | P1 | P3 | P4 | P5 (--auto-dev) | P6 | Total |
|---|---|---|---|---|---|---|---|
| Small (10 pages, 2 ph) | 5s | 1m | 3m | 5m | 15m×2=30m | 1m | ~40m / ~10m read-only |
| Medium (40 pages, 10 ph) | 5s | 3m | 3m | 15m | 15m×10 (3-parallel)=50m | 2m | ~75m / ~23m read-only |
| Large (82 pages, 29 ph) | 5s | 5m | 3m | 30m | 15m×29 (3-parallel)=145m | 3m | ~3-4h / ~41m read-only |

No Time Panic: full quality on every page. Default (no `--auto-dev`) is
read-only and skips Phase 5 entirely — the fast, safe path.

---

## Required environment

The project being tested must have these env vars set (locally or in CI):

```
E2E_CLERK_USER_ID=user_xxx          # admin Clerk user for auth helper
CLERK_SECRET_KEY=sk_test_xxx        # Backend API key
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxx
NEXT_PUBLIC_CLERK_FRONTEND_API=clerk.xxx.dev
NEXT_PUBLIC_CONVEX_URL=https://xxx.convex.cloud
NEXT_PUBLIC_APP_URL=https://app.example.com   # production URL to test against
```

If any are missing, Phase 3 halts and writes a `worker-blocked-*.json` listing the gaps.

---

## Cross-references

- `~/.claude/lib/clerk-auth-browse.sh` — Clerk authenticated browser pattern (source of `clerk-auth.ts`)
- `~/.aisb/lib/safe-npm-build.sh` — CPU mutex (mandatory for build commands)
- `~/.aisb/lib/dispatch-to-session.sh` — worker dispatch (parallel Phase 4 + 5)
- `~/.claude/rules/46-no-time-panic.md` — no streamlined variants
- `~/.claude/commands/debugaudit.md` — single-page runtime forensic
- `~/.claude/commands/uiuxaudit.md` — single-page design forensic

---

## Orchestration (how Claude runs this)

When invoked, parse flags then run phases in order. With `--resume`, read
`.audit/test-complet-<date>/.last-phase` and skip phases ≤ that number.

```bash
SK=~/.claude/skills/e2e/scripts
PD="${PROJECT_DIR:-$PWD}"
OD="$PD/.audit/test-complet-$(date +%Y-%m-%d)"
ARGS="$*"
RESUME_FROM=-1
case "$ARGS" in *--resume*) [ -f "$OD/.last-phase" ] && RESUME_FROM=$(cat "$OD/.last-phase") ;; esac
case "$ARGS" in *--auto-dev*) export AUTO_DEV=1 ;; esac
case "$ARGS" in *--full-arsenal*) export AUTO_ARSENAL=1 ;; esac   # v1.2.0 #4: all 17 audits/domain

# Phase 0 always runs (cheap, fail-fast — aborts pipeline on hard fail)
bash "$SK/00-preflight.sh" "$PD" "$OD" || exit 2
[ "$RESUME_FROM" -lt 1 ] && bash "$SK/01-recon-pages.sh"      "$PD" "$OD"             # Phase 1
[ "$RESUME_FROM" -lt 3 ] && bash "$SK/02-test-infra-setup.sh" "$PD"                   # Phase 3
[ "$RESUME_FROM" -lt 4 ] && bash "$SK/03-run-e2e-tests.sh"    "$PD" "$OD" "${DOMAIN:-}"  # Phase 4
[ "$RESUME_FROM" -lt 5 ] && bash "$SK/04-dev-placeholders.sh" "$PD" "$OD"             # Phase 5 (opt-in)
[ "$RESUME_FROM" -lt 6 ] && bash "$SK/05-aggregate-report.sh" "$PD" "$OD"             # Phase 6
```

Phase 2 was removed in v1.1.0 (was a no-op). `--resume` default `-1` means a
fresh run executes every phase; with `--resume` it skips phases ≤ `.last-phase`.

## TLDR

```
/e2e                  # READ-ONLY: P0→P1→P3→P4→P6
/e2e --auto-dev       # also P5 (dev placeholders, commits)
/e2e --resume         # continue from .last-phase
  → Phase 0: preflight (stack + env, fail-fast)
  → Phase 1: inventory + AUTO-DETECT domains + sweep marker
  → Phase 3: setup Playwright + Clerk auth + Convex seed
  → Phase 4: parallel /debugaudit per domain (real forensic skill)
  → Phase 5: [opt-in] parallel dev of placeholders (commit + push)
  → Phase 6: final-report.md — /100 score + grade + ranked next-steps
```

Output: `.audit/test-complet-<date>/final-report.md` — `/100` launch readiness verdict.

## Changelog

**v1.2.0 (2026-05-17)** — Honest-coverage release (closes 3 overstated claims):
- **#1 Full-app scan**: Phase 1 now inventories the ENTIRE `app/`/`src/app/`
  (marketing, auth, public, landing, pricing, dashboard) — not dashboard only.
  Each page gets an `area` field; report shows per-area breakdown. "Toutes les
  pages" is now true, not just dashboard.
- **#3 Adaptive dispatch**: Phase 4 uses `omega-dispatch-budget.sh` (load-aware)
  instead of fixed `MAX_PARALLEL=4`. Consistent with the system-wide Defense D
  fix — `/e2e` can no longer recreate the Kommu/Causio CPU meltdown by flooding
  a fixed batch into a saturated box. Hard ceiling `TCA_MAX_PARALLEL` still caps.
- **#4 `--full-arsenal`**: optional flag runs all 17 Quality Arsenal audits per
  domain (`/audit-orchestrator full`) instead of `/debugaudit` only. Default
  stays `/debugaudit` (fast). Now "full test complet" is achievable, not implied.

**v1.1.0 (2026-05-17)** — Hardening release:
- Phase 0 preflight (fail-fast stack/env check)
- Domains **auto-detected** from route segments (was hardcoded 8 film-production
  clusters; skill is now genuinely portable as its description claims)
- Dev is **opt-in** `--auto-dev` (was opt-out `--skip-dev`) — test ≠ mutate
- Phase 4 workers invoke real `/debugaudit` (was paraphrased prose — violated
  CLAUDE.md audit-keyword mandate)
- Sweep-completeness marker → integrates with `oracle-mark-done.sh` gate
  (prevents the Kommu/Causio premature-done incident on long sweeps)
- `--resume` via `.last-phase`; jq-pure JSON (no fragile string building)
- `/100` normalized score + grade + ranked next-steps (Quality Arsenal canon)
- Removed Phase 2 no-op (dead code)

