Skip to content

refactor(layering): R84 requires each new unit test to be named for a module beside it - #3669

Merged
thymikee merged 3 commits into
refactor/test-kit-single-entryfrom
refactor/test-colocation-ratchet
Oct 15, 2026
Merged

thymikee merged 3 commits into
refactor/test-kit-single-entryfrom
refactor/test-colocation-ratchet

Conversation

@thymikee

@thymikee thymikee commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Stacked on #3667 (test-kit single entry) on #3659 (R11 devDependencies) on #3645 (R83).

What

R84 test-colocation: every *.test.ts under root src/ and packages/<pkg>/src/ sits in the directory of a module (or in that directory's __tests__/) and is named <module>.test.ts or <module>-<aspect>.test.ts. It measures its offenders against the merge-base and keeps no baseline file, the same way R83 does: 202 unmatched tests at head against 202 at the merge-base. Growth fails; moving or renaming a test into place needs no edit (base entries are carried to head coordinates through renamedSince, so a rename is the same entry). Burn-down belongs to the package and root workers; this PR only lands the rule.

Conventions (stated in the rule's doc comment, so it needs no exemptions)

  • Cross-module package tests (conformance drivers, package-surface tests) are named for the package entry: index-<aspect>.test.ts, beside index.ts. index is an ordinary module to the rule.
  • Repo-level guards (tests that assert on Swift sources, manifests, docs or scripts) move to test/repo-guards/, under the exempt test/ tree, and run in unit-core.
  • Exempt: test/, scripts/, package-local test/ trees. The rule reads only src/ and packages/*/src/, and not test-kit, whose sources are test support.
  • A module is any production source file (isProductionSourceFile): fixtures and __tests__/ helpers never count as the module a test is named for.

Evidence

  • test-colocation.test.ts: matched by module and by -aspect; unmatched for a different name, a glued suffix or a dotted suffix; __tests__ judged against the parent directory (and not against modules inside __tests__); index-<aspect> matched only with an index.ts beside it; fixtures never the module; test/, scripts/ and package test trees unmeasured; growth fails, a cleanup or unchanged set passes; the message names both conventions.
  • Planted src/__tests__/planted-unmatched.test.ts in the real tree: check:layering named it under R84. Removed.
  • The measurement runs through mergeBaseRatchets (LayeringRatchets.unmatchedTests); measureRatchets now takes the tracked tree ({ manifests, files }) that R83 and R84 share.
  • Gates: pnpm check:quick, check:layering (384 node tests), check:fallow, check:gate-manifest, check:affected --run, repo-wide pnpm format.

🤖 Generated with Claude Code

@thymikee
thymikee added this pull request to stack #3660 October 15, 2026 13:38
@thymikee thymikee changed the title refactor(layering): add R84 so a new unit test must be named for a module beside it refactor(layering): R84 requires each new unit test to be named for a module beside it Oct 15, 2026
@thymikee
thymikee marked this pull request as ready for review October 15, 2026 13:38

@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 6 files

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

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

Comment thread scripts/layering/test-colocation.ts Outdated
Comment thread scripts/layering/ratchet-reference.ts Outdated
@thymikee
thymikee force-pushed the refactor/test-colocation-ratchet branch 3 times, most recently from 4c2e459 to bce7f7d Compare October 15, 2026 14:48
@thymikee

Copy link
Copy Markdown
Member Author

The code at bce7f7d has one problem to fix before merge. R84 sends authors to a test/repo-guards/ directory that no test project collects. The checks are still queued, with no failures so far. The diff only touches scripts/layering, so the Repo Guards and Lint & Format jobs through check:layering are the ones that apply. No conflicts.

The violation message in test-colocation.ts, the rule comment above it and the PR body all say repo-level guards belong in test/repo-guards/ and "run in unit-core". That directory does not exist at this commit, and the unit-core include in vitest.config.ts lists test/ files one by one with no test/repo-guards glob. No gate fails when a test file belongs to no vitest project. An author who follows the remedy moves a guard out of src/, and it then runs in no lane while check:layering, the unit suite and CI stay green. The burn-down will take this route for some of the 347 offenders. The rule should be that every location R84 names as a remedy is collected by a vitest project. Please add test/repo-guards/**/*.test.ts to the unit-core include and map it in check:affected, or drop that remedy from the message and comment until the PR that creates the directory lands. To validate, put a throwaway test in test/repo-guards/ and show that the unit suite runs it.

Not blocking, and fine to take or leave: no fixture-repo test covers a test that was unmatched at the base and then renamed (the carry-over through the base-to-head mapping and the re-sort in ratchet-reference.ts), and a case like the one at session-authority-overlay.test.ts:312 would pin it. IN_SCOPE and TEST_FILE in test-colocation.ts also re-spell predicates from tracked-sources.ts, so exporting those and reusing them would keep one source of truth.

The two open inline threads on the declaration-module regex and the unmatched-test sort are fixed at this commit. Please resolve the regex thread and the sort thread.

I read the code but did not run check:layering. So I could not confirm the 347 count, which the rule comment gives as 346, or the planted-test result. The rename carry-over is checked by reading only.

Before merge, a vitest project must collect test/repo-guards/, or the message must drop that remedy.

@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 -4 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 19.9 ms 18.1 ms -1.8 ms
CLI --help 50.6 ms 51.3 ms +0.7 ms

@thymikee
thymikee force-pushed the refactor/test-colocation-ratchet branch from bce7f7d to a1a7401 Compare October 15, 2026 16:09
@thymikee
thymikee force-pushed the refactor/test-colocation-ratchet branch from a1a7401 to 56bbc2e Compare October 15, 2026 16:20
@thymikee

Copy link
Copy Markdown
Member Author

The base was old: #3663 added the glob to unit-core before this stack was rebased onto it. On the current head (vitest.config.ts:138, inside the unit-core include list):

            'test/repo-guards/*.test.ts',

and pnpm vitest list --project unit-core lists them under [unit-core], e.g.

[unit-core] test/repo-guards/apple-runner-log-redaction.test.ts > commit-wait cadence logging goes through the typed value-free boundary
[unit-core] test/repo-guards/apple-runner-package-source.test.ts > package apple runner source strips unit-test blocks without mutating checkout source

To keep the remedy from rotting, test-colocation.test.ts now asserts that vitest.config.ts still collects test/repo-guards/*.test.ts, so removing the glob fails check:layering. The non-blocking points are taken too: R84 reuses SOURCE_TREE_ROOT from tracked-sources instead of re-spelling it, the carried merge-base entries go through a tested inHeadCoordinates helper (rename into a new lexical position, re-sorted), and the rule comment no longer hard-codes a count (the live number, 253 at the new merge-base, is in the check:layering output). Both inline threads you listed are resolved.

@thymikee

Copy link
Copy Markdown
Member Author

The PR is ready. Both earlier threads from the review of bce7f7d are fixed at 56bbc2e: foo.d.ts is no longer indexed as foo in measureUnmatchedTests, and the sort in inHeadCoordinates is now pinned by a test.

Not blocking: the new test at https://github.com/callstack/agent-device/blob/56bbc2e/scripts/layering/test-colocation.test.ts#L151 matches the literal glob text in vitest.config.ts instead of asking vitest what it collects, and TEST_KIT_TREE and TEST_FILE in https://github.com/callstack/agent-device/blob/56bbc2e/scripts/layering/test-colocation.ts#L32 repeat parts of TEST_SUPPORT_PATH from tracked-sources.ts. You can take or leave both.

Both cubic-dev-ai threads are fixed at this head, so you can resolve them: the .d.ts indexing one (#3669 (comment)) and the inHeadCoordinates sort one (#3669 (comment)).

I did not run check:layering or vitest list. I checked that test/repo-guards is collected from the config text at 56bbc2e and from your quoted vitest list output. I also did not exercise a rename that git does not detect as a rename. renamedSince does not map it, so it shows as a new offender, which fits the rename-into-place design.

No conflicts. CI is still pending: every check is queued or was cancelled by a newer push, and none has failed. This diff only touches scripts/layering, so Repo Guards (check:layering) and unit-core are the jobs that matter. Both need to go green on 56bbc2e before merge.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 15, 2026
thymikee and others added 3 commits October 15, 2026 19:02
…dule beside it

Every *.test.ts under root src/ and packages/*/src/ (test-kit excluded) sits in the directory of a
module, or in its __tests__/, named <module>.test.ts or <module>-<aspect>.test.ts. The unmatched set
is a merge-base ratchet like R83: growth fails, a move into place needs no edit, no baseline file.
index is an ordinary module (cross-module package tests are index-<aspect>.test.ts); repo-level
guards live in test/repo-guards/, under the exempt test/ tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…carried colocation entries

foo.d.ts is the module foo, not foo.d, so a colocated foo.test.ts matches it; base entries mapped to
head coordinates are re-sorted so a rename that changes lexical order keeps the measured ordering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e repo-guards remedy

R84 reads SOURCE_TREE_ROOT from tracked-sources instead of re-spelling it, the carried merge-base
entries go through a tested helper that re-sorts them, and a test pins that vitest.config.ts collects
test/repo-guards/ so the remedy the rule names runs in unit-core.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thymikee
thymikee force-pushed the refactor/test-colocation-ratchet branch from 56bbc2e to 6bdaabf Compare October 15, 2026 17:09
@thymikee
thymikee merged commit f35cb97 into main Oct 15, 2026
20 of 31 checks passed
@thymikee
thymikee deleted the refactor/test-colocation-ratchet 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