fix(blocks-react): let the build system own declaration freshness - #669
Conversation
|
Warning Review limit reached
Next review available in: 31 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
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 |
|
@codex please review this PR |
@nextlyhq/adapter-drizzle
@nextlyhq/adapter-mysql
@nextlyhq/adapter-postgres
@nextlyhq/adapter-sqlite
@nextlyhq/admin
@nextlyhq/admin-css
@nextlyhq/blocks-engine
@nextlyhq/blocks-react
@nextlyhq/builder
create-nextly-app
nextly
@nextlyhq/plugin-form-builder
@nextlyhq/plugin-page-builder
@nextlyhq/plugin-sdk
@nextlyhq/plugin-seo
@nextlyhq/storage-s3
@nextlyhq/storage-uploadthing
@nextlyhq/storage-vercel-blob
@nextlyhq/ui
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c153c4f0dd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b4ffe4f201
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex please review this PR |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Independent corroboration from other lanes — four branches, four packages, one shape. The body argues this from one failing job. Two other sessions have since reported the same signature on branches with no connection to each other or to
The docs-only branch is the strongest single data point. It changes no source, no config and no lockfile, so nothing on it can break module resolution inside a plugin package — yet it produces the same failure. That rules out the change under test as the cause on every one of these. Every failing package is a dependent resolving into a directory the nested build rebuilds, and which one loses varies run to run. That is the signature of a race, and it matches the mechanism this PR removes: Also worth recording: no counter-example has been found. Both sessions were asked specifically for a run showing this signature where no |
PRs across every lane have been going red on
Lint / Typecheck / Test / Buildwithin a package the change never touched, and a different package each run.
Cause
packages/blocks-react/vitest.global-setup.tsran, during vitest collection:That carries the
^buildedge, so it is not one package.--dry=json:nextlyis in there because it is a devDependency ofblocks-react, and turbo traverses devDependencies. Every one of those bundles withtsup clean: true, so each deletes itsdist/before emitting — while the CI Test step is running seventeen packages' suites concurrently against those same directories.The failing job's timeline is exactly that:
It accounts for every property of the failure: a different package each run (whichever was mid-import), never reproducible locally (one suite at a time), and unaffected by any turbo flag on the outer command — the invocation is nested inside vitest, so
--onlyon the Test step does not reach it (measured: that run had 0 replays and failed anyway).The change
The nested build is removed. The file still refuses to start when the declarations are absent — it just says so instead of building them.
Freshness already belongs to the build system:
packages/blocks-react/turbo.jsonmakestestdepend on this package's ownbuildand namesdist/**among itsinputs, so an edit to anything the declarations are emitted from rebuilds and re-runs. Every documented path —pnpm test,turbo run test, CI — arrives through that edge with the artifact current. Building again in global setup was belt-and-braces against a guarantee that already held.The entries are read from
package.jsonrather than listed, so the check is exactly what the suites resolve and cannot drift as entries are added.The accepted cost: a bare
vitest runon a never-built tree now fails instead of self-healing.One legible failure, once, in place of a nondeterministic one in somebody else's package.
The trade-off this accepts, stated rather than left to be found
existsSynccatches an absentdist, never a stale one. A directvitestrun against a tree whosedistpredates the source will assert against the stale artifact and can pass wrongly.That is acceptable because it is unreachable through any documented path:
pnpm test,turbo run testand CI all arrive throughtest → dependsOn: ["build"]withdist/**ininputs, so the artifact is current by construction. It is named here so the next reader does not rediscover it as a defect.Verification
Removing the build must not blind the suites to a stale
dist. Built the package, droppedexport { pruneHiddenNodes } from "./visibility";fromsrc/index.ts, ran without rebuilding:Which suite caught it is the informative part.
entry-surface.test.tsimports the module, so it sees source through Vite's transform and detects the drift.type-surface.test.tsreads the built.d.tsand passed — correctly, since the stale artifact still contained the export. The two fail on different things by design, and the one that can fail here does.A second mutation — dropping
export type { PageRendererProps } from "./page-renderer";— passed both stale (4/4) and after a rebuild (4/4), which is correct and worth explaining so nobody reads it as the suite going blind.type-surface.test.tsasks one question: does this package re-export every engine type its declarations are written in terms of?engineTypesInderives that set by matchingfrom "@nextlyhq/blocks-engine"imports, named and namespace forms.PageRendererPropsis declared locally inpage-renderer.tsx, so it is outside that set by construction and removing it changes nothing the suite asserts, fresh or stale.The two suites split cleanly:
entry-surfacecovers what this package declares,type-surfacecovers what it borrows from the engine and owes onward. The value mutation above exercises the first; nothing exercises the second through staleness, which is the trade-off named in the previous section rather than a gap.Also verified: the missing-
distpath produces the message above;turbo run test --filter=@nextlyhq/blocks-reactgreen (15 files, 9 tasks);check-typesandlintclean.Provenance
This finishes the reasoning of the PR that introduced the setup rather than reversing it. That PR concluded in review that build freshness belongs to the build system and removed a per-suite rebuild for exactly that reason — then left the same responsibility in global setup one layer up. Its author reviewed this diagnosis, chose removal over narrowing the filter (
--onlywould cut ten packages to one, but that one isblocks-react, whosedistthe downstream suites import, so the race would get rarer and harder to diagnose rather than closed), and asked for the stale-distcontrol above.No changeset — test-harness only, nothing published changes.