Repository navigation
Make lib folder dependencies point in a single direction - #67
Conversation
Move on-disk paths and the Packref home into a new layout folder so store and workspace no longer import each other. Split core/packages into identity, repository host, and spec modules to break the errors/packages cycle. Add a layer test that enforces the folder order and rejects import cycles. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
ℹ️ No critical issues. There are two gaps in the new layer test and one doc nit. See the inline comments.
Reviewed changes
I reviewed the full diff of the single commit. I ran tsc --noEmit, pnpm run check, pnpm run analyze, and pnpm run test (296 passed, 2 skipped). All of them pass. I also ran mutation probes against layers.test.ts.
- Split of
core/packages.ts— Identity types and orders move tocore/identity.ts, and repository hosts move tocore/repository.ts. This removes thecore/errors.ts↔core/packages.tsfile cycle. - New
layoutfolder —PackrefHomeand the project and user-level path helpers move fromworkspacetolayout, andgetStorePackagePathbecomesgetPackageIdentityPath. This removes thestore↔workspacefolder cycle. - Shared provider check —
checkIsRepositoryProviderreplaces three inline provider checks inreferences/install.ts,store/index.ts, andsources/repository/normalize.ts. Behavior does not change. - Reference path lookups —
references/remove.tsandreferences/sync.tsnow callgetProjectReferencePath. It gives the same path as the oldgetDirectoryPath+getStorePackagePathcomposition. - Layer guard test —
src/lib/__tests__/layers.test.tsenforces a folder allow-list and rejects file-level import cycles. The probes show that it catches an upward#libimport and a file cycle incore. - Architecture docs —
docs/architecture.mdadds thelayoutrow and a### Layerssection.
claude-opus-5-5 | 𝕏
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found. The new commit fixes all three points from the last review.
Reviewed changes
I reviewed commit 0db6084, which changes layers.test.ts and one row in docs/architecture.md. pnpm run check passes, and all 5 tests in layers.test.ts pass. I ran mutation probes against the new tests.
- Shared cycle search — Moved the DFS into
findCycles(graph). The file-cycle test and a new folder-cycle test overALLOWED_DEPENDENCIESboth use it. When I add"sources"to thestoreallow-list, the folder test fails withsources -> store -> sources. - Relative import guard — Added a test that rejects
from "./..."andfrom "../..."specifiers in non-testsrc/libfiles. Both of my probes fail this test: a../layout/home.tsimport and a same-folderimport typefrom./identity.ts. - Narrower
layoutdoc row — Changed thedocs/architecture.mdrow so that it lists only project paths, user-level paths, and the Packref home. The global store paths stay instore/paths.ts.
claude-opus-5-5 | 𝕏
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found. The new commit removes only a test and one doc sentence. The source code does not change.
Reviewed changes
I reviewed commit 3194e72. The range diff against 0db6084 shows changes in only these two files. I also did a lint probe to find which layer rules a check still enforces.
- Removed the layer guard test — Deleted
src/lib/__tests__/layers.test.ts, which contained theALLOWED_DEPENDENCIESallow-list, the folder-cycle and file-cycle checks, and the relative-import check. - Removed the doc pointer — Deleted the sentence in
docs/architecture.mdthat told contributors to updateALLOWED_DEPENDENCIES. The### Layerslist stays.
ℹ️ Only file cycles are still enforced — the folder layers are now documentation only
Lint still catches file-level cycles. Adamantite's core preset sets import/no-cycle to error, and oxlint resolves #lib/... specifiers. In my probe, two files in src/lib/core that import each other through #lib caused an import(no-cycle) error on both files. But no check now catches an upward folder import, or a folder cycle that has no file cycle. Before this PR, store ↔ workspace was that type of cycle. This is acceptable if you want the ### Layers list to be a convention only.
Technical details
# Folder layering is no longer enforced after `3194e72`
## Affected sites
- docs/architecture.md:32-41 — the `### Layers` section states the rule, but no test or lint rule enforces it.
- node_modules/adamantite/dist/presets/lint/core.js — `"import/no-cycle": "error"` (still active, and it catches file cycles over `#lib` specifiers); `"import/no-relative-parent-imports": "off"`.
## Probe results at `3194e72`
- `src/lib/core/a.ts` <-> `src/lib/core/b.ts` through `#lib/core/...` → `import(no-cycle)` error on both. Caught.
- `src/lib/core/c.ts` imports `#lib/layout/home.ts` (upward import, no file cycle) → no layer error. Not caught.
## Required outcome
- None, if the layers are a convention only. If you want enforcement, then an upward `#lib` import or a folder cycle must fail `pnpm run check` or `pnpm run test`.
## Suggested approach (optional)
- Use `no-restricted-imports` `patterns` overrides for each folder in `oxlint.config.ts` (for example, files in `src/lib/core/**` cannot import `#lib/layout/**` or a higher layer). This keeps enforcement in the lint step and does not need a test file.
## Open questions for the human (optional)
- Is it your intention that the `### Layers` list is a convention only?claude-opus-5-5 | 𝕏
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found. The new commits add lint enforcement for the
src/liblayers. This closes the enforcement gap from the last review.
Reviewed changes
I reviewed commits a6b7cca and 38f8f46. They change only oxlint.config.ts and docs/architecture.md. pnpm run check and tsc --noEmit pass. I ran lint probes with scratch files in src/lib, and then deleted the files.
- Type-only cycles — Set
import/no-cycletoignoreTypes: false, so lint also reports cycles throughimport type. No cycles of this type are in the current code. LIB_LAYERSoverrides — Added oneno-restricted-importsoverride for eachsrc/libfolder. Each override rejects#libfolders that are not in the allow-list, and all./and../specifiers. The probes caught these imports: an upward import, a type-only import,export * from, dynamicimport(), a side-effect import, a same-layer import (store→workspace), a deep-folder import (sources/repository→references), and relative./and../imports. Allowed imports and same-folder#libimports do not cause errors. The custom messages show ashelp:lines.- Test exemption — Turned off
no-restricted-importsforsrc/lib/**/__tests__/**. The probe shows that this also applies to nested folders such assources/repository/__tests__. No Adamantite preset sets this rule, so the overrides do not replace other settings. - Architecture docs — Added a sentence that names
LIB_LAYERSandimport/no-cycleas the enforcement. The allow-list agrees with the### Layerslist and has no cycles.
claude-opus-5-5 | 𝕏
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Run failed. View the logs →
|
1 similar comment
|
Run failed. View the logs →
|
There was a problem hiding this comment.
ℹ️ No new issues. The layer rules have not changed, and there is one wording nit inline.
Reviewed changes
I reviewed commit 1010499. It changes only oxlint.config.ts and one paragraph in docs/architecture.md. pnpm run check (0 warnings, 0 errors) and tsc --noEmit pass. I ran lint probes with scratch files in src/lib, and then deleted the files.
- Explicit layer overrides — Replaced the
LIB_LAYERSgenerator with one hand-writtenno-restricted-importsoverride for each folder exceptreferences. Eachgrouplist is the same as the complement of the old allow-list, so the layers do not change. The probes still catch an upward import (core→#lib/layout) and a deep-folder import (sources/repository→#lib/workspace). - Relative imports — Replaced the
./**and../**pattern group withimport/no-relative-parent-importsonsrc/lib/**/*.ts. The probes caught these../imports: value imports,import type,export * from, dynamicimport(), side-effect imports, and./../. Same-folder./imports are now allowed. They cannot get to a different folder. - Test exemption — Turned off
import/no-relative-parent-importswithno-restricted-importsinsrc/lib/**/__tests__/**. A nested test file with../../../and upward#libimports causes no errors. - Architecture docs — Changed the enforcement paragraph to name the overrides and
import/no-relative-parent-imports.
claude-opus-5-5 | 𝕏
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

The folders in
src/libimported each other in both directions.storeandworkspacedepended on each other, andcore/errorsandcore/packagesformed a cycle. This made it hard to see which module owns what, and any new code could add more cycles without notice.Now each folder imports only lower layers:
core,sharedlayout(new: on-disk paths and the Packref home)registries,manifests,store,workspacesourcesreferencesTo break the cycles, the path helpers and
PackrefHomemoved fromworkspacetolayout.core/packages.tsis split intoidentity.ts,repository.ts(repository hosts), and spec parsing. This also removes duplicate provider checks insources,store, andreferences.oxlint
import/no-cyclenow also reports cycles through type-only imports (ignoreTypes: false). Onmainit reports the oldcore/errors↔core/packagescycle. Per-folderno-restricted-importsoverrides inoxlint.config.tsenforce the layers, andimport/no-relative-parent-importsstops relative imports from bypassing them.docs/architecture.mddocuments the layers. Behavior does not change, so there is no changeset.Changes made by Claude Opus 5.5 (1M context) in Claude Code.
🤖 Generated with Claude Code