[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6X7Y5EMFDPJFB7Y818PB0AS":3,"skill-same:01M6X7Y5EMFDPJFB7Y818PB0AS":82},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":53,"commitSha":54,"skillDirectory":55,"forksCount":56,"repositoryHtmlUrl":57,"repositoryHomepageUrl":58,"ownerHtmlUrl":59,"ownerBlogUrl":58,"ownerDescription":60,"updatedAt":61,"install":62,"resources":75},"01M6X7Y5EMFDPJFB7Y818PB0AS","test-performance",null,"Use when optimizing test suite performance — database setup, seeder optimization, parallel testing, CI pipeline efficiency, or RefreshDatabase alternatives.","event4u-app\u002Fagent-config","event4u-app","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F199339632?v=4","01M6X5TWBNCQCE1VDKT4E9KF7N","event4u.app","01M6X5TWF4HRM266RG2Q5VVH1X",19,"MIT","https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Fsrc\u002Fskills\u002Ftest-performance\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"performance","test performance","test","quality","testing","when","suite","alternatives","efficiency","base","test suite","use","parallel","laravel","pipeline","Optimization","engineering","ci","database","setup","2026-11-10 10:12:30",false,"---\nmodel_tier: medium\nname: test-performance\ndescription: \"Use when optimizing test suite performance — database setup, seeder optimization, parallel testing, CI pipeline efficiency, or RefreshDatabase alternatives.\"\ndomain: quality\nframework: laravel\nworkspaces:\n  - engineering\npacks:\n  - engineering-base\n---\n\n# test-performance\n\n## When to use\n\nUse this skill when:\n\n- Tests are running too slowly (locally or in CI)\n- Database setup\u002Fteardown is a bottleneck\n- Parallel testing needs optimization\n- Seeders need performance analysis\n- CI pipeline test jobs need to be faster\n- Investigating flaky tests caused by database state\n\n## Procedure: Analyze test performance\n\n### 1. Measure baseline\n\nBefore optimizing, always measure:\n\n```bash\n# Count tests per suite\nfind tests\u002F app\u002FModules\u002F*\u002FTests\u002F -name \"*.php\" | xargs grep -l \"it(\" | wc -l\n\n# Count by suite type\ngrep -rh \"it(\" tests\u002FUnit\u002F app\u002FModules\u002F*\u002FTests\u002FUnit\u002F --include=\"*.php\" | wc -l\ngrep -rh \"it(\" tests\u002FComponent\u002F app\u002FModules\u002F*\u002FTests\u002FComponent\u002F --include=\"*.php\" | wc -l\ngrep -rh \"it(\" tests\u002FIntegration\u002F app\u002FModules\u002F*\u002FTests\u002FIntegration\u002F --include=\"*.php\" | wc -l\n\n# Count migrations\nls database\u002Fmigrations\u002F*.php | wc -l\n\n# Count seeders\nfind database\u002Fseeders database\u002Fseeder-data -name \"*.php\" -path \"*\u002Fdata\u002F*\" | wc -l\n```\n\n### 2. Identify bottlenecks\n\nThe typical test lifecycle is:\n\n```\nProcess Start → Migrate → Seed → [Test → Rollback] × N → Process End\n                 ↑ expensive (once per worker)\n```\n\nCheck these areas in order of typical impact:\n\n| Area | What to check | Typical impact |\n|------|--------------|---------------|\n| **Migration count** | How many CREATE TABLE statements? | High if >20 |\n| **Schema dump** | Is `database\u002Fschema\u002F` used? | High if missing |\n| **Seeder INSERT method** | Individual `save()` vs bulk insert? | Medium |\n| **Truncation** | Per-seeder truncate vs centralized? | Low (but causes correctness issues) |\n| **Connection discovery** | Dynamic `getPdo()` probing? | Low |\n| **Parallel worker setup** | Does each worker re-migrate? | High |\n\n### 3. Optimization strategies (ordered by ROI)\n\n#### A. Schema Dump (highest ROI)\n\nLaravel's `schema:dump` consolidates all migrations into one SQL file.\nInstead of running N individual CREATE TABLE migrations, it loads one SQL dump.\n\n```bash\nphp artisan schema:dump --database=api_database\n# Generates database\u002Fschema\u002Fapi_database-schema.sql\n```\n\n**Savings:** 58 migrations → 1 SQL load = ~10-25s per worker.\n\n#### B. Template DB Cloning (high ROI for parallel tests)\n\nInstead of each parallel worker running migrate+seed independently:\n1. Prepare ONE template database (migrate + seed)\n2. Clone template for each worker via mysqldump\n\n```bash\n# Prepare template\nphp artisan migrate:fresh --database=template_db\nphp artisan db:seed --database=template_db\n\n# Clone per worker\nmysqldump template_db | mysql worker_db_test_1\n```\n\n**Savings:** Eliminate per-worker migrate+seed entirely.\n\n#### C. Skip Migrate+Seed Flag (high ROI for local dev)\n\nAdd a config flag to skip database setup when DB is already prepared:\n\n```php\n\u002F\u002F config\u002Ftesting.php\n'skip_migrate_seed' => EnvHelper::boolean('TESTING_SKIP_MIGRATE_SEED', false),\n```\n\nDeveloper workflow: `make migrate-testing` once, then `make test-quick` repeatedly.\n\n#### D. Bulk Inserts in Seeders (medium ROI)\n\nReplace individual `$model->save()` with bulk insert:\n\n```php\n\u002F\u002F Before: N INSERT statements\nforeach ($data as $row) {\n    $model = new MyModel($row);\n    $model->save();\n}\n\n\u002F\u002F After: 1 INSERT statement\nMyModel::insert($data);\n$models = MyModel::whereIn('id', $ids)->get();\n```\n\n#### E. Centralize Truncation (correctness fix)\n\nPer-seeder truncation is redundant after `migrate:fresh` and causes:\n- Non-deterministic ordering (lazy init triggers truncate)\n- Ghost data bugs (locally passes, CI fails)\n\nMake truncation configurable, default off:\n\n```php\n\u002F\u002F config\u002Ftesting.php\n'seed_truncate' => EnvHelper::boolean('DB_SEED_TRUNCATE', false),\n```\n\n#### F. Static Connection Discovery (cleanup)\n\nReplace dynamic `getPdo()` probing with explicit config:\n\n```php\n\u002F\u002F config\u002Ftesting.php\n'connections_to_transact' => ['api_database', 'customer_database'],\n```\n\n### 4. CI-specific optimizations\n\n- **MariaDB tmpfs:** Mount data dir on RAM disk for zero I\u002FO latency\n- **Shared DB prep:** One CI job prepares DB, test jobs clone from it\n- **Cache test DBs:** Skip re-migration if migration files haven't changed\n- **Separate suites:** Run no-DB tests (Unit) on cheaper runners\n\n## Related project docs\n\n- `agents\u002Freference\u002Fdocs\u002Fseeders.md` — seeder conventions (if exists)\n\n## Output format\n\n1. Optimized test configuration or seeder with timing comparison\n2. Parallelization or caching improvements applied\n\n## Gotcha\n\n- Don't use RefreshDatabase when DatabaseTransactions suffices — full refresh is 10x slower.\n- The model forgets that parallel tests share the database — use unique identifiers in test data.\n- Seeder optimization has the highest ROI — a 2s seeder running 100 times = 200s wasted.\n- Don't add indexes to test databases just for test performance — the real fix is better test design.\n\n\n## Do NOT\n\n- Do NOT use RefreshDatabase when DatabaseTransactions works — 10x slower.\n- Do NOT run full test suite on every code change — use `--filter`.\n- Do NOT add test-only indexes — fix test design instead.\n- Do NOT disable parallel testing to \"fix\" flaky tests — fix the root cause.\n\n## Where the time goes, per ecosystem\n\nThe diagnosis above is PHPUnit-shaped. The method — measure before optimising,\nfind the slowest tests first, separate setup cost from assertion cost —\ntransfers; the instrument does not. Resolve the runner with\n`resolve_toolchain` and read its `ecosystems`:\n\n| `ecosystems` | Slowest-test instrument | The usual first cause |\n|---|---|---|\n| `php` | `--profile` \u002F Pest's duration column | database refresh per test |\n| `js` | `vitest --reporter=verbose`, `jest --detectOpenHandles` | module transform and a leaked handle |\n| `python` | `pytest --durations=20` | session-scoped fixtures rebuilt per test |\n| `go` | `go test -v`, `-cpuprofile`, `-race` for the slow-and-flaky pair | a `TestMain` that starts real I\u002FO |\n\n`go test` caches a package's result until its inputs change, so a suite that\nlooks fast on the second run may not have run at all — `-count=1` defeats the\ncache when you are measuring.\n","# test-performance\n\n## When to use\n\nUse this skill when:\n\n- Tests are running too slowly (locally or in CI)\n- Database setup\u002Fteardown is a bottleneck\n- Parallel testing needs optimization\n- Seeders need performance analysis\n- CI pipeline test jobs need to be faster\n- Investigating flaky tests caused by database state\n\n## Procedure: Analyze test performance\n\n### 1. Measure baseline\n\nBefore optimizing, always measure:\n\n```bash\n# Count tests per suite\nfind tests\u002F app\u002FModules\u002F*\u002FTests\u002F -name \"*.php\" | xargs grep -l \"it(\" | wc -l\n\n# Count by suite type\ngrep -rh \"it(\" tests\u002FUnit\u002F app\u002FModules\u002F*\u002FTests\u002FUnit\u002F --include=\"*.php\" | wc -l\ngrep -rh \"it(\" tests\u002FComponent\u002F app\u002FModules\u002F*\u002FTests\u002FComponent\u002F --include=\"*.php\" | wc -l\ngrep -rh \"it(\" tests\u002FIntegration\u002F app\u002FModules\u002F*\u002FTests\u002FIntegration\u002F --include=\"*.php\" | wc -l\n\n# Count migrations\nls database\u002Fmigrations\u002F*.php | wc -l\n\n# Count seeders\nfind database\u002Fseeders database\u002Fseeder-data -name \"*.php\" -path \"*\u002Fdata\u002F*\" | wc -l\n```\n\n### 2. Identify bottlenecks\n\nThe typical test lifecycle is:\n\n```\nProcess Start → Migrate → Seed → [Test → Rollback] × N → Process End\n                 ↑ expensive (once per worker)\n```\n\nCheck these areas in order of typical impact:\n\n| Area | What to check | Typical impact |\n|------|--------------|---------------|\n| **Migration count** | How many CREATE TABLE statements? | High if >20 |\n| **Schema dump** | Is `database\u002Fschema\u002F` used? | High if missing |\n| **Seeder INSERT method** | Individual `save()` vs bulk insert? | Medium |\n| **Truncation** | Per-seeder truncate vs centralized? | Low (but causes correctness issues) |\n| **Connection discovery** | Dynamic `getPdo()` probing? | Low |\n| **Parallel worker setup** | Does each worker re-migrate? | High |\n\n### 3. Optimization strategies (ordered by ROI)\n\n#### A. Schema Dump (highest ROI)\n\nLaravel's `schema:dump` consolidates all migrations into one SQL file.\nInstead of running N individual CREATE TABLE migrations, it loads one SQL dump.\n\n```bash\nphp artisan schema:dump --database=api_database\n# Generates database\u002Fschema\u002Fapi_database-schema.sql\n```\n\n**Savings:** 58 migrations → 1 SQL load = ~10-25s per worker.\n\n#### B. Template DB Cloning (high ROI for parallel tests)\n\nInstead of each parallel worker running migrate+seed independently:\n1. Prepare ONE template database (migrate + seed)\n2. Clone template for each worker via mysqldump\n\n```bash\n# Prepare template\nphp artisan migrate:fresh --database=template_db\nphp artisan db:seed --database=template_db\n\n# Clone per worker\nmysqldump template_db | mysql worker_db_test_1\n```\n\n**Savings:** Eliminate per-worker migrate+seed entirely.\n\n#### C. Skip Migrate+Seed Flag (high ROI for local dev)\n\nAdd a config flag to skip database setup when DB is already prepared:\n\n```php\n\u002F\u002F config\u002Ftesting.php\n'skip_migrate_seed' => EnvHelper::boolean('TESTING_SKIP_MIGRATE_SEED', false),\n```\n\nDeveloper workflow: `make migrate-testing` once, then `make test-quick` repeatedly.\n\n#### D. Bulk Inserts in Seeders (medium ROI)\n\nReplace individual `$model->save()` with bulk insert:\n\n```php\n\u002F\u002F Before: N INSERT statements\nforeach ($data as $row) {\n    $model = new MyModel($row);\n    $model->save();\n}\n\n\u002F\u002F After: 1 INSERT statement\nMyModel::insert($data);\n$models = MyModel::whereIn('id', $ids)->get();\n```\n\n#### E. Centralize Truncation (correctness fix)\n\nPer-seeder truncation is redundant after `migrate:fresh` and causes:\n- Non-deterministic ordering (lazy init triggers truncate)\n- Ghost data bugs (locally passes, CI fails)\n\nMake truncation configurable, default off:\n\n```php\n\u002F\u002F config\u002Ftesting.php\n'seed_truncate' => EnvHelper::boolean('DB_SEED_TRUNCATE', false),\n```\n\n#### F. Static Connection Discovery (cleanup)\n\nReplace dynamic `getPdo()` probing with explicit config:\n\n```php\n\u002F\u002F config\u002Ftesting.php\n'connections_to_transact' => ['api_database', 'customer_database'],\n```\n\n### 4. CI-specific optimizations\n\n- **MariaDB tmpfs:** Mount data dir on RAM disk for zero I\u002FO latency\n- **Shared DB prep:** One CI job prepares DB, test jobs clone from it\n- **Cache test DBs:** Skip re-migration if migration files haven't changed\n- **Separate suites:** Run no-DB tests (Unit) on cheaper runners\n\n## Related project docs\n\n- `agents\u002Freference\u002Fdocs\u002Fseeders.md` — seeder conventions (if exists)\n\n## Output format\n\n1. Optimized test configuration or seeder with timing comparison\n2. Parallelization or caching improvements applied\n\n## Gotcha\n\n- Don't use RefreshDatabase when DatabaseTransactions suffices — full refresh is 10x slower.\n- The model forgets that parallel tests share the database — use unique identifiers in test data.\n- Seeder optimization has the highest ROI — a 2s seeder running 100 times = 200s wasted.\n- Don't add indexes to test databases just for test performance — the real fix is better test design.\n\n\n## Do NOT\n\n- Do NOT use RefreshDatabase when DatabaseTransactions works — 10x slower.\n- Do NOT run full test suite on every code change — use `--filter`.\n- Do NOT add test-only indexes — fix test design instead.\n- Do NOT disable parallel testing to \"fix\" flaky tests — fix the root cause.\n\n## Where the time goes, per ecosystem\n\nThe diagnosis above is PHPUnit-shaped. The method — measure before optimising,\nfind the slowest tests first, separate setup cost from assertion cost —\ntransfers; the instrument does not. Resolve the runner with\n`resolve_toolchain` and read its `ecosystems`:\n\n| `ecosystems` | Slowest-test instrument | The usual first cause |\n|---|---|---|\n| `php` | `--profile` \u002F Pest's duration column | database refresh per test |\n| `js` | `vitest --reporter=verbose`, `jest --detectOpenHandles` | module transform and a leaked handle |\n| `python` | `pytest --durations=20` | session-scoped fixtures rebuilt per test |\n| `go` | `go test -v`, `-cpuprofile`, `-race` for the slow-and-flaky pair | a `TestMain` that starts real I\u002FO |\n\n`go test` caches a package's result until its inputs change, so a suite that\nlooks fast on the second run may not have run at all — `-count=1` defeats the\ncache when you are measuring.\n",{"name":5,"packs":49,"domain":27,"framework":37,"model_tier":51,"workspaces":52,"description":7},[50],"engineering-base","medium",[40],"main","12bd765ce1d800501d45dfb8232102793af01290","src\u002Fskills\u002Ftest-performance",1,"https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config","https:\u002F\u002Fevent4u.app","https:\u002F\u002Fgithub.com\u002Fevent4u-app","Your events in your hand","2026-11-13 03:25:49",{"source":8,"skillName":5,"commands":63,"prompt":73,"zipAvailable":74},[64,67,70],{"tool":65,"command":66},"npx","npx skills add event4u-app\u002Fagent-config --skill test-performance",{"tool":68,"command":69},"bunx","bunx skills add event4u-app\u002Fagent-config --skill test-performance",{"tool":71,"command":72},"pnpm","pnpm dlx skills add event4u-app\u002Fagent-config --skill test-performance","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Fsrc\u002Fskills\u002Ftest-performance\u002FSKILL.md",true,[76],{"path":77,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":80,"sourceHtmlUrl":81},"evals\u002Ftriggers.json","REFERENCE","参考文档",2641,"https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Fsrc\u002Fskills\u002Ftest-performance\u002Fevals\u002Ftriggers.json",[83,99,112,124,136,146],{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":92,"publishedAt":44},"01M6X84PK96XBPENXH66JCTSD1","unknown-key-fixture","Declares a key the schema does not know.","https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Ftests\u002Fscripts\u002Ffixtures\u002Fbody-portable\u002Funknown-key\u002FSKILL.md",[89],{"categoryNo":90,"categoryName":91,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[93,94,95,96,97,98],"unknown key fixture","Unknown key","fixture","unknown","schema","package",{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":106,"publishedAt":44},"01M6X84HW7NAHZ7GZMQ9RXK1XJ","portable-fixture","Declares only semantics the MCP-lite carrier transports whole.","https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Ftests\u002Fscripts\u002Ffixtures\u002Fbody-portable\u002Fportable\u002FSKILL.md",[105],{"categoryNo":90,"categoryName":91,"taxonomyType":21,"taxonomyTypeDesc":22},[95,107,108,109,110,98,111],"portable","portable fixture","engineer","only","MCP",{"skillNo":113,"name":114,"nameZh":6,"description":115,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":119,"publishedAt":44},"01M6X84F29FE0RGGZ1ZTFGZTX2","non-portable-fixture","Declares a runtime semantic the carrier drops.","https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Ftests\u002Fscripts\u002Ffixtures\u002Fbody-portable\u002Fnon-portable\u002FSKILL.md",[118],{"categoryNo":90,"categoryName":91,"taxonomyType":21,"taxonomyTypeDesc":22},[108,120,107,95,121,122,123,98],"non portable fixture","semantic","high","runtime",{"skillNo":125,"name":126,"nameZh":6,"description":127,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":131,"publishedAt":44},"01M6X848F706PT9MDCX75JKJ6B","candidate-zero-width","A candidate whose prose carries an invisible joiner.","https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fskill-scout-candidates\u002Fzero-width-injection\u002FSKILL.md",[130],{"categoryNo":90,"categoryName":91,"taxonomyType":21,"taxonomyTypeDesc":22},[132,133,134,135],"candidate zero width","candidate","ZeRO","prose",{"skillNo":137,"name":138,"nameZh":6,"description":139,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":140,"categories":141,"keywords":143,"publishedAt":44},"01M6X841SSC2T31VDF41SA6DG1","candidate-disclosure-suppression","A candidate whose prose tells the agent to withhold from the user.","https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fskill-scout-candidates\u002Fdisclosure-suppression\u002FSKILL.md",[142],{"categoryNo":90,"categoryName":91,"taxonomyType":21,"taxonomyTypeDesc":22},[144,133,135,145],"candidate disclosure suppression","user",{"skillNo":147,"name":148,"nameZh":6,"description":149,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":150,"categories":151,"keywords":153,"publishedAt":44},"01M6X83TFS5AGPBPVTQNWP0BB3","candidate-dangerous-frontmatter","A candidate claiming an unscoped tool grant and a permission bypass.","https:\u002F\u002Fgithub.com\u002Fevent4u-app\u002Fagent-config\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fskill-scout-candidates\u002Fdangerous-frontmatter\u002FSKILL.md",[152],{"categoryNo":90,"categoryName":91,"taxonomyType":21,"taxonomyTypeDesc":22},[154,133,155,156,157,158],"candidate dangerous frontmatter","frontmatter","shell","permission","tool"]