Five-layer pyramid:
- Unit (
bun test) — Engine logic, Vault contracts, HITL invariants, manifest validation. Co-located with source. Runs in milliseconds. - Integration (
bun test+ real SQLite) — connector sync, index queries, extension loading and isolation. Each test gets a fresh temp dir + fresh DB. - E2E CLI (
bun test+ Gateway subprocess) — full CLI command flows against a real Gateway backed by mock MCP servers. - UI Components (Vitest + Testing Library) — React components in the Tauri WebView. Vitest is used here because
bun testdoes not support jsdom. - E2E Desktop (Playwright + Tauri WebDriver) — full desktop flows on all three platforms. Runs on push to
mainonly (ci.yml'se2e-desktopjob is gated ongithub.ref == 'refs/heads/main', so a release tag does not run it).
Security scans: bun audit, trivy, CodeQL on every PR; Dependabot alerts for vulnerable dependencies (updates are manual, see CONTRIBUTING.md § Updating Dependencies). HIGH/CRITICAL findings block merges unless scripts/structure-audit/accepted-advisories.ts holds an open, dated acceptance for one that has no fix, and bun run audit:advisories blocks any live advisory, of any severity, that has no current dated decision there — see security-hardening.md. License compatibility (bun run audit:js-licenses + cargo-deny) and committed-secret detection (gitleaks) are also enforced on every PR — see license-policy.md and SECURITY.md.
Structure-audit gates (also CI-enforced) sit alongside the test pyramid:
bun run audit:invariants— runtime-test complement: static rulesD10–D31, coveringI1(spawnunderconnectors/usesextensionProcessEnv()), the vault-key allow-list (D11),I14(D12— directdb.run/db.execoutsidedb/write.ts),I15(D10— everyServerSpecunderconnectors/lazy-mesh/routes throughwrapServerSpec(...)), and aD-numbered rule each (several of them multi-part) forI17–I19,I22–I27,I29,I33,I35,I37,I38andI39(whoseD29(d)also confinesI40's saved-tool accessor).D24,D25,D30andD31guard no invariant: the SyncContext capability boundary, hidden connector spawns, full-SQLite initialisation and listener registration. The runtime tests insecurity-invariants.test.tsstay authoritative; this gate just fails first. SeeSECURITY-INVARIANTS.mdfor the rule-to-invariant map.bun run audit:openapi-drift— fails ifpackages/gateway/openapi/v1.yamlandHTTP_ROUTESdisagree.bun run audit:coverage-floor— per-file coverage floor (≥85% line, ≥80% branch) with a ratcheting baseline; prevents new files from landing under-tested.bun run audit:boundaries,audit:dead-code,audit:duplication,audit:any— package-boundary / unused-export / token-duplication /any-usage gates (Phase 4 B3 structure audit).
For the full per-subsystem coverage-gate table (test:coverage:engine / agents / vault / sandbox / embedding / metrics / preflight / deployment and a dozen more) and the environment-variable overrides each gate respects, see the nimbus-commands skill / reference file.
For deeper detail on which test layer to use for each subsystem, see .claude/commands/nimbus-testing.md.