From 536601c3ba62f6fa203612cad720980c6c3beb9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 15 Oct 2026 15:39:28 +0200 Subject: [PATCH 1/2] docs: say where tests and fixtures live and which rules hold it AGENTS.md states the two colocation conventions (index- package tests, test/repo-guards/ for repo-level guards) and the no-test-exports rule with test-kit as the only home for shared helpers; docs/agents/testing.md carries the test-kit placement rules (packages it builds on keep helpers local, no test-kit import in a vi.mock factory) inside the existing docs/agents byte budget. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 7 +++++++ docs/agents/test-audit.md | 2 +- docs/agents/testing.md | 23 +++++++++++------------ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b46d4d2d98..399b81c13a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,6 +91,13 @@ under `contracts/fixtures/`. - Tests mirror source topology one-to-one. Split a source module and its test together; do not add to the legacy `interaction.test.ts` or platform `index.test.ts` aggregations. Pure moves carry their tests unchanged; rename-only hunks owe no new coverage. +- A test sits beside the module it is named for: `.test.ts` or `-.test.ts` + (R84). Cross-module package tests are `index-.test.ts` beside `index.ts`; repo-level guards on + Swift sources, manifests, docs or scripts live in `test/repo-guards/`. +- No package `exports` entry points at test support (R83). A fixture one package uses stays inside + it, imported relatively; helpers shared across packages live only in `@agent-device/test-kit`, a + `devDependency` production source never imports and that never depends on `platform-*`, + `provider-*`, the daemon or root. ## Toolchain and worktree traps diff --git a/docs/agents/test-audit.md b/docs/agents/test-audit.md index b6d2ef3351..b6968b4479 100644 --- a/docs/agents/test-audit.md +++ b/docs/agents/test-audit.md @@ -24,7 +24,7 @@ Authoring rejects; audits hunt: - type pins posing as runtime assertions (`Equal = true`, `X ? true : never`, `satisfies` after erasure, `toHaveLength(n)` over literals); if erasing leaves nothing executable, use `void [fixtures]`; - mocks asserting their own inputs; negative controls passing for the wrong reason; - names promising more than the input exercises; -- dead code called only by tests; tests preserving test-only exports. +- dead code called only by tests; tests preserving test-only exports; an `exports` entry only tests import. ## Retention criteria diff --git a/docs/agents/testing.md b/docs/agents/testing.md index b42194f5d5..3928d91fce 100644 --- a/docs/agents/testing.md +++ b/docs/agents/testing.md @@ -32,9 +32,8 @@ Two selection traps recur: - A workspace package manifest or TypeScript config can rewire all consumers, so the affected selector fails open to the full gate set on purpose. -Docs-only changes with no runtime behavior impact need no runtime tests or new tests asserting prose. -Keep required gates; after those and focused checks pass, repeat or broaden only for changes, -failures, or unresolved risks. +Docs-only changes need no runtime tests or tests asserting prose. After the required gates, repeat +or broaden only for changes, failures, or unresolved risks. ## Platform and live-device policy @@ -67,13 +66,13 @@ Read the entry file before running a lane. Do not copy its environment matrix he ## Shared test utilities -Before creating fixtures, look in `@agent-device/test-kit/` (generic) and -`packages/daemon/src/__tests__/support/` (daemon-shaped). Import named builders from their -defining module, never through a barrel. Shared `DeviceInfo`, session, snapshot, store, -runtime-fact, and mocked-binary values belong in a sibling fixture module, not in repeated -test literals. `PROPERTY_RUNS` and the touch-point/rect arbitraries live in -`@agent-device/selectors/snapshot-geometry-fixtures`; -`makeSnapshotState` lives in `@agent-device/capture-kit/snapshot-state-fixtures`. +Before creating fixtures, look in `@agent-device/test-kit` and +`packages/daemon/src/__tests__/support/`. Shared `DeviceInfo`, session, snapshot, store, +runtime-fact, and mocked-binary values belong in a sibling fixture module, not in repeated test +literals; a fixture one package uses is a `*.fixtures.ts` beside its module. The packages test-kit +builds on (kernel, contracts, capture-kit, host-kit, command-registry, daemon-contracts) cannot +declare it; their tests keep helpers local. Never import test-kit in a `vi.mock` factory: it loads +the module being mocked; spy it in place, as `pinOwnProcessStartTime` does. Use `mkdtempForTest` or `mkdtempForTestSync`. Global setup redirects `TMPDIR` for the run and removes it after every worker exits — skip per-test cleanup. An interrupted run may leave a @@ -109,8 +108,8 @@ For structured classifiers, pair the positive case with the closest negative. Wh can be identical with and without a typed reason, the negative test must prove the message alone cannot activate retry, fallback, or recovery. -Test through public interfaces where practical; never add production exports or test-only -dependency injection — a missing seam needs a real product seam. +Test through public interfaces; never add production exports or test-only dependency injection — a +missing seam needs a real product seam. ## Properties, fuzzing, and mutation From c10f6a2de64b177ba64de472c5490ef819272dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 15 Oct 2026 16:31:28 +0200 Subject: [PATCH 2/2] docs: describe R83 as a ratchet and qualify the test-kit mock-factory rule AGENTS.md says to add no test-support exports and that the legacy count only falls; test-audit limits the junk pattern to production-package exports (test-kit's entry is intentional); testing.md names the modules whose mock factories must not import test-kit and notes that still-exported fixtures stay importable until moved. A fuzz-harness sentence that restated the harness is dropped to stay inside the docs/agents byte budget. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 4 ++-- docs/agents/test-audit.md | 2 +- docs/agents/testing.md | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 399b81c13a..f2ee773328 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -94,8 +94,8 @@ under `contracts/fixtures/`. - A test sits beside the module it is named for: `.test.ts` or `-.test.ts` (R84). Cross-module package tests are `index-.test.ts` beside `index.ts`; repo-level guards on Swift sources, manifests, docs or scripts live in `test/repo-guards/`. -- No package `exports` entry points at test support (R83). A fixture one package uses stays inside - it, imported relatively; helpers shared across packages live only in `@agent-device/test-kit`, a +- Add no package `exports` entry that points at test support; R83 only lets the legacy count fall. A + fixture one package uses stays inside it, imported relatively; helpers shared across packages live only in `@agent-device/test-kit`, a `devDependency` production source never imports and that never depends on `platform-*`, `provider-*`, the daemon or root. diff --git a/docs/agents/test-audit.md b/docs/agents/test-audit.md index b6968b4479..533841567c 100644 --- a/docs/agents/test-audit.md +++ b/docs/agents/test-audit.md @@ -24,7 +24,7 @@ Authoring rejects; audits hunt: - type pins posing as runtime assertions (`Equal = true`, `X ? true : never`, `satisfies` after erasure, `toHaveLength(n)` over literals); if erasing leaves nothing executable, use `void [fixtures]`; - mocks asserting their own inputs; negative controls passing for the wrong reason; - names promising more than the input exercises; -- dead code called only by tests; tests preserving test-only exports; an `exports` entry only tests import. +- dead code called only by tests; tests preserving test-only exports; a production package `exports` entry only tests import. ## Retention criteria diff --git a/docs/agents/testing.md b/docs/agents/testing.md index 3928d91fce..b13ba371e3 100644 --- a/docs/agents/testing.md +++ b/docs/agents/testing.md @@ -71,8 +71,10 @@ Before creating fixtures, look in `@agent-device/test-kit` and runtime-fact, and mocked-binary values belong in a sibling fixture module, not in repeated test literals; a fixture one package uses is a `*.fixtures.ts` beside its module. The packages test-kit builds on (kernel, contracts, capture-kit, host-kit, command-registry, daemon-contracts) cannot -declare it; their tests keep helpers local. Never import test-kit in a `vi.mock` factory: it loads -the module being mocked; spy it in place, as `pinOwnProcessStartTime` does. +declare it; their tests keep helpers local. Never import test-kit in the `vi.mock` factory of a +module its entry loads (`host-kit/process`, `command`, `file`): spy it in place, as +`pinOwnProcessStartTime` does. Fixtures a package still exports (R83's legacy count) stay +importable until moved. Use `mkdtempForTest` or `mkdtempForTestSync`. Global setup redirects `TMPDIR` for the run and removes it after every worker exits — skip per-test cleanup. An interrupted run may leave a @@ -118,9 +120,7 @@ another example. Keep examples for a real past bug or a named decision. Reuse `P budgets so property files stay inside the unit slow-test gate. Parser fuzz targets live in `scripts/fuzz/targets.ts`. Validation generators carry the invalid -outcome they planted, so silent acceptance and wrong error codes are failures. Cases run in a -worker process, so a case that never returns or kills its process is reported as `hang` or `crash` -against the exact input. Promote a discovered case with the command the harness prints — never +outcome they planted, so silent acceptance and wrong error codes are failures. Promote a discovered case with the command the harness prints — never hand-copy an unshrunk input. Mutation scope: `scripts/mutation/modules.ts#KERNEL_MODULES` (weekly), `scripts/mutation/run.ts#LANE_SOURCES`