♻️ refactor: monorepo dependency policy + override audit#2531
♻️ refactor: monorepo dependency policy + override audit#2531andrew-bierman wants to merge 13 commits into
Conversation
The policy defines when to use workspace / catalog: / overrides, and the override registry justifies each surviving root override (react, @packrat-ai/nativewindui) with a removal condition. The fenced JSON block is the machine-checked source the check:overrides lint (U3) enforces.
Removes @sinclair/typebox, elysia, and expo-sqlite from root overrides, leaving only react + @packrat-ai/nativewindui (transitive/fork forces). Each was verified redundant against its origin commit and resolution: - typebox: added (98382fa) to give elysia 1.4.x its required typebox >=0.34.0 (Unsafe export). packages/api now directly pins ^0.34.15, so elysia resolves 0.34.49 with Unsafe without the override. check-types + 328 API unit tests pass. (RN jest tooling @jest/schemas now uses its own isolated typebox 0.27.10 — correct; the override was over-forcing it across a major API break.) - elysia: added (6dce074) to prevent duplicate installs; superseded by the later catalog move (fc98b3b). Single elysia node after drop. - expo-sqlite: added in the Expo SDK 55 upgrade pin; direct ~55.0.15 in apps/expo holds it. Single node after drop. Verified via version-node uniqueness (not bun pm why requirer trees) per docs/dependency-policy.md.
…ride The nativewindui override pinned the fork prerelease 2.0.3-2. Upstream has since published 2.0.4/2.0.5/2.0.6, so packages/ui now pins 2.0.6 directly and the override is removed — its removeWhen condition (fork merges upstream) is met. Verified: single 2.0.6 node, bun check-types exit 0, bun test:expo 357 tests pass (21 files). Root overrides now contains only react (the single-copy transitive invariant). Registry in docs/dependency-policy.md updated to react-only. Note: this is a UI component bump — unit tests + types pass but visual QA is recommended before merge.
Adds scripts/lint/no-undocumented-overrides.ts: parses root package.json overrides and the fenced JSON registry in docs/dependency-policy.md, and fails if any override lacks a documented reason+removeWhen, any registry entry is stale, or the registry block is missing/malformed. Wired into the three existing lint surfaces (mirroring no-duplicate-deps): lefthook pre-push chain, scripts/check-all.ts, and checks.yml. Unit tests (bun:test) cover missing/stale/incomplete entries and malformed blocks, plus an integration test asserting the real repo is in sync; run via test:lint in checks.yml. Now the policy can't rot: adding an undocumented override fails CI.
Addresses code-review findings on the new check:overrides lint:
- Type honesty: RegistryEntry fields are string?; parseRegistry now
validates each entry is an object at the parse boundary (a value like
{"react": 42} is a malformed registry) instead of an unchecked cast.
- CRLF tolerance: the fence regex accepts \r?\n so the registry parses
on CRLF-saved files.
- Defensive package.json read via a readJson helper (mirrors
no-duplicate-deps.ts) — a malformed root manifest exits 1 with a clean
message instead of throwing.
- Export REGISTRY_HEADING and reference it in tests, removing the silent
heading-string sync requirement.
- Added tests: fence-before-heading ignored, heading-without-fence,
CRLF input, non-object entry value, non-string field normalization.
16 tests pass; check:overrides + check-types green.
|
Warning Review limit reached
More reviews will be available in 41 minutes and 31 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (6)
WalkthroughThis PR establishes a monorepo dependency policy with three primitives (workspace, catalog, root overrides) and implements a lint that validates root overrides against a registry block embedded in the dependency policy documentation. The lint is wired into CI checks, pre-commit hooks, and package scripts. ChangesMonorepo Dependency Policy & Override Registry Enforcement
Dependency Version Update
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Coverage Report for Expo Unit Tests Coverage (./apps/expo)
File CoverageNo changed files found. |
Coverage Report for API Unit Tests Coverage (./packages/api)
File CoverageNo changed files found. |
There was a problem hiding this comment.
Pull request overview
This PR formalizes the monorepo dependency policy, reduces root overrides to only the documented React invariant, and adds enforcement so future overrides stay justified and in sync with policy documentation.
Changes:
- Adds
docs/dependency-policy.mdwith an override registry parsed by a new custom lint. - Removes redundant root overrides and bumps
@packrat-ai/nativewinduito2.0.6. - Wires
check:overridesinto package scripts, lefthook,check-all, CI, and adds lint tests.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
docs/dependency-policy.md |
Defines dependency primitive policy and machine-checked override registry. |
docs/plans/2026-05-31-001-refactor-monorepo-dependency-policy-plan.md |
Records the implementation plan and verification criteria. |
docs/brainstorms/2026-05-31-monorepo-dependency-policy-requirements.md |
Captures requirements and audit rationale for the policy work. |
scripts/lint/no-undocumented-overrides.ts |
Adds lint logic to compare root overrides with the policy registry. |
scripts/lint/no-undocumented-overrides.test.ts |
Adds unit/integration coverage for registry parsing and violation detection. |
scripts/check-all.ts |
Registers the new override lint in the aggregate check runner. |
package.json |
Adds scripts, removes redundant overrides, and keeps only the React override. |
packages/ui/package.json |
Bumps @packrat-ai/nativewindui to the stable 2.0.6 release. |
bun.lock |
Regenerates dependency resolution after override removal and package bump. |
lefthook.yml |
Runs the new override lint during pre-push checks. |
.github/workflows/checks.yml |
Runs the override lint and its tests in CI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "private": true, | ||
| "dependencies": { | ||
| "@packrat-ai/nativewindui": "2.0.3-2" | ||
| "@packrat-ai/nativewindui": "2.0.6" |
|
|
||
| **Test scenarios:** | ||
| - Happy path: after removal + install, exactly one `elysia` version node exists across the workspace, at the same version captured before removal (the catalog `^1.4.0` resolution, `1.4.28` at audit time). | ||
| - Happy path: exactly one `@sinclair/typebox` node, at a version satisfying both `packages/api`'s `^0.34.15` and elysia's `>= 0.34.0 < 1` (`0.34.49` at audit time). |
Copilot review caught that @packrat-ai/nativewindui 2.0.6 raises its react-native-keyboard-controller peer floor to ^1.21.0, which conflicts with Expo SDK 55's pinned 1.20.7 (the 2.0.3-2 fork required only ^1.16.7, which 1.20.7 satisfied). The expo test suite passed but does not check peer ranges, so the conflict slipped through the original bump. Reverts packages/ui to 2.0.3-2 and restores the nativewindui override + registry entry (documented with the SDK-55 peer conflict as its removeWhen condition). Root overrides: 5 → 2 (react + nativewindui). The policy, lint, and the 3 genuinely-redundant override drops (typebox/elysia/expo-sqlite) are unaffected. Also scopes the plan's typebox uniqueness criterion to the runtime copy and names the expected isolated jest @sinclair/typebox@0.27.10 (Copilot comment 2). Verified: nativewindui single 2.0.3-2 node, RNKC ^1.16.7 peer satisfied by 1.20.7, check:overrides OK (2 documented), check-types + 357 expo tests pass.
|
Thanks @copilot — both findings were valid and are addressed in
|
nativewindui 2.1.0 (PackRat-AI/nativewindui#19) fixes the over-tight peer ranges that blocked the bump — notably react-native-keyboard-controller, relaxed from ^1.21.0 to >=1.16.7, so it no longer conflicts with Expo SDK 55's 1.20.7. packages/ui now pins 2.1.0 directly and the override is gone. This is the clean resolution of the earlier reverted bump: keyboard-controller stays at the SDK's 1.20.7 (no expo.install.exclude, no native-module skew), nativewindui resolves to a single 2.1.0 node, and root overrides drop to just react (5 -> 1). Verified: nativewindui single 2.1.0 node, RNKC >=1.16.7 peer satisfied by 1.20.7, check:overrides OK (1 documented), check-types + 357 expo tests pass, expo-doctor no longer flags keyboard-controller.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/plans/2026-05-31-001-refactor-monorepo-dependency-policy-plan.md`:
- Around line 90-116: The plan's U2 "completed" end-state claims root overrides
are "react + `@packrat-ai/nativewindui`" but the deployed registry
(docs/dependency-policy.md) only lists "react" because the nativewindui override
was removed; update the plan text under U2 (and the summary/status: completed
block) to record that `@packrat-ai/nativewindui` was dropped after adopting 2.1.0
and reference the registry change so the plan's claimed end-state matches
docs/dependency-policy.md and package.json overrides.
In `@scripts/lint/no-undocumented-overrides.ts`:
- Around line 56-62: The extractRegistryBlock function's RegExp match result is
typed as (string[] | null) under noUncheckedIndexedAccess, so change the final
return to safely access the capture group using optional chaining and nullish
coalescing: replace the current conditional return that uses match[1] with
returning match?.[1] ?? null (keep the existing RegExp and the match variable
name). This ensures the function still returns string | null without unsafe
indexing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: b39682af-7681-4921-8c0b-06570847528c
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock,!bun.lock
📒 Files selected for processing (10)
.github/workflows/checks.ymldocs/brainstorms/2026-05-31-monorepo-dependency-policy-requirements.mddocs/dependency-policy.mddocs/plans/2026-05-31-001-refactor-monorepo-dependency-policy-plan.mdlefthook.ymlpackage.jsonpackages/ui/package.jsonscripts/check-all.tsscripts/lint/no-undocumented-overrides.test.tsscripts/lint/no-undocumented-overrides.ts
- no-undocumented-overrides.ts: use match?.[1] ?? null for noUncheckedIndexedAccess safety (the regex capture is string | undefined under that flag). - plan doc: add a post-execution outcome note recording the divergence from the planned 5->2 to the final 5->1 (nativewindui override also dropped via 2.1.0); the authoritative end-state is docs/dependency-policy.md.
|
Thanks @coderabbitai — both addressed in
|
|
Tip For best results, initiate chat on the files or code changes.
🐇 ✨ |
…epo-dependency-policy # Conflicts: # bun.lock # packages/ui/package.json
The merge with development surfaced a version mismatch: development had added a direct @packrat-ai/nativewindui dep to apps/expo at 2.0.3-2, while packages/ui now pins 2.1.0 (this PR). Aligns apps/expo to 2.1.0 so check:catalog passes and a single nativewindui version resolves.
Deploying packrat-guides with
|
| Latest commit: |
8e1045f
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://5a134623.packrat-guides-6gq.pages.dev |
| Branch Preview URL: | https://refactor-monorepo-dependency.packrat-guides-6gq.pages.dev |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
packrat-admin | 8e1045f | Commit Preview URL Branch Preview URL |
Jun 01 2026, 06:23 AM |
apps/expo/app/_layout.web.tsx imported Alert/AlertMethods straight from @packrat-ai/nativewindui — the only file in the app bypassing the @packrat/ui wrapper that every other consumer uses (@packrat/ui/nativewindui re-exports it). That stray direct import forced apps/expo to declare @packrat-ai/nativewindui itself, which (a) duplicated the dependency's ownership and (b) surfaced as a check:catalog version mismatch once packages/ui moved to 2.1.0. Routes the import through @packrat/ui/nativewindui and drops apps/expo's direct dep, so packages/ui is the single owner of @packrat-ai/nativewindui. check:catalog no longer flags it; check-types passes.
Summary
The repo carried two "shared-version" primitives —
catalog:and rootoverrides— with no written rule for which to use, and anoverridesblock nobody could fully justify. This establishes a dependency policy, applies it to clear out overrides that no longer earn their place, and adds a lint so the policy can't silently rot.Result: 5 root overrides → 1. Only
react(the single-copy invariant) remains, documented with a removal condition that CI enforces.What changed
docs/dependency-policy.md— when to use workspace /catalog:/overrides, plus a machine-checked fenced-JSON registry that justifies each surviving override with a removal condition.@sinclair/typebox,elysia,expo-sqlite(verified redundant against their origin commits), and@packrat-ai/nativewindui(resolved at the source — see below).check:overrideslint (scripts/lint/no-undocumented-overrides.ts) wired into lefthook,check-all, andchecks.yml. Adding an undocumented override now fails CI.Why each dropped override was safe
typebox— added to give elysia 1.4.x its required typebox>=0.34.0(Unsafeexport).packages/apinow pins^0.34.15directly, so elysia resolves0.34.49withUnsafewithout the override. (RN's bundled jest tooling keeps its own isolated0.27.10in a separate subtree — expected, not a runtime duplicate.)elysia— added to prevent duplicate installs; superseded by the later catalog migration. Single elysia node confirmed after removal.expo-sqlite— an Expo SDK 55 pin; the direct~55.0.15inapps/expoholds it. Single node after removal.@packrat-ai/nativewindui— pinned a fork prerelease (2.0.3-2). The2.0.6release had an over-tightreact-native-keyboard-controllerpeer floor (^1.21.0) that conflicted with Expo SDK 55's1.20.7. Rather than work around it, we fixed it at the source (PackRat-AI/nativewindui#19 →2.1.0, permissive>=peer ranges).packages/uinow pins2.1.0directly; keyboard-controller stays at the SDK's1.20.7, so there's no SDK divergence and noexpo.install.excludehack.Each removal was checked via version-node uniqueness (one resolved copy in the tree), not just
bun pm whyrequirer listings.Verification
bun check-types✓ ·bun test:api:unit(328) ✓ ·bun test:expo(357) ✓ ·bun test:lint(16) ✓bun check:overrides✓ (1 documented override) — including a live negative test (an undocumented/stale override exits 1)expo-doctordoes not flag keyboard-controller (it's at the SDK's1.20.7)Out of scope (deferred)
container_srcbuild strategy (workspace-ify vsbun build --compile) — coupled to the Turborepo migration and the@tobyg74/tiktok-api-dldecision; tracked in the brainstorm doc.Post-Deploy Monitoring & Validation
Dependency-graph + lint-config change. The one behavioral surface is the
@packrat-ai/nativewindui2.0.3-2→2.1.0bump (a peer-range fix, same component code path). After merge:apps/expobuild/preview after merge, for any NativeWindUI regressions.checks+unit-testsgreen;bun check:overridespasses.2.1.0→ revert the adoption commit (restores2.0.3-2+ its override).developmentalready has an unrelatedexpo-doctorpatch-version-drift finding (e.g.expo-router); not introduced here.Summary by CodeRabbit
New Features
Documentation
Chores
@packrat-ai/nativewinduidependency to 2.1.0.