test-optimization
SkillDev toolsProfile a test suite, optimize the slowest top 10% in grouped slices, and close with a re-profile. Works for unit tests (JUnit/Vitest/…; "small test" style) in any sub-project (backend, frontend, cli, mcp-server) or Cypress E2E. Use when the developer asks to optimize, speed up, or profile slow tests, top 10% slowest, or test performance. With `--resolve`, run resolve-only mode: triage the blacklist Candidates (tag / plan / ask) with no profiling or optimization.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the test-optimization skill
What this skill tells your AI
The instructions your AI receives, as published by nerds-odd-e/doughnut in .agents/skills/test-optimization/SKILL.md and read by ahel’s review.
Purpose: Systematic test-performance workflow for any sub-project (backend, frontend, cli, mcp-server, E2E).
Output: Optimized tests with per-slice commits + summary ending with
## TEST OPTIMIZATION COMPLETE.
When --resolve is given, skip every other step and go straight to
resolve_candidates. Read
resolving-candidates.md in full first.
Git does not use the Nix prefix. All other repo tooling does:
CURSOR_DEV=true nix develop -c …
Non-negotiable rules (every optimization pass):
- Remove or simplify redundant tests first — merge overlapping scenarios, drop duplicate setup, delete tests that only repeat coverage elsewhere.
- No fixed-time waits — no
sleep, nocy.wait(ms)without an assertion, no arbitrarysetTimeout/ debounce-timeout polling in unit tests. Use assertions, intercept aliases, fake timers, or API/testability setup. - Flaky is failure — re-run touched tests until stable; fix root cause, do not mask with retries.
Execution model: After writing the plan, always use dough-execute-plan
(.agents/skills/dough-execute-plan/SKILL.md). Coordinator delegates each group to a
fresh sub-agent and applies dough-execute-plan's coordinator-owned wrap-up. Do not
accumulate context across slices in one agent.
E2E skip tag: @skipOptimizationDueToKnownNecessarySlowness on a Scenario
or Feature marks known-necessary slowness. Profile runs exclude it via
--expose tags=… (see profile). Adding the tag is a developer decision (Jidoka)
— propose only; do not add it yourself.
Candidates: .planning/test-optimization-blacklist.md holds Candidates
from optimization runs (proposals only). Keep that section; do not invent a
Skip list there.
Do not commit raw profile JSON (large, machine-specific). Gitignored paths:
e2e_test/reports/, .planning/*-profile-results.json,
.planning/quick/*-profile-results.json, ongoing/*-profile-results.json.
| Scope | Profile command | Parse durations from |
|---|---|---|
| E2E | CURSOR_DEV=true nix develop -c pnpm cy:run-on-sut --reporter json --expose tags='not @ignore and not @skipOptimizationDueToKnownNecessarySlowness' (SUT up; pnpm sut:healthcheck) | JSON blocks in stdout — tee to /tmp/e2e-profile.log |
| Frontend | CURSOR_DEV=true nix develop -c pnpm -C frontend exec vitest run --reporter=json | Vitest JSON testResults[].assertionResults[].duration |
| CLI | cd cli && CURSOR_DEV=true nix develop -c pnpm exec vitest run --reporter=json | Same as Vitest |
| Backend | CURSOR_DEV=true nix develop -c pnpm backend:test_only then parse | backend/build/test-results/test/TEST-*.xml → testcase@time |
| MCP server | CURSOR_DEV=true nix develop -c pnpm -C mcp-server exec vitest run --reporter=json | Vitest JSON |
E2E tags: Always pass --expose tags='not @ignore and not @skipOptimizationDueToKnownNecessarySlowness' for profile (and re-profile) so tagged scenarios/features are not run and do not enter the top 10%. CI default tags still apply for normal runs; this override is profile-only. In CI, also keep excluding @wip if you mirror CI: not @ignore and not @wip and not @skipOptimizationDueToKnownNecessarySlowness. Use --expose / -x, not --env — preprocessor v27 on Cypress >= 15.17 ignores env.tags.
Frontend note: frontend:test runs Vitest browser mode (--browser=chromium).
Profile uses plain vitest run for duration data; verify changes with
frontend:test.
E2E JSON: Cypress --reporter-options output=… may not write a file; tee
stdout and parse { "tests": [ { "title", "duration" } ] } blocks between
spec runs.
Store baseline locally (e.g. .planning/quick/<scope>-profile-results.json with
"do not commit" note). Record baseline wall time and test count in the plan.
Sort eligible by duration descending; take first n_slow. Record in plan:
rank, seconds/ms, file/spec, test/scenario name.
| Strategy | How |
|---|---|
| By file | One group per file containing ≥1 slow test |
| Batches of 3 | Consecutive slow tests in rank order, 3 per group (last may be smaller) |
Choose the strategy with fewer groups. Tie-break: prefer by file.
Read sub-project rules when editing tests: frontend.mdc / frontend-testing.mdc,
backend.mdc / backend-testing.mdc, e2e-authoring.mdc, cli.mdc.
Each group slice (sub-agent):
- Optimize only tests in that group (see
optimize_tactics). - Verify with focused commands (see
verify). - Return control for dough-execute-plan's required refactor, formatting, plan update,
perf(<scope>): …commit, and push sequence.
Hard-to-improve → Candidates / skip tag: If no meaningful speedup after serious attempt, or would need product/design trade-off:
- Do not force a weak change.
- Append under Candidates in
.planning/test-optimization-blacklist.md: file, test/scenario, duration, why hard, date (YYYY-MM-DD). - Mark slice done (or Jidoka-stop if value decision required).
Promoting a Candidate to permanent skip is a developer decision (Jidoka) —
propose tagging the Scenario or Feature with
@skipOptimizationDueToKnownNecessarySlowness; do not add the tag yourself.
Read and follow verification.md.
- Re-run same profile command as baseline (same
--expose tags=…for E2E). - Record: test count, suite wall, top-10 table, top-10% total CPU (Vitest) or sum of slow scenarios (E2E).
- Note any new Candidates proposed.
- If full E2E re-profile is red (e.g.
Bad GatewayoncleanDB), document that; use per-spec timings + CI for authoritative "after" — do not fake a green wall time.
Set plan Status: done; clean up spent plan history (see planning_cleanup).
Keep the Candidates blacklist file.
- Do not keep two plans for the same scope — merge or delete duplicates.
- Optionally keep one-line note in STATE/ROADMAP; otherwise delete spent
quick/PLAN and SUMMARY noise (seeplanning.mdchistory cleanup). - Never commit profile JSON.
- Leave
.planning/test-optimization-blacklist.mdand active GSD milestone artifacts untouched.
If user asks only to clean up: remove completed test-opt plans; do not delete blacklist or unrelated GSD dirs in progress.
<success_criteria> Optimize mode:
- Full-suite profile captured with E2E skip tag excluded via
--expose tags - Top 10% selected from eligible (profiled) tests
- Plan written and executed via dough-execute-plan (commit + push per group)
- Non-negotiable rules applied (no redundant tests left, no fixed waits, no flaky)
- Re-profile recorded; plan marked done; spent history cleaned
- Final output includes
## TEST OPTIMIZATION COMPLETE
Resolve mode (--resolve):
- Every Candidate resolved by exactly one of tag / plan / ask
- At most one plan created for all replacements
- Resolved Candidates deleted from the blacklist (no "Resolved" archive kept)
- No profiling or optimization performed
- Final output includes
## CANDIDATES RESOLVED</success_criteria>
- Scope and baseline vs after metrics.
- Groups optimized and commits made.
- Candidates proposed (if any).
- Planning cleanup performed.
## TEST OPTIMIZATION COMPLETE
Resolve mode (--resolve) — report per Candidate: the decision (tag / plan /
ask) and its one-line rationale; the plan location if one was created; confirm the
blacklist Candidates list was pruned.
## CANDIDATES RESOLVED
<out_of_scope>
- Do not optimize in the coordinator agent after plan is written.
- Do not commit profile JSON.
- In optimize mode, do not add
@skipOptimizationDueToKnownNecessarySlownesswithout developer Jidoka (in--resolvemode you may tag directly per theresolve_candidatesstep). - Do not add
@focus/@onlyin committed code. - Do not run full E2E suite for per-slice verify unless shared helpers require it. </out_of_scope>
Signals
- GitHub stars
- 49
- Forks
- 72
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
test-optimization- Source
- github.com/nerds-odd-e/doughnut