Skip to content

ci(root): hash every module a package type-checks - #858

Merged
mobeenabdullah merged 3 commits into
mainfrom
ci/hash-every-typechecked-module
Aug 16, 2026
Merged

mobeenabdullah merged 3 commits into
mainfrom
ci/hash-every-typechecked-module

Conversation

@mobeenabdullah

@mobeenabdullah mobeenabdullah commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

What was wrong

main was reporting a green @nextlyhq/e2e#check-types while the package held two real type errors. Nothing was wrong with the check. It was never executed.

check-types declared its inputs as an INCLUDE list:

"inputs": ["src/**/*.{ts,tsx,mts,cts}", "scripts/**/*.{ts,tsx,mts,cts}", "*.{ts,tsx,mts,cts}", "tsconfig.json", "tsconfig.tests.json"]

e2e has no src/ directory. Its modules live in tests/, which no glob matches. Asked directly, turbo hashed 5 files for a package holding 35:

$ turbo run check-types --filter=@nextlyhq/e2e --dry=json
inputs: flaky-reporter.ts, global-setup.ts, package.json, playwright.config.ts, tsconfig.json
tests/ files hashed: 0

So a type error introduced under tests/ left the hash unmoved and turbo replayed the previous entry. Since turbo does not cache failures, the replayed result was a green computed before the break existed. This is not a stale answer; it is an answer to a different question.

A second, larger instance of the same defect

check-types declares dependsOn: [], so no package has a graph edge to @nextlyhq/tsconfig — yet 22 packages extend its base.json, which decides strict, target and lib. Nothing hashed it. Measured before the fix:

appending a newline to packages/tsconfig/base.json
  hash before: e2f45f80054274ba
  hash after : e2f45f80054274ba   (UNMOVED)

Changing a compiler setting would have replayed stale greens across the entire monorepo at once.

The fix

Subtract from the default instead of enumerating what to include. An include list is unbounded — every directory, extension and config a package might adopt must be predicted — and each gap is silent and reports green. An exclude list is bounded, and its gaps cost only an unnecessary re-run. This is also what Turborepo's own docs prescribe: inputs opts you out of all defaults, and $TURBO_DEFAULT$ exists to re-enter them.

"globalDependencies": ["packages/tsconfig/*.json"],
"check-types": { "inputs": ["$TURBO_DEFAULT$", "!**/*.md"] }

The list being replaced had already been patched once along the EXTENSION axis and still failed along the DIRECTORY axis. Adding tests/** would have fixed this case and left the next axis to be found the same way.

Evidence

Same planted type error in e2e/tests/canvas/poc-driver.ts, both configs, warm cache:

config result
before cache hit, replaying logs e2f45f80054274baTasks: 1 successful
after cache miss, executing 9a6450b5f310f129failed, error TS2322

Hash movement, measured and reverted to baseline:

edit before after
packages/tsconfig/base.json unmoved moves
e2e/tests/** unmoved moves
e2e inputs / tests/ hashed 5 / 0 38 / 30

My first attempt at the negative control was worthless and I am recording that: the cache was cold, so the run executed and failed, which proves nothing about replay. A cold cache cannot demonstrate a replayed green. Redone with the cache warmed under the old config first, which is the table above.

The guard

scripts/turbo-inputs.test.mjs asserts the property from turbo's own resolved inputs rather than by reviewing globs — reading the patterns and judging them complete is the same act that produced the gap. Stub-verified: against the old config it fails naming all three defects (e2e 30 unhashed, plugin-page-builder 2, missing global tsconfig).

It asserts the population by MEMBERSHIP before any verdict, because "no package has an unhashed module" is satisfied perfectly by a run that read nothing. Packages that legitimately ship no TypeScript (tsconfig, eslint-config, prettier-config, admin-css) are handled there rather than by a per-package floor that would fail on all four.

Scope and honesty

  • Full check-types --force on a built tree: 22 of 22 pass. The failures visible on an unbuilt tree are the missing-dist state AGENTS.md describes, not this change.
  • Cost: more cache misses. A package's non-Markdown file now moves its typecheck hash. That is the intended trade for a gate: a false negative admits broken code to main, a false positive costs a re-run.
  • plugin-page-builder/e2e/*.spec.ts are in no tsc program at all — a separate gap this does not fix. Now hashed, still unchecked. Worth its own task.
  • Not fixed here, and it generalises this defect: CI restores the turbo cache with a prefix fallback (restore-keys: turbo-v2-${{ runner.os }}-${{ github.job }}-) while the exact key carries the commit SHA, so the exact key never hits and every run restores from some earlier commit. That makes any future input-set gap silently cross-branch rather than confined to one lane. Reported by the verdict-gate lane.

Prior art

  • ci(root): stop a cancelled run from publishing a half-built turbo cache #667 split cache restore from save and gated the save on job success. That addressed incomplete entries from cancelled runs; this entry is complete and valid, and its key simply does not depend on the file that changed.
  • AGENTS.md already documents the mechanism under "measure with --force". So this is not a discovery — it is an unenforced documented rule, which AGENTS.md itself calls out: "A documented rule with nothing enforcing it is not a control, and filing a task is not installing one." This is the first time it cost something.

No changeset: CI configuration and a test, nothing published changes.


A naturally occurring instance, found independently

The evidence above uses a planted error. The page-builder lane hit the same
mechanism by accident while merging main into #854, which is worth recording
because nobody constructed it:

The forced key moved from ee8f6c8860611a0a to e2f45f80054274ba — and the
only reason is that the merge brought in a top-level e2e/flaky-reporter.ts,
which *.{ts,tsx,mts,cts} matches. Nothing under tests/ has ever moved that
key.

That is the defect stated from the other direction: over the whole life of that
cache entry, the only thing that ever invalidated it was a file in the one
directory the globs happened to cover. Every change under tests/ — 30 modules,
including the two that introduced the TS2339 this PR's sibling fixed — left it
untouched.

check-types enumerated what to include, so a package keeping modules
outside src/ had them hashed by nothing: turbo hashed 5 of e2e's 35, and a
type error under tests/ replayed a green earned before it existed.

Starts from $TURBO_DEFAULT$ and subtracts instead, and adds the shared
tsconfig as a global dependency, which 22 packages extend and no hash
covered.

A test asserts the property from turbo's own resolved inputs.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@mobeenabdullah, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 50f1d208-54a0-4d40-9b50-4185b063aa88

📥 Commits

Reviewing files that changed from the base of the PR and between f7545fe and 0bb960e.

📒 Files selected for processing (2)
  • scripts/turbo-inputs.test.mjs
  • turbo.jsonc

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Aug 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

@nextlyhq/adapter-drizzle

npm i https://pkg.pr.new/@nextlyhq/adapter-drizzle@0bb960e

@nextlyhq/adapter-mysql

npm i https://pkg.pr.new/@nextlyhq/adapter-mysql@0bb960e

@nextlyhq/adapter-postgres

npm i https://pkg.pr.new/@nextlyhq/adapter-postgres@0bb960e

@nextlyhq/adapter-sqlite

npm i https://pkg.pr.new/@nextlyhq/adapter-sqlite@0bb960e

@nextlyhq/admin

npm i https://pkg.pr.new/@nextlyhq/admin@0bb960e

@nextlyhq/admin-css

npm i https://pkg.pr.new/@nextlyhq/admin-css@0bb960e

@nextlyhq/blocks-engine

npm i https://pkg.pr.new/@nextlyhq/blocks-engine@0bb960e

@nextlyhq/blocks-react

npm i https://pkg.pr.new/@nextlyhq/blocks-react@0bb960e

@nextlyhq/builder

npm i https://pkg.pr.new/@nextlyhq/builder@0bb960e

create-nextly-app

npm i https://pkg.pr.new/create-nextly-app@0bb960e

nextly

npm i https://pkg.pr.new/nextly@0bb960e

@nextlyhq/plugin-form-builder

npm i https://pkg.pr.new/@nextlyhq/plugin-form-builder@0bb960e

@nextlyhq/plugin-page-builder

npm i https://pkg.pr.new/@nextlyhq/plugin-page-builder@0bb960e

@nextlyhq/plugin-sdk

npm i https://pkg.pr.new/@nextlyhq/plugin-sdk@0bb960e

@nextlyhq/plugin-seo

npm i https://pkg.pr.new/@nextlyhq/plugin-seo@0bb960e

@nextlyhq/storage-s3

npm i https://pkg.pr.new/@nextlyhq/storage-s3@0bb960e

@nextlyhq/storage-uploadthing

npm i https://pkg.pr.new/@nextlyhq/storage-uploadthing@0bb960e

@nextlyhq/storage-vercel-blob

npm i https://pkg.pr.new/@nextlyhq/storage-vercel-blob@0bb960e

@nextlyhq/ui

npm i https://pkg.pr.new/@nextlyhq/ui@0bb960e

commit: 0bb960e

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19f5621316

ℹ️ 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".

Comment thread scripts/turbo-inputs.test.mjs
Comment thread scripts/turbo-inputs.test.mjs
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 19f5621316

ℹ️ 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".

A tsconfig paths entry pointing at a sibling's source puts that sibling's
files in this package's program, and inputs are package-scoped however they
are written, so editing packages/nextly/src left admin's hash unmoved.

The dry run also lists a task whose script is absent, marking it
<NONEXISTENT>, so membership alone did not prove anything runs.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 51491d9f24

ℹ️ 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".

Slicing at the first brace anywhere starts the parse inside a warning that
happens to contain one, which is what CI hit: the same
"Expected property name or '}' at position 1" reproduces from a preceding
line carrying a brace.

A failed parse now names what it received.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0bb960eb89

ℹ️ 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".

Comment thread turbo.jsonc
Comment thread turbo.jsonc
@mobeenabdullah
mobeenabdullah merged commit 7e20bf3 into main Aug 16, 2026
24 checks passed
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 7e20bf388b

ℹ️ 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".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant