Skip to content

refactor(test-kit): one named-export entry, and pin its shape in R83 - #3667

Merged
thymikee merged 5 commits into
refactor/r11-test-dev-dependenciesfrom
refactor/test-kit-single-entry
Oct 15, 2026
Merged

thymikee merged 5 commits into
refactor/r11-test-dev-dependenciesfrom
refactor/test-kit-single-entry

Conversation

@thymikee

@thymikee thymikee commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Stacked on #3659 (R11 devDependencies) on #3645 (R83).

What

@agent-device/test-kit exports exactly "." → src/index.ts, with every helper a named export (54 names, no export *). The 18 subpaths are gone; every importer (about 470 files across the daemon, root src/, test/ and scripts/; re-run over the daemon tests main gained since) now import @agent-device/test-kit. The rewrite is a mechanical codemod (merged same-file imports, import type kept); the hand-written parts are index.ts, host-process-mock.ts, eight test edits and the R83 additions below.

Why the eight pinOwnProcessStartTime tests changed

They mocked @agent-device/host-kit/process with a factory that did (await import('@agent-device/test-kit')).pinOwnProcessStartTime(importOriginal). With one eager entry that import deadlocks: the entry loads host-kit/command, host-kit/file and capture-kit, which load host-kit/process, which is still being mocked. The helper now takes the module namespace and spies it in place (pinOwnProcessStartTime(hostProcess), registered with beforeEach so vi.restoreAllMocks cannot unpin it); no module is mocked, so no test-kit import happens during a mock factory.

Proof the pin still takes effect: with readCurrentOwnerIdentity made to return a different start time, device-claims.test.ts fails 6 of 28 tests; restored, all 28 pass. The eight tests pass together (103 tests). Rule for future tests: never import test-kit inside a vi.mock factory.

Import-time side effects

None. Each of the 18 modules imports cleanly in plain Node with no top-level effects (the fs.writeFileSync/setInterval lines in legacy-daemon-fixture.ts are inside a template string that becomes a child script). The entry loads in plain Node in ~160 ms (54 exports). The six node:test scripts that import test-kit still pass; the entry pulls vitest into them, which loads harmlessly outside a runner.

Wall time, vitest run --project unit-core (1647 files, 14,222 tests, same on both sides)

vitest Duration import share
before (subpaths, head of #3659) 155.95 s 23 %
after (single entry) 154.46 s 28 %

Each test file now imports all of test-kit instead of one module, which shows as the larger import share; the total is unchanged within noise (single run each, shared host).

R83 additions: the shape of test-kit

checkTestKitIsolation (inside R83) pins:

  • exports is exactly .;
  • no dependencies/devDependencies/peerDependencies entry on platform-*, provider-*, @agent-device/daemon or agent-device (root), and no import of them or relative reach out of packages/test-kit/. A fixture that needs those packages' code is a test of that package and belongs in it;
  • no package test-kit depends on may declare test-kit. TypeScript project references are acyclic and test-kit references capture-kit, command-registry, contracts, daemon-contracts, host-kit and kernel, so those six packages' tests keep their helpers local.

Planted in tests: an extra export, each forbidden dependency in all three fields, eight forbidden or escaping imports, and a devDependencies/dependencies cycle through kernel. Only the daemon and the root consume test-kit today; the daemon already declares it in devDependencies (#3659). Every other package's worker adds it to devDependencies and references when its tests start importing it.

Gates

pnpm check:quick, check:layering (373 node tests), check:fallow, check:gate-manifest, check:affected --run, vitest --project unit-core in full, repo-wide pnpm format.

🤖 Generated with Claude Code

@thymikee
thymikee added this pull request to stack #3660 October 15, 2026 13:26
@thymikee thymikee changed the title refactor(test-kit): collapse the 18 subpaths into one named-export entry refactor(test-kit): one named-export entry, and pin its shape in R83 Oct 15, 2026
@thymikee
thymikee marked this pull request as ready for review October 15, 2026 13:26

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 464 files

Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread scripts/layering/package-export-surface.ts Outdated
Comment thread scripts/layering/package-export-surface.ts Outdated
Comment thread scripts/layering/package-export-surface.ts Outdated
Comment thread scripts/layering/package-export-surface.ts Outdated
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.24 MB 5.24 MB 0 B
Package (unpacked) 5.24 MB 5.24 MB 0 B
Package (download) 1.57 MB 1.57 MB +8 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 26.4 ms 26.0 ms -0.4 ms
CLI --help 74.2 ms 75.7 ms +1.6 ms

@thymikee
thymikee force-pushed the refactor/test-kit-single-entry branch from 4c4e3ec to 3f68766 Compare October 15, 2026 14:26

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread scripts/layering/test-kit-isolation.ts Outdated
@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at 9bb17a7. The single test-kit entry and the R83 pin look correct.

Not blocking, and you can take or leave these: docs/agents/testing.md:70 still says to import from the defining module and never through a barrel, so it should say shared helpers are named imports from @agent-device/test-kit and keep the no-barrel rule for package-internal support only; the error message at packages/test-kit/src/property-arbitraries.ts:386 still names the removed property-arbitraries subpath; and the PR body says "no export *", but R83 only checks package.json exports (https://github.com/callstack/agent-device/blob/9bb17a7/scripts/layering/test-kit-isolation.ts#L79), so either drop the claim or add a one-line source check on packages/test-kit/src/index.ts inside checkTestKitIsolation.

CI is still pending: all 18 jobs were queued when I looked and none had failed. This diff rewrites imports in 458 test files and changes R83, so Typecheck & Package, unit, integration and Repo Guards (layering) must go green on this head before merge. I did not confirm that the rewritten imports typecheck, did not run the mutation that shows the namespace-spy pin makes the device-claims tests pass, and did not check the no-import-time-side-effects claim or the wall-time figures.

The five cubic-dev-ai P2 threads are fixed at this head and no longer apply, so you can resolve them: #3667 (comment) (transitive cycles), #3667 (comment) (optionalDependencies), #3667 (comment) (import scan), #3667 (comment) (forbidden package set), #3667 (comment) (exports leaf check).

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 15, 2026
@thymikee
thymikee force-pushed the refactor/test-kit-single-entry branch 2 times, most recently from 8009ebe to 68bce17 Compare October 15, 2026 16:20
@thymikee

Copy link
Copy Markdown
Member Author

Taken: the property-arbitraries error message now names packages/test-kit/src/property-arbitraries.ts; R83 now also refuses export * in packages/test-kit/src/index.ts (one source check in checkTestKitIsolation, tested), so the PR body's claim is enforced rather than asserted. The docs/agents/testing.md wording lives in the docs layer, #3673: it already drops "never through a barrel" and says test-kit's entry is the shared-helper import, so the note is covered once that layer lands in stack order. All five threads you listed are resolved.

@thymikee

Copy link
Copy Markdown
Member Author

The PR is ready at 68bce17. The earlier concerns are fixed: the isolation check now follows transitive dependencies, counts optional and peer dependencies, includes vi.mock literals, derives the forbidden set from the provider package layout (so testmu is covered), and requires every string leaf of the "." export to point at ./src/index.ts.

Not blocking, and fine to take or leave: the new refusal at https://github.com/callstack/agent-device/blob/68bce17/scripts/layering/test-kit-isolation.ts#L148 is a regex, and it misses export type * from './x.ts', which oxc reports as an unnamed export; it also refuses export * as ns, which readNamedExports in https://github.com/callstack/agent-device/blob/68bce17/scripts/layering/facade-exports.ts#L52 accepts, so the two entry rules disagree. Reusing readNamedExports (or oxc staticExports and refusing kind None) would give one parser for the "entry names every export" rule.

The five earlier inline threads are fixed at this commit, so you can resolve them: #3667 (comment) (transitive walk), #3667 (comment) (optional and peer deps), #3667 (comment) (vi.mock literals), #3667 (comment) (provider forbidden set), #3667 (comment) (export leaf check).

I did not run the layering gate or the test-kit-isolation tests locally, so this rests on reading the diff. I also did not confirm that the source map keys use the repo-relative packages/test-kit/src/index.ts form; I inferred it from other checks that read the same map. CI is still queued, with no failures so far. The Repo Guards layering lane and the unit and coverage lanes will exercise this change once they run, and they must pass at 68bce17 before merge. The docs wording waits for #3673 to land in stack order. There are no conflicts.

thymikee and others added 5 commits October 15, 2026 19:02
@agent-device/test-kit exports exactly '.', pointing at src/index.ts, with every helper a named
export (no export *). All 458 importers move to the entry. The eight tests that pinned the host
process start time through a vi.mock factory importing test-kit now spy the host-kit process module
in place: a factory that imports the entry deadlocks, because the entry loads host-kit/process while
that module is still being mocked. R83 also pins test-kit's shape: one entry, no dependency on or
import of platform-*, provider-*, the daemon or the root, and no package it builds on may declare it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e and walk the graph

The isolation check moves to its own module and now takes the forbidden packages from the
packages/platform-*, packages/provider-* and packages/daemon directories (so a provider published
as @agent-device/testmu is covered), reads optionalDependencies, walks the workspace dependency graph
transitively for both forbidden packages and a cycle back to test-kit, and scans test-kit sources
with the shared specifierSites walk so vi.mock literals count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… src/index.ts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ved from the entry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ath in an error message

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thymikee
thymikee force-pushed the refactor/test-kit-single-entry branch from 68bce17 to f8358ee Compare October 15, 2026 17:09
@thymikee
thymikee merged commit 6fc50d1 into main Oct 15, 2026
22 of 29 checks passed
@thymikee
thymikee deleted the refactor/test-kit-single-entry branch October 15, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant