--- description: Isolation and credential tests need root and use test.skipIf(!IS_ROOT); locally 5 skip, CI runs as root so all 61 run; verify isolation changes in node:24-bookworm as root --- Some tests exercise real UID isolation, process cleanup, and `prepare.ts` credential cleanup. They need root and are written as `test.skipIf(!IS_ROOT)(...)` (`IS_ROOT` from `src/testing.ts`), so they show as skipped instead of silently passing. - As a normal user `vp test` passes 56 and skips 5. In CI (self-hosted runner, root) all 61 run. - When changing `isolation.ts`, `runtime.ts`, `credentials.ts`, `prepare.ts`, or `command.ts`, run the suite as root in `node:24-bookworm` (e.g. a container with the repo mounted) before pushing; a green non-root run proves nothing about those paths. - The migration also ran an end-to-end smoke as root with fake `codex`/`claude`/`npx` binaries and a fake Gitea through `protect-source.sh` -> `prepare.ts` -> `run.ts` -> `post.ts`; repeat that for changes to the phase flow ([[bot-agents-runtime-no-build]]). - `src/testing.ts` holds the shared test helpers and is the `#testing` file alias. Every test imports it as `#testing`, never `./testing.ts`, and it re-exports the source helpers `tests/` needs, since `tests/` may not use `../`. Tests follow [[tests-layout-vitest]] (unit tests in `src/*.test.ts`, repo-level ones in `tests/`).