exam
Run the heavy local exam lane (T4) on the gold-standard macOS host: preflight → caffeinate keep-awake → a single RUN_FLAKY=1 pnpm exam pass (WebKit @interactive + @macos-only on Darwin + @flaky quaran...
/exam — Heavy Local Lane (T4)
Project-scope heavy-lane exam skill. Runs the platform-gated WebKit @interactive suite (the specs that need a real macOS WebKit engine and so cannot run on PR CI), triages failures with agent judgment, files deduped exam-failure tracking issues, and optionally fixes up to N in-session. Leave it running before sleep; read the morning summary when you return.
This is the local convenience lane (T4), not the enforcement layer. The scheduled T3 CI re-exam (., twice-weekly Mon/Thu cron + workflow_dispatch) is the paper-trail backstop that runs even when nobody remembered to run this. The two are a pair: / is the rich lane with agent triage and in-session fixes; the scheduled CI job is the thin net. See $HOME/ for the design rationale and $HOME/ for the T0–T4 tier model.
Argument Parsing
Parse $ARGUMENTS for:
--fix [N]— After the exam run, pick up to N openexam-failureissues (default N=3) and attempt in-session fixes. Each fix is verified with a scoped WebKit rerun. Without--fix, the skill stops after filing issues.--skip-preflight— Bypass the Step 1 preflight checks. Use only when explicitly requested (e.g. you know the tree is intentionally dirty during a repair session).
Step 1 — Preflight
Skip this step entirely if
--skip-preflightwas passed.
The night-exam pattern wants a clean, current main so the results are attributable. Run these checks; hard-block where noted, warn-but-continue otherwise.
1a. Clean working tree (hard block)
git status --porcelainIf the output is non-empty, stop:
Working tree is dirty. Commit or stash before running /exam. Dirty files: <list>
1b. On main (warn, do not block)
git branch --show-currentmain is the intended branch for a night exam. If the current branch is something else (a topic branch, a worktree sub-branch), warn but continue — running the exam on a branch to validate a change pre-merge is legitimate:
Warning: you are on
<name>, notmain. Exam results reflect this branch's state, not main. Continuing anyway.
1c. Up to date with remote (hard block if behind)
git fetch --quiet
git status -sbIf the status line contains behind, stop (so the exam does not test stale code):
Local branch is behind the remote. Pull before running /exam. Run: git pull --ff-only
Step 2 — Keep-Awake Wrapper + Single Exam Pass
Run the entire suite in one pnpm exam invocation with RUN_FLAKY=1 in the env — not two passes. scripts/ runs the WebKit @interactive lane once, then (because RUN_FLAKY=1) the @flaky quarantine sweep in both projects. Invoking pnpm exam twice (once plain, once with RUN_FLAKY=1) re-runs the entire serial @interactive lane a second time for no reason — do not do that.
Wrap it in caffeinate -i on macOS so the machine does not sleep mid-suite:
# macOS: caffeinate -i holds the sleep assertion for the child's lifetime.
# On Linux/WSL caffeinate is absent and run-exam.sh requires FORCE_EXAM=1 anyway;
# the WebKit @interactive verdict is only trustworthy on real macOS regardless.
if [[ "$(uname)" == "Darwin" ]]; then
caffeinate -i env RUN_FLAKY=1 pnpm exam
else
RUN_FLAKY=1 pnpm exam
fiCapture the full combined output (stdout + stderr) to a variable AND stream it live to the terminal. Record the exit code as EXAM_EXIT_CODE.
scripts/ is platform-gated: on a non-Darwin host without FORCE_EXAM=1 it refuses to run (the WebKit lane false-reds off real macOS — see #2604/#2649). A clean non-Darwin refusal is not a failure to triage; report it and stop.
Step 3 — Parse Lane Output
scripts/ emits structured status lines the skill consumes:
[lane status] RAN: <lane-name>
[lane status] SKIPPED: <lane-name> — <reason>plus per-step ✅/❌ markers and a final ✅ All checks passed! / ❌ N check(s) failed: summary. Collect:
LANES_RAN— lane names fromRAN:lines (e.g.E2E tests (webkit @interactive),chromium @flaky quarantine (non-blocking),webkit @flaky quarantine (non-blocking))LANES_SKIPPED—{ lane, reason }fromSKIPPED:lines (e.g. the@macos-only/@webkit-only specsexclusion on non-Darwin, or the@flakysweep whenRUN_FLAKYwas not set)EXAM_EXIT_CODE— from Step 2
Skipped lanes are not failures. Report them in the morning summary; never file an issue for a skip. The @flaky quarantine lanes are non-blocking — their failures do not drive EXAM_EXIT_CODE and are triaged as quarantine signal, not regressions.
Step 4 — Triage Failures (two passes)
Noise scan — always, regardless of
EXAM_EXIT_CODE. Scan the captured output for the env-noise signatures in 4a. Noise can co-exist with a zero exit; if any noise matched, the summaryResultisNOISE-ONLY(orFAILif real regressions also exist) — never a plainPASS.Failure clustering — only when
EXAM_EXIT_CODEis non-zero. Parse the output for failure signatures and cluster them per 4b, excluding anything already matched as noise.
4a. Env-noise signatures (never file as exam-failure)
These are known non-regression conditions. Do NOT file issues. Surface them in the morning summary as "env noise" with the recommended action.
| Noise signature | Detection | Recommended action |
|---|---|---|
WebKit ESM-loader noise (#2174) | TypeError: Importing a module script failed in the --workers=1 WebKit pass; re-passes on a warm-cache rerun with no code change | Rerun the scoped spec once (pnpm test:e2e --project=webkit --workers=1 --grep="<spec>"); if it passes on a warm cache, it is the known Vite on-demand-transform race, not a regression |
Keyboard-delivery noise (#2238, #2649) | toHaveAttribute/waitForSelector timeout immediately after a keyboard action, no shortcut-engine code changed, AND the spec is in the passing set of the latest e2e-webkit-macos.yml run | Cross-check gh run list --workflow=e2e-webkit-macos.yml --limit 5; if green there, treat as known machine-dependent key-delivery noise |
@flaky quarantine failure | A failure under a chromium @flaky / webkit @flaky (non-blocking) lane | Already quarantined by definition — report under "Known quarantine", never file a duplicate. Each @flaky tag carries an inline issue URL; that is its tracking home |
| Lane skipped (non-Darwin) | [lane status] SKIPPED: @macos-only/@webkit-only specs — non-Darwin host | Expected off real macOS; run on a Darwin host or rely on the T3 e2e-webkit-macos.yml job |
| Lane skipped (RUN_FLAKY unset) | [lane status] SKIPPED: @flaky quarantine … RUN_FLAKY not set | Only relevant if you intended the quarantine sweep; this skill sets RUN_FLAKY=1 by default (Step 2) |
If a failure matches a noise signature, list it separately in the summary and skip issue filing for that cluster.
4b. Real regression failures
A failure is a real regression if it matches NO noise signature above AND:
it is in a blocking
@interactiveor@macos-onlyspec (droveEXAM_EXIT_CODE), ANDno open
exam-failure-labeled issue already covers its cluster.
Group related failures into one cluster when they share an obvious root cause (same component, same code path, same error message). One cluster → one issue — not one per spec, not one per run.
Step 5 — Deduped Issue Filing
For each real-regression cluster:
5a. Check for an existing open issue (dedupe)
gh issue list --label "exam-failure" --state open --json number,title \
--jq '.[] | "\(.number) \(.title)"'If an open issue already covers this cluster (fuzzy: title shares ≥3 key tokens, or the same failing spec file), comment on it instead of opening a duplicate:
EXAM_AT=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
EXAM_HEAD=$(git rev-parse --short HEAD)
gh issue comment <existing-number> --body "$(cat <<EOF
Still failing: ${EXAM_AT} — HEAD ${EXAM_HEAD}
<same failing specs + first error detail>
EOF
)"5b. File a new issue if no match found
Ensure the label exists once before the first create (idempotent):
gh label create "exam-failure" --color "e11d48" \
--description "Heavy-lane exam run failed; tracks the open regression" 2>/dev/null || trueCompute metadata BEFORE the heredoc. The heredoc is unquoted (<<EOF) so ${...} expands — therefore every literal backtick inside the body must be escaped (\`) to avoid command substitution.
EXAM_AT=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
EXAM_HEAD=$(git rev-parse --short HEAD)
EXAM_BRANCH=$(git branch --show-current)
SCHEDULED_XREF=$(gh run list --workflow=e2e-webkit-macos.yml --limit 3 \
--json createdAt,status,conclusion \
--jq '.[] | "\(.createdAt) \(.status)/\(.conclusion)"')
gh issue create \
--label "exam-failure" \
--title "exam: <short symptom>" \
--body "$(cat <<EOF
## Exam failure — <cluster title>
**Detected:** ${EXAM_AT} — HEAD ${EXAM_HEAD} — branch ${EXAM_BRANCH}
**Lanes that ran:** <LANES_RAN list>
### Failing specs
<spec file list>
### Error detail
\`\`\`
<first error message / timeout detail>
\`\`\`
### Noise check
- ESM-loader noise (#2174): <yes/no — evidence>
- Keyboard-delivery noise (#2238/#2649): <yes/no — evidence>
- @flaky quarantine: <yes/no>
### Scheduled exam cross-reference (e2e-webkit-macos.yml)
${SCHEDULED_XREF}
---
*Filed automatically by \`/exam\`. Do not close manually — use \`gh issue close\` after a confirmed fix.*
EOF
)"Collect all filed/updated issue URLs into FILED_ISSUES. The dedupe contract here mirrors scripts/ (the CI-side filer the T3 workflow uses): at most one open exam-failure issue per failure cluster.
Step 6 — Fix Mode (--fix)
Skip this step unless
--fixwas passed.
6a. Collect open exam-failure issues
gh issue list --label "exam-failure" --state open --json number,title,url,body --limit <N>Pick up to N (default 3 unless the user gave a different N). Prefer lowest-numbered / freshest.
6b. For each issue
Read the issue body to identify the failing spec(s).
Create a fix branch:
git checkout -b fix/<short-slug>.Investigate root cause (read the relevant source), then apply a minimal surgical fix — one bug, one commit.
Reproduce + verify with the scoped WebKit runner (NOT a full
pnpm examrerun, and NOT vitest):pnpm test:e2e --project=webkit --workers=1 --grep="<spec name or describe>"If the scoped run passes: commit (
git commit -m "fix(<scope>): <what and why>"), then close the issue with a comment linking the commit/branch.Do NOT push (worktree push policy — only the manager session pushes). Leave the branch for review; report it in the morning summary.
Time-box each issue to ~20 min (branch → passing scoped run). If it overruns, abandon it: git checkout main, delete the branch, leave a diagnostic comment on the issue ("attempted but deferred"), and move to the next candidate. Do not let one hard issue consume the session. Do not attempt more than N issues — focus over breadth.
Step 7 — Morning Summary
Always print a structured summary as the final output:
=== /exam summary — <date> ===
HEAD: <short SHA> — <git log -1 --pretty=%s>
Branch: <branch>
Result: PASS | FAIL | NOISE-ONLY
── Lanes ─────────────────────────────
RAN:
- E2E tests (webkit @interactive)
- webkit @flaky quarantine (non-blocking)
- ... (only lanes that produced a RAN line)
SKIPPED:
- <lane> — <reason>
- ... (only skipped lanes; or "none")
── Env noise (not filed) ─────────────
- [ESM-loader #2174 | keyboard-delivery #2238/#2649 | @flaky] <spec> — <detail>
→ <recommended action>
- ... (or "none")
── Real regressions (<N>) ────────────
- <cluster title> — <one-line error> → #<issue> (new | updated)
- ... (or "none — all blocking lanes passed")
── Fix mode (--fix only) ─────────────
Fixed: #<n> <title> → branch fix/<slug> (commit <sha>)
Deferred:#<n> <title> — <reason>
(omit this section if --fix was not passed)
── Backstop ──────────────────────────
T3 scheduled CI: e2e-webkit-macos.yml (Mon/Thu cron + workflow_dispatch).
Dispatch on a branch before merging risky @interactive/@macos-only changes:
gh workflow run e2e-webkit-macos.yml --ref <branch> If nothing failed and no noise matched, end with:
All exam lanes passed. No issues filed.
Notes
pnpm exam=scripts/— it applies the Darwin platform gate and the per-lane grep logic. Run the suite through it, not by hand-assembling Playwright commands; the script handles therun- exam. sh --workers=1serial WebKit pass (#2174) and the@macos-onlyinclusion correctly.Single pass, not two. Set
RUN_FLAKY=1in the env of ONEpnpm examcall (Step 2). The old two-call pattern re-ran the entire serial@interactivelane twice.Lane skip ≠ failure. Non-Darwin platform-spec exclusion and the unset-
RUN_FLAKYskip are expected; they appear in the summary for visibility but are never filed.@flakyis a quarantine pipeline, not a lane to fix here. Its failures are non-blocking and tracked by the inline issue URL on each tag — seee2e/§ "Test Placement Triage".README. md Issue label:
exam-failure(create on first use; see Step 5b).--fixis best-effort. In-session fixes are opportunistic; if a fix is uncertain, leave a diagnostic and move on.
Reference
Heavy lane:
scripts/(run- exam. sh pnpm exam)CI-side deduped issue filer (T3):
scripts/file- exam- issue. sh Scheduled CI exam (T3 backstop):
.github/ workflows/ e2e- webkit- macos. yml Tag taxonomy, tier model, b4push/exam contract, module-to-spec map:
e2e/README. md Known noise:
e2e/§ "Local e2e lanes",README. md #2174,#2238,#2649Pattern rationale:
$HOME/. claude/ skills/ test- wisdom/ docs/ real- world- patterns/ scheduled- re- exam. mdx Tier model (T0–T4):
$HOME/. claude/ skills/ test- wisdom/ docs/ decision- guide/ execution- tiers. mdx Sibling skills:
/(open-ended bug sweep),l- broad- walk- test /(specific bug reproduction)l- agent- walk- test