# tests/ Test files for scripts bundled with this skill. ## When to add tests Add tests here when the skill has scripts in `scripts/` that are complex enough to break silently — validators, parsers, generators, anything with branching logic or edge cases. Test infrastructure (`.bats`, `*_test.*`, `test_*.sh`) belongs here, not in `scripts/`. ## Dependencies Tests require [bats-support](https://github.com/bats-core/bats-support) and [bats-assert](https://github.com/bats-core/bats-assert). The test files load helpers from the repo root's `tests/test_helper/`. From the repo root: ```bash git clone https://github.com/bats-core/bats-support tests/test_helper/bats-support git clone https://github.com/bats-core/bats-assert tests/test_helper/bats-assert ``` Run all tests for this skill (from the repo root): ```bash bats plugins/kyberforge/.apm/skills/factory-audit/tests/ ``` ## Files | File | Purpose | |------|---------| | `validate-skill.bats` | `scripts/validate.sh` against skill directories | | `validate-agent.bats` | `scripts/validate.sh` against agent files | | `validate-provenance-skill.bats` | `scripts/validate-provenance.sh` against skill directories | | `validate-provenance-agent.bats` | `scripts/validate-provenance.sh` against agent files | ## Two scripts, four suites `factory-audit` merges what were two skills — `skill-audit` and `agent-audit` — each of which shipped its own `validate.sh` and `validate-provenance.sh`. The merged skill has **one** of each. Every suite here invokes one of those two scripts; the four files are two scripts × two artifact types, not four scripts. `validate-skill.bats` and `validate-agent.bats` run the same `scripts/validate.sh` and differ only in the fixtures they point it at. The two provenance suites stand in the same relation to `scripts/validate-provenance.sh`. Do not add a third script path here on the assumption that a differently named suite must mean a differently named script. ### Auto-detection is pinned across the pair Each entry point decides for itself what it was handed. ADR-0025 states the rule: a directory containing `SKILL.md` takes the skill flow; an `.agent.md` file, or a file under a directory named `agents/`, takes the agent flow. Anything else is rejected rather than guessed at. That behaviour is new with the merge — before it, each script was hard-wired to one artifact type and nothing about classification could be wrong — so it is asserted from both sides rather than in one place: - the skill-side suites pin the skill-directory classification and the neither-shape rejection, - the agent-side suites pin the two agent rules *separately* — `.agent.md` in a directory that is not `agents/`, and a plain `.md` under `.apm/agents/` — so that a detector implementing only one of them cannot pass both. Plus a control asserting an agent file never picks up a skill-only gate. Both skill-side suites additionally pin the `SKILL.md` **file** path, not just the directory: a pre-commit `files:` hook matches files, so every hook-driven invocation hands over a `SKILL.md` path. Each entry point resolves it to the directory, and the suites assert the two spellings produce the identical verdict rather than merely that the file spelling survives. A misclassification is silent and total — the wrong rubric runs end to end and reports the artifact clean against gates that never applied to it — and no other fixture in these suites would notice, because every other fixture is already the shape its own suite expects. ### The two provenance exit contracts are different on purpose `scripts/validate-provenance.sh` does **not** behave identically in its two modes, and the difference is deliberate: | Mode | Successful run | |------|----------------| | skill | may exit 0 **with** output — INFO findings print, status stays 0 | | agent | exits 0 and prints **nothing** | Each half is asserted from its own side, by the `exit contract:` test in each provenance suite. Both are asserted on purpose: a merge that collapsed one contract into the other would still satisfy whichever side was left unasserted, so a single-sided pin would go green on exactly the defect it exists to catch.