--- id: PX-PLAN-XQFSKHHG type: plan title: Layered Test Architecture and Owned Fixture spec: PX-SPEC-DZLVGRW4 status: draft depends_on: - PX-PLAN-RMJ8BIOX --- ## Outcome Tests are separated by guarantee: unit, Pi contract, native integration, generated package, UI acceptance. A repository-owned fixture replaces the text-patched `@marcfargas/pi-test-harness`. One Vitest coordinator runs all source layers with required isolation; TypeScript checking covers every maintained file. Verified current state: `scripts/patch_pi_test_harness.mjs` rewrites installed harness files at install; 37 extensions have `__tests__/harness.test.ts`; `test/harness.ts` wraps the harness; `vitest.config.ts` has four projects; `tsconfig.json` excludes tests, benches, scripts, and `the-system/index.ts`. ## Behaviors ```mermaid flowchart TB t1["1. Owned fixture runs ultra contract test unpatched"] --> t2["2. All harness tests migrate; patch script deleted"] t2 --> t3["3. Layer projects in one Vitest coordinator"] t3 --> t4["4. Generated-package project runs snapshots outside checkout"] t3 --> t5["5. Complete typecheck; focused check per extension"] t4 --> t6["6. UI acceptance runs against generated browser artifacts"] ``` 1. `test/fixture/` exposes `createPiSession` built on public `createAgentSession`, `SessionManager.inMemory`, `ModelRuntime`, and a deterministic scripted provider; owns temp dirs, env, sockets, timers, shutdown; rejects on any unexpected extension or async error. `extensions/ultra/__tests__/harness.test.ts` becomes `contract.test.ts` on the fixture. 2. Migrate remaining `harness.test.ts` files; remove the harness devDependency from every extension manifest, `test/harness.ts`, `scripts/patch_pi_test_harness.mjs`, and the install step; static check requires `__tests__/contract.test.ts`. 3. `vitest.config.ts` projects by guarantee: `unit` (isolate false, workers), `contract` (isolate true), `native` (isolate true, one worker, per-file process env), `web`, `strata` retained as native members; `validator` folds into `native`. Property tests live in `unit` with seeded runners and retained regression cases. 4. `packages` project: for each `dist/` snapshot in a temp root, install an independent Pi version, load, assert manifests, resources, lazy first use, workers, allowed externals, no workspace leakage; one composite run for the complete collection. Runs only when `dist` exists; `//:verify-packages` from the packages plan becomes this project. 5. `tsconfig.json` includes tests, benches, fixtures, workers, browser entrypoints, build and codegen TypeScript; per-extension `tsconfig.json` extends root and includes shared `test/` inputs; `//extensions/:check` runs focused `tsc -p`; root `//:check` runs the union once. Convert remaining `.mjs` automation to TypeScript unless it bootstraps the build. 6. Playwright suites (`mockup`, `strata`, `the-system`, `chrome-cdp`, `klaus`) serve generated browser assets from `dist/` rather than source. ## Fixture structure ```mermaid classDiagram PiSession --> ScriptedProvider : streams PiSession --> ResourceOwner : owns PiSession --> ErrorSink : fails on ContractTest --> PiSession : loads entrypoint PackageTest --> PiSession : loads dist snapshot ``` Touched: `test/fixture/*`, `test/harness.ts` (removed), `scripts/patch_pi_test_harness.mjs` (removed), `mise.toml` install task, `vitest.config.ts`, `tsconfig.json`, `extensions/*/tsconfig.json`, `extensions/*/__tests__/*`, `extensions/*/package.json`, `scripts/extensions.mjs` static check, `extensions/*/playwright.config.ts`. ## Constraints - No private Pi properties, no `as any` reach into agent internals; if the public API lacks a hook, the fixture narrows scope rather than patching. - Concurrent sessions in one process share `process.env`; tests needing distinct env run in `native` with process isolation. - Snapshots normalize volatile paths, timestamps, identifiers. ## Verification - [ ] `mise run //:install` performs no dependency patching. - [ ] No extension depends on `@marcfargas/pi-test-harness`. - [ ] `//:test` runs one coordinator with layered projects; contract and native retain isolation. - [ ] `packages` project passes for every extension and the composed collection. - [ ] `tsc` covers all maintained TypeScript; `//extensions/ultra:check` typechecks only ultra plus shared inputs. - [ ] UI acceptance loads assets from `dist`.