[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6NKBCWSSXVQTMTT722F2Z95":3,"skill-same:01M6NKBCWSSXVQTMTT722F2Z95":49},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":21,"linkOnly":22,"markdownContent":23,"markdownBody":24,"frontMatter":25,"refName":26,"commitSha":27,"skillDirectory":28,"forksCount":29,"repositoryHtmlUrl":30,"repositoryHomepageUrl":6,"ownerHtmlUrl":31,"ownerBlogUrl":32,"ownerDescription":33,"updatedAt":34,"install":35,"resources":48},"01M6NKBCWSSXVQTMTT722F2Z95","run-tests",null,"joelbarmettlerUZH\u002Fultrainit.sh","joelbarmettlerUZH","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F24369532?v=4","01M6NK9DS0035TVQP3EQ36E14N","Joel Barmettler","01M6NK9DXBM5D1GYV4414HX06T",8,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Frun-tests\u002FSKILL.md",[],[18,19,20],"run tests","run","tests","2026-11-10 10:12:30",false,"---\nname: run-tests\ndescription: \"\n  Run the bats-core test suite for ultrainit inside Docker and interpret\n  results. Use when run tests, check tests pass, make test-unit, verify\n  nothing broke, or debugging a failing test. Covers all test tiers: unit,\n  scripts, edge, integration. Do NOT use for smoke tests — those make real\n  API calls and cost real money.\n---\n\n## Before You Start\n\n- `Makefile` — all test targets and their Docker invocations\n- `tests\u002Fhelpers\u002Ftest_helper.bash` — `_common_setup`, `make_claude_envelope`\n- `tests\u002Fhelpers\u002Fmock_claude.bash` — `setup_mock_claude`, dispatch mode\n- `Dockerfile.test` — the test image (must be built if changed)\n\n## Test Tiers\n\n| Command | What it tests | Speed |\n|---------|---------------|-------|\n| `make test-unit` | Individual `lib\u002F*.sh` functions | ~30s |\n| `make test-scripts` | `scripts\u002Fvalidate-skill.sh`, `scripts\u002Fvalidate-subagent.sh` | ~15s |\n| `make test-edge` | Budget exhaustion, corrupt state, special chars, numeric edge cases | ~20s |\n| `make test-integration` | Phase-level pipeline (gather, synthesize, resume) | ~60s |\n| `make test-all` | All of the above | ~2min |\n\n## Running Tests\n\n### Full suite\n\n```bash\nmake test-all\n```\n\n### Single tier\n\n```bash\nmake test-unit        # fastest, run after every lib change\nmake test-scripts     # after changes to scripts\u002Fvalidate-*.sh\nmake test-edge        # after changes to budget, config, or CLI arg handling\nmake test-integration # after changes to gather.sh, synthesize.sh, or merge.sh\n```\n\n### Single .bats file\n\nThe Makefile targets use Docker. To run one file, use the docker command directly:\n\n```bash\ndocker run --rm \\\n    -v \"$(pwd)\":\u002Fworkspace \\\n    -w \u002Fworkspace \\\n    ghcr.io\u002Fjoelbarmettleruzh\u002Fultrainit-test:latest \\\n    bats tests\u002Funit\u002Fagent_run.bats\n```\n\n### Verbose output\n\nAdd `--tap` for TAP format or `--verbose-run` for assertion details:\n\n```bash\ndocker run --rm -v \"$(pwd)\":\u002Fworkspace -w \u002Fworkspace \\\n    ghcr.io\u002Fjoelbarmettleruzh\u002Fultrainit-test:latest \\\n    bats --verbose-run tests\u002Funit\u002Fagent_run.bats\n```\n\n## Interpreting Output\n\n- `ok N - test name` = pass\n- `not ok N - test name` = fail, followed by assertion details\n- `# (from function ... source ... line N)` = exact location of failed assertion\n\n**Integration tests always show green** in CI even when failing — they run with `|| true` in `.github\u002Fworkflows\u002Ftest.yml`. After `make test-integration`, read the output explicitly.\n\n## Debugging a Failing Test\n\n### 1. Find the tmpdir\n\nAdd `echo \"TMPDIR: $TEST_TMPDIR\" >&3` inside the failing `@test` body (bats redirects `>&3` to the terminal). Run the test in verbose mode.\n\n### 2. Inspect mock logs\n\n```bash\ncat $TEST_TMPDIR\u002F.ultrainit\u002Fmock_claude.log  # all mock invocations\n```\n\nLook for `CALL:` lines. If the mock was never called when it should have been, check if `setup_mock_claude` was called in `setup()`.\n\n### 3. Check dispatch matching\n\nDispatch mode matches agent name from the `--json-schema` argument basename (case-insensitive substring). If `docs` matches before `docs-scanner`, rename the dispatch file: longer\u002Fmore-specific names first alphabetically.\n\n### 4. Verify envelope wrapping\n\nPassing raw fixture JSON where an envelope is expected causes `run_agent` to extract `.structured_output` as `null`, writing `\"null\"` to the findings file silently:\n\n```bash\n# Wrong — raw JSON, no envelope\ncat tests\u002Ffixtures\u002Ffindings\u002Fidentity.json > \"$MOCK_CLAUDE_RESPONSE\"\n\n# Correct — envelope-wrapped\nmake_claude_envelope \"$(cat tests\u002Ffixtures\u002Ffindings\u002Fidentity.json)\" \"0.15\" > \"$MOCK_CLAUDE_RESPONSE\"\n```\n\n## Building the Test Image\n\nOnly needed when `Dockerfile.test` changes:\n\n```bash\nmake test-image   # builds locally\n```\n\nThe CI image is pulled from `ghcr.io\u002Fjoelbarmettleruzh\u002Fultrainit-test:latest`. If the image doesn't exist yet on a fresh fork, run `make test-image` first.\n","## Before You Start\n\n- `Makefile` — all test targets and their Docker invocations\n- `tests\u002Fhelpers\u002Ftest_helper.bash` — `_common_setup`, `make_claude_envelope`\n- `tests\u002Fhelpers\u002Fmock_claude.bash` — `setup_mock_claude`, dispatch mode\n- `Dockerfile.test` — the test image (must be built if changed)\n\n## Test Tiers\n\n| Command | What it tests | Speed |\n|---------|---------------|-------|\n| `make test-unit` | Individual `lib\u002F*.sh` functions | ~30s |\n| `make test-scripts` | `scripts\u002Fvalidate-skill.sh`, `scripts\u002Fvalidate-subagent.sh` | ~15s |\n| `make test-edge` | Budget exhaustion, corrupt state, special chars, numeric edge cases | ~20s |\n| `make test-integration` | Phase-level pipeline (gather, synthesize, resume) | ~60s |\n| `make test-all` | All of the above | ~2min |\n\n## Running Tests\n\n### Full suite\n\n```bash\nmake test-all\n```\n\n### Single tier\n\n```bash\nmake test-unit        # fastest, run after every lib change\nmake test-scripts     # after changes to scripts\u002Fvalidate-*.sh\nmake test-edge        # after changes to budget, config, or CLI arg handling\nmake test-integration # after changes to gather.sh, synthesize.sh, or merge.sh\n```\n\n### Single .bats file\n\nThe Makefile targets use Docker. To run one file, use the docker command directly:\n\n```bash\ndocker run --rm \\\n    -v \"$(pwd)\":\u002Fworkspace \\\n    -w \u002Fworkspace \\\n    ghcr.io\u002Fjoelbarmettleruzh\u002Fultrainit-test:latest \\\n    bats tests\u002Funit\u002Fagent_run.bats\n```\n\n### Verbose output\n\nAdd `--tap` for TAP format or `--verbose-run` for assertion details:\n\n```bash\ndocker run --rm -v \"$(pwd)\":\u002Fworkspace -w \u002Fworkspace \\\n    ghcr.io\u002Fjoelbarmettleruzh\u002Fultrainit-test:latest \\\n    bats --verbose-run tests\u002Funit\u002Fagent_run.bats\n```\n\n## Interpreting Output\n\n- `ok N - test name` = pass\n- `not ok N - test name` = fail, followed by assertion details\n- `# (from function ... source ... line N)` = exact location of failed assertion\n\n**Integration tests always show green** in CI even when failing — they run with `|| true` in `.github\u002Fworkflows\u002Ftest.yml`. After `make test-integration`, read the output explicitly.\n\n## Debugging a Failing Test\n\n### 1. Find the tmpdir\n\nAdd `echo \"TMPDIR: $TEST_TMPDIR\" >&3` inside the failing `@test` body (bats redirects `>&3` to the terminal). Run the test in verbose mode.\n\n### 2. Inspect mock logs\n\n```bash\ncat $TEST_TMPDIR\u002F.ultrainit\u002Fmock_claude.log  # all mock invocations\n```\n\nLook for `CALL:` lines. If the mock was never called when it should have been, check if `setup_mock_claude` was called in `setup()`.\n\n### 3. Check dispatch matching\n\nDispatch mode matches agent name from the `--json-schema` argument basename (case-insensitive substring). If `docs` matches before `docs-scanner`, rename the dispatch file: longer\u002Fmore-specific names first alphabetically.\n\n### 4. Verify envelope wrapping\n\nPassing raw fixture JSON where an envelope is expected causes `run_agent` to extract `.structured_output` as `null`, writing `\"null\"` to the findings file silently:\n\n```bash\n# Wrong — raw JSON, no envelope\ncat tests\u002Ffixtures\u002Ffindings\u002Fidentity.json > \"$MOCK_CLAUDE_RESPONSE\"\n\n# Correct — envelope-wrapped\nmake_claude_envelope \"$(cat tests\u002Ffixtures\u002Ffindings\u002Fidentity.json)\" \"0.15\" > \"$MOCK_CLAUDE_RESPONSE\"\n```\n\n## Building the Test Image\n\nOnly needed when `Dockerfile.test` changes:\n\n```bash\nmake test-image   # builds locally\n```\n\nThe CI image is pulled from `ghcr.io\u002Fjoelbarmettleruzh\u002Fultrainit-test:latest`. If the image doesn't exist yet on a fresh fork, run `make test-image` first.\n",{},"main","197708b955e457c87d304fdf3389621f7e2f202a",".claude\u002Fskills\u002Frun-tests",1,"https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh","https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH","https:\u002F\u002Fjoelbarmettler.xyz","M. Sc. Artificial Intelligence \r\n& Senior A.I. Architect","2026-11-02 02:33:53",{"source":7,"skillName":5,"commands":36,"prompt":46,"zipAvailable":47},[37,40,43],{"tool":38,"command":39},"npx","npx skills add joelbarmettlerUZH\u002Fultrainit.sh --skill run-tests",{"tool":41,"command":42},"bunx","bunx skills add joelbarmettlerUZH\u002Fultrainit.sh --skill run-tests",{"tool":44,"command":45},"pnpm","pnpm dlx skills add joelbarmettlerUZH\u002Fultrainit.sh --skill run-tests","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Frun-tests\u002FSKILL.md",true,[],[50,84,94,109,119,129],{"skillNo":51,"name":52,"nameZh":6,"description":53,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":54,"categories":55,"keywords":64,"publishedAt":21},"01M6NKEDBGZBAT592SECRS8E4N","valid-skill","Use when building or modifying API endpoints in src\u002Fapi\u002F. Covers route creation, middleware wiring, and request validation. Do NOT use for frontend components or static pages.","https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fskills\u002Fvalid-skill\u002FSKILL.md",[56,61],{"categoryNo":57,"categoryName":58,"taxonomyType":59,"taxonomyTypeDesc":60},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",{"categoryNo":62,"categoryName":63,"taxonomyType":59,"taxonomyTypeDesc":60},"01JBSEEDCAT000000000000023","Skill与智能体开发",[65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83],"valid","valid skill","endpoints","request","do","route","creation","pages","middleware","frontend components","for","wiring","static","use","src","api","validation","components","frontend",{"skillNo":85,"name":86,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":90,"publishedAt":21},"01M6NKEAC2NAMBFHT0S0PRYQKN","invalid-skill-no-desc","https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fskills\u002Finvalid-skill-no-desc\u002FSKILL.md",[89],{"categoryNo":62,"categoryName":63,"taxonomyType":59,"taxonomyTypeDesc":60},[91,92,93],"invalid skill no desc","invalid","invalid skill",{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":101,"publishedAt":21},"01M6NKE7MF1YCS3WCQA5AY3ZXP","invalid-skill-angle-brackets","Use when working with \u003Ccomponent> templates. Do NOT use for \u003Cother> things.","https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fskills\u002Finvalid-skill-angle-brackets\u002FSKILL.md",[100],{"categoryNo":62,"categoryName":63,"taxonomyType":59,"taxonomyTypeDesc":60},[102,103,104,92,93,105,106,75,107,69,78,108],"invalid skill angle brackets","angle brackets","brackets","component","things","with","templates",{"skillNo":110,"name":111,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":21},"01M6NKE4EJ5EWNN7S5FJ1SFZR5","validate-generated-artifact","https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh\u002Fblob\u002Fmain\u002F.ultrainit\u002Fvalidation\u002Fskills\u002Fvalidate-generated-artifact\u002FSKILL.md",[],[115,116,117,118],"validate generated artifact","artifact","generated","validate",{"skillNo":120,"name":121,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":21},"01M6NKE157C519F1W8WHGXPRTK","tune-synthesis-context","https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh\u002Fblob\u002Fmain\u002F.ultrainit\u002Fvalidation\u002Fskills\u002Ftune-synthesis-context\u002FSKILL.md",[],[125,126,127,128],"tune synthesis context","tune","Synthesis","context",{"skillNo":130,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":133,"publishedAt":21},"01M6NKDT0VD32KKE2HTHT30FWH","https:\u002F\u002Fgithub.com\u002FjoelbarmettlerUZH\u002Fultrainit.sh\u002Fblob\u002Fmain\u002F.ultrainit\u002Fvalidation\u002Fskills\u002Frun-tests\u002FSKILL.md",[],[19,18,20]]