Skip to content

Adopt cached Nx CI and automated releases - #12

Merged
tannerlinsley merged 7 commits into
mainfrom
taren/nx-ci-release
Jul 31, 2026
Merged

Adopt cached Nx CI and automated releases#12
tannerlinsley merged 7 commits into
mainfrom
taren/nx-ci-release

Conversation

@tannerlinsley

@tannerlinsley tannerlinsley commented Jul 31, 2026

Copy link
Copy Markdown
Member

What changed

  • Added an Nx target graph with deterministic local caching, independent test environments, shared GitHub Actions cache setup, and affected-PR execution.
  • Split comparison, conformance, and stress checks into parallel matrices behind one stable CI aggregate check.
  • Fixed the root Vitest exclusion regression that made pnpm-linked suites run repeatedly.
  • Added Changesets version PR automation and guarded tag-scoped npm OIDC publication with exact-SHA CI, artifact, tag, registry, provenance, and release-note validation.
  • Parallelized safe bundle and adapter work while preventing pnpm from reinstalling dependencies during generated-output builds.
  • Added contributor and workflow contract documentation/tests.

Why

The previous workflow serialized browser suites behind a monolithic validation job, repeated test files through workspace symlinks, had no reusable local task cache, and required manual release orchestration. This gives local and CI runs the same cached graph while keeping browser measurements and revision-stamped artifacts uncached.

Validation

  • pnpm run validate — 112 test files / 567 tests plus format, docs, types, packages, bundles, and catalog gates
  • warm pnpm test — 0.58s with 7/8 Nx tasks restored
  • fresh release build — 10 tarballs in 21.8s; artifact publisher contract passed
  • comparison line shard — 30 browser scenarios passed
  • conformance shard 1/8 — 13 cases, 3/3 interaction cases, zero gaps or diagnostics
  • stress raw-line shard — 5/5 cells passed
  • release/CI workflow contract tests and YAML parsing passed
  • changeset status --since=origin/main reports no package bump (infrastructure-only change)

Summary by CodeRabbit

  • New Features

    • Added coordinated versioning and release notes across public chart packages.
    • Added automated release readiness, verification, and publication workflows.
    • Added sharded benchmark execution with improved parallel processing and failure reporting.
    • Added standardized validation and CI commands.
  • Bug Fixes

    • Improved long-axis-title layout on narrow charts.
    • Improved release and benchmark failure detection.
  • Documentation

    • Added contributor guidance for setup, testing, changesets, CI, and releases.
    • Updated development instructions and documented resolved workflow issues.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c15f896-d763-4a38-97fd-04c407b56b42

📥 Commits

Reviewing files that changed from the base of the PR and between b33a7af and f573aa5.

📒 Files selected for processing (3)
  • .github/workflows/chart-library-benchmarks.yml
  • .github/workflows/release.yml
  • API-FRICTION.md
📝 Walkthrough

Walkthrough

The PR adds Nx-based repository validation, Changesets release configuration, partitioned benchmark CI, shared GitHub setup, release-state checks, artifact publication, changelog synchronization, and workflow contract tests.

Changes

Charts infrastructure

Layer / File(s) Summary
Workspace execution and contribution contracts
.changeset/*, nx.json, project.json, package.json, pnpm-workspace.yaml, vitest.config.ts, README.md, CONTRIBUTING.md, API-FRICTION.md, .nvmrc, .gitignore
Nx targets and scripts centralize validation. Changesets define fixed package versioning. Repository setup, Vitest exclusions, and contributor guidance are documented.
Partitioned benchmark and CI execution
.github/actions/setup/action.yml, .github/workflows/chart-library-benchmarks.yml, scripts/benchmark/*, scripts/compare-*.mjs, scripts/check-framework-adapters.mjs, scripts/ci-workflow.test.mjs, benchmarks/*, docs/comparison.md, packages/charts-core/docs/comparison.md
Benchmark filtering, concurrent case building, adapter checks, browser setup, matrix jobs, artifacts, aggregate gating, baseline updates, and workflow contract validation are added or updated.
Validated release workflow
.github/workflows/release.yml, scripts/release-security.mjs, scripts/verify-ci-success.mjs, scripts/verify-published-release.mjs, scripts/release-workflow.test.mjs
Release processing supports manual and validated triggers, successful-main checks, artifact validation, OIDC publishing, package verification, and GitHub release creation.
Release state, package publication, and changelog artifacts
scripts/release-status.mjs, scripts/publish-release.mjs, scripts/release-package-config.mjs, scripts/run-with-concurrency.mjs, scripts/sync-release-changelog.mjs, scripts/write-release-notes.mjs, scripts/*test.mjs
Release readiness, stable-version validation, bounded publication, changelog synchronization, release-note generation, concurrency handling, and related tests are added.
Compact chart title layout
packages/charts-core/src/scene.ts, packages/charts-core/src/scene-layout.test.ts, .changeset/compact-axis-titles.md, benchmarks/conformance/cases/*/tanstack.ts
Narrow charts use a smaller x-axis label font. Tests verify containment of long titles. Three conformance cases remove fixed margins.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Possibly related PRs

  • TanStack/charts#2: Modifies chart catalog validation and publication in the benchmark workflow.
  • TanStack/charts#5: Modifies the release workflow and release scripts, including publication and package-version validation.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR's two main changes: cached Nx-based CI and automated release workflows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch taren/nx-ci-release

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.

@socket-security

socket-security Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednx@​22.7.55910093100100
Added@​changesets/​changelog-github@​0.7.01001006893100
Added@​changesets/​cli@​2.31.19710010095100

View full report

@socket-security

socket-security Bot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
High CVE: Axios Node HTTP adapter can use an inherited proxy after interceptor config cloning

CVE: GHSA-gcfj-64vw-6mp9 Axios Node HTTP adapter can use an inherited proxy after interceptor config cloning (HIGH)

Affected versions: >= 0.31.1 < 0.33.0; >= 1.15.2 < 1.18.0

Patched version: 1.18.0

From: pnpm-lock.yamlnpm/nx@22.7.5npm/axios@1.16.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/axios@1.16.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: npm brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash

CVE: GHSA-mh99-v99m-4gvg brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash (HIGH)

Affected versions: < 5.0.8

Patched version: 5.0.8

From: pnpm-lock.yamlnpm/nx@22.7.5npm/brace-expansion@5.0.6

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/brace-expansion@5.0.6. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: npm brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups

CVE: GHSA-3jxr-9vmj-r5cp brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups (HIGH)

Affected versions: >= 3.0.0 < 5.0.7; < 1.1.16; >= 2.0.0 < 2.1.2

Patched version: 5.0.7

From: pnpm-lock.yamlnpm/nx@22.7.5npm/brace-expansion@5.0.6

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/brace-expansion@5.0.6. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: npm form-data: CRLF injection in form-data via unescaped multipart field names and filenames

CVE: GHSA-hmw2-7cc7-3qxx form-data: CRLF injection in form-data via unescaped multipart field names and filenames (HIGH)

Affected versions: < 2.5.6; >= 3.0.0 < 3.0.5; >= 4.0.0 < 4.0.6

Patched version: 4.0.6

From: pnpm-lock.yamlnpm/nx@22.7.5npm/form-data@4.0.5

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/form-data@4.0.5. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm nx is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package.jsonnpm/nx@22.7.5

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/nx@22.7.5. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: npm tmp: Type-confusion bypass of _assertPath allows path traversal via non-string prefix/postfix/template

CVE: GHSA-7c78-jf6q-g5cm tmp: Type-confusion bypass of _assertPath allows path traversal via non-string prefix/postfix/template (HIGH)

Affected versions: >= 0.2.6 < 0.2.7

Patched version: 0.2.7

From: pnpm-lock.yamlnpm/nx@22.7.5npm/tmp@0.2.6

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/tmp@0.2.6. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@coderabbitai coderabbitai 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.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/release.yml (1)

166-171: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Disable automatic npm caching in the privileged release workflow.

cache: '' only clears the explicit cache input; it does not disable the newer automatic npm caching path in actions/setup-node v4+. Set package-manager-cache: false on the release job’s setup-node step if the publish/release job runs automatically, or omit the setup step entirely if Node is not needed for the release creation step.

🤖 Prompt for 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.

In @.github/workflows/release.yml around lines 166 - 171, Update the “Setup
Node” step in the release workflow to explicitly set package-manager-cache to
false, preventing automatic npm caching while preserving the existing Node and
registry configuration.

Source: Linters/SAST tools

🧹 Nitpick comments (7)
.github/actions/setup/action.yml (1)

25-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive the Playwright cache key from the lockfile.

The key hardcodes 1.62.0. If the Playwright version changes in pnpm-lock.yaml and this string is not updated, the cache hits, Install Chromium is skipped, and the runner uses browsers built for the previous version.

♻️ Proposed cache key
-        key: ${{ runner.os }}-playwright-1.62.0
+        key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
🤖 Prompt for 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.

In @.github/actions/setup/action.yml around lines 25 - 36, Update the
playwright-cache step’s key to derive its Playwright version from pnpm-lock.yaml
instead of hardcoding 1.62.0, ensuring lockfile version changes produce a
distinct cache key and trigger Install Chromium when needed. Preserve the
existing runner OS prefix and cache path.
scripts/ci-workflow.test.mjs (1)

282-295: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Extend the pin check to composite actions and accept only exact SHA lengths.

Two gaps:

  1. The check reads only chart-library-benchmarks.yml. .github/actions/setup/action.yml also uses external actions, and its actions/cache pin is 41 characters, which is not a valid SHA. The test passes today.
  2. {40,64} accepts any length between 40 and 64, including 41. Use (?:[0-9a-f]{40}|[0-9a-f]{64}) so only SHA-1 and SHA-256 lengths pass.
♻️ Proposed check
+const setupAction = await readFile(
+  resolve(import.meta.dirname, '../.github/actions/setup/action.yml'),
+  'utf8',
+)
+
 function assertPinnedExternalActions(source) {
   const uses = [...source.matchAll(/^\s*uses:\s*([^\s#]+)\s*(?:#.*)?$/gm)].map(
     (match) => match[1],
   )
   assert.ok(uses.length > 0, 'workflow must use actions')
   for (const action of uses) {
     if (action.startsWith('./')) continue
     assert.match(
       action,
-      /@[0-9a-f]{40,64}$/,
+      /@(?:[0-9a-f]{40}|[0-9a-f]{64})$/,
       `${action} must be pinned to an immutable commit`,
     )
   }
 }

Then call assertPinnedExternalActions(setupAction) alongside the workflow assertion at Line 25.

🤖 Prompt for 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.

In `@scripts/ci-workflow.test.mjs` around lines 282 - 295, Update
assertPinnedExternalActions to accept only 40- or 64-character hexadecimal
commit SHAs, replacing the ranged length check with exact SHA-1/SHA-256
alternatives. Load the contents of .github/actions/setup/action.yml and invoke
assertPinnedExternalActions for it alongside the existing workflow assertion so
composite-action references are validated too.
scripts/check-framework-adapters.mjs (1)

73-88: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Duplicated worker pool without fail-fast in scripts/check-framework-adapters.mjs and scripts/compare-chart-libraries.mjs. Both sites implement the same index-pulling pool, and scripts/publish-release.mjs holds a third copy. In all copies, a rejection in one worker does not stop the remaining workers, so builds keep starting while cleanup runs.

  • scripts/check-framework-adapters.mjs#L73-L88: add an abort flag to runWithConcurrency, then move it into a shared module such as scripts/benchmark/concurrency.mjs.
  • scripts/compare-chart-libraries.mjs#L281-L296: replace the inline loop in buildCases with an import of the shared helper.
🤖 Prompt for 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.

In `@scripts/check-framework-adapters.mjs` around lines 73 - 88, Extract
runWithConcurrency into a shared concurrency module and add fail-fast behavior
using an abort flag so a rejected operation prevents workers from starting
further operations; preserve the existing concurrency limit and propagate the
rejection. In scripts/check-framework-adapters.mjs#L73-L88, replace the local
implementation with the shared helper import. In
scripts/compare-chart-libraries.mjs#L281-L296, replace the inline worker loop in
buildCases with the same helper import. Do not modify
scripts/publish-release.mjs#L? unless separately required by the shared-helper
extraction.
.github/workflows/release.yml (1)

46-55: 🩺 Stability & Availability | 🔵 Trivial

Confirm that the version pull request can satisfy branch protection.

changesets/action uses secrets.GITHUB_TOKEN. GitHub does not start new workflow runs for commits or pull requests created with that token. The ci: Version Packages pull request therefore gets no Chart library benchmarks run and no CI check.

If CI is a required status check on main, the version pull request cannot merge without manual intervention. Use a GitHub App token or a dedicated PAT for this job, or exempt this bot pull request from the required check.

🤖 Prompt for 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.

In @.github/workflows/release.yml around lines 46 - 55, Update the
changesets/action authentication in the “Create or update version pull request”
step so it uses a GitHub App token or dedicated PAT that can trigger workflows,
instead of secrets.GITHUB_TOKEN; alternatively configure branch protection to
exempt this bot pull request from the required CI and Chart library benchmarks
checks.
scripts/verify-ci-success.mjs (1)

20-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the shared release repository slug.

scripts/release-security.mjs exports releaseRepositorySlug, and releases use it. Import that constant from ./release-security.mjs in verify-ci-success.mjs instead of duplicating 'TanStack/charts' so the repository requires fewer edit points.

🤖 Prompt for 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.

In `@scripts/verify-ci-success.mjs` around lines 20 - 24, Update the repository
assertion in verify-ci-success.mjs to import and use the shared
releaseRepositorySlug exported by release-security.mjs instead of the hardcoded
'TanStack/charts' value, preserving the existing CI gate validation.
scripts/publish-release.mjs (1)

99-99: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Share one runWithConcurrency implementation.

scripts/publish-release.mjs uses (values, concurrency, operation), while scripts/check-framework-adapters.mjs uses (operations, concurrency) where each operation is a thunk. Keep helper implementations separate, export distinct shared helpers, or rename the current helpers until the call sites use one contract.

🤖 Prompt for 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.

In `@scripts/publish-release.mjs` at line 99, Unify the runWithConcurrency
contract used by scripts/publish-release.mjs and
scripts/check-framework-adapters.mjs: both call sites must use the same argument
shape and operation semantics. Share a single implementation, or rename/export
distinct helpers to avoid conflicting definitions, then update each caller
accordingly while preserving existing concurrency behavior.
scripts/release-workflow.test.mjs (1)

162-239: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared workflow contract helpers into one module.

scripts/ci-workflow.test.mjs and scripts/release-workflow.test.mjs both define job, needs, scalarList, assertPinnedExternalActions, indentation, and escapeRegExp. Move these helpers to a shared file such as scripts/workflow-contract.mjs and import them from both tests.

🤖 Prompt for 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.

In `@scripts/release-workflow.test.mjs` around lines 162 - 239, Extract job,
needs, scalarList, assertPinnedExternalActions, indentation, and escapeRegExp
from both workflow test files into a shared scripts/workflow-contract.mjs
module, exporting each helper. Remove the duplicate definitions and import the
shared helpers in scripts/ci-workflow.test.mjs and
scripts/release-workflow.test.mjs, preserving their existing behavior and
assertions.
🤖 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 @.github/actions/setup/action.yml:
- Line 17: Update both actions/cache references in the workflow to use the valid
40-character commit SHA 668228422ae6a00e4ad889ee87cd7109ec5666a7, removing the
trailing d while preserving the v5.0.4 pin comment.

In @.github/workflows/chart-library-benchmarks.yml:
- Around line 118-120: Update the “Publish comparison summary” step and the
conformance summary step to tolerate an empty results glob. Ensure the cat
command does not receive a literal unmatched pattern and does not fail when no
.md files exist, while preserving the current append-to-GITHUB_STEP_SUMMARY
behavior when files are present.

In `@package.json`:
- Around line 11-13: Define separate Nx projects for each package with a ci
target so ci:all and ci:pr operate on a multi-project graph and ci:pr can
exclude unaffected packages; otherwise remove the ci:all and ci:pr scripts from
the package scripts until those project definitions exist.

In `@scripts/publish-release.mjs`:
- Around line 99-110: Update runWithConcurrency to wait for every worker to
settle before propagating failure: collect each worker promise with
Promise.allSettled (or equivalent), gather all rejected worker errors, and throw
an aggregated error only after all operations finish. Preserve the existing
concurrency limit and operation ordering behavior.

In `@scripts/release-package-config.mjs`:
- Around line 109-115: Update assertStableReleaseVersion in
scripts/release-package-config.mjs:109-115 to require each numeric component to
match 0|[1-9]\d*, rejecting leading-zero versions while preserving valid stable
versions. Add a rejected 01.2.3 case in
scripts/release-package-config.test.mjs:15-19.

In `@scripts/release-status.mjs`:
- Around line 51-57: Update the tag-revision validation in classifyReleaseStatus
so an existing tag (tagRevision !== null) requires expectedRevision and cannot
bypass the equality guard when the value is undefined or empty; preserve the
existing matching-revision behavior and reject the missing-value case. Add a
release-status test covering a set tagRevision with expectedRevision omitted.

In `@scripts/verify-ci-success.mjs`:
- Around line 32-41: The external API requests lack deadlines, allowing stalled
responses to block release jobs. Add signal: AbortSignal.timeout(30_000) to the
workflow-runs fetch in scripts/verify-ci-success.mjs, and to the fetch calls
used by readRegistryPackage, readLatestVersion, and githubReleaseExists in
scripts/release-status.mjs; preserve their existing request behavior otherwise.

In `@scripts/verify-ci-success.test.mjs`:
- Around line 19-22: Update the invalid candidate fixtures in the verification
test to include runs with non-main head_branch and non-completed status values,
while keeping the existing invalid cases. Ensure the release-gate filtering
exercised by the test depends on both head_branch and status predicates so
removing either predicate causes the test to fail.

---

Outside diff comments:
In @.github/workflows/release.yml:
- Around line 166-171: Update the “Setup Node” step in the release workflow to
explicitly set package-manager-cache to false, preventing automatic npm caching
while preserving the existing Node and registry configuration.

---

Nitpick comments:
In @.github/actions/setup/action.yml:
- Around line 25-36: Update the playwright-cache step’s key to derive its
Playwright version from pnpm-lock.yaml instead of hardcoding 1.62.0, ensuring
lockfile version changes produce a distinct cache key and trigger Install
Chromium when needed. Preserve the existing runner OS prefix and cache path.

In @.github/workflows/release.yml:
- Around line 46-55: Update the changesets/action authentication in the “Create
or update version pull request” step so it uses a GitHub App token or dedicated
PAT that can trigger workflows, instead of secrets.GITHUB_TOKEN; alternatively
configure branch protection to exempt this bot pull request from the required CI
and Chart library benchmarks checks.

In `@scripts/check-framework-adapters.mjs`:
- Around line 73-88: Extract runWithConcurrency into a shared concurrency module
and add fail-fast behavior using an abort flag so a rejected operation prevents
workers from starting further operations; preserve the existing concurrency
limit and propagate the rejection. In
scripts/check-framework-adapters.mjs#L73-L88, replace the local implementation
with the shared helper import. In scripts/compare-chart-libraries.mjs#L281-L296,
replace the inline worker loop in buildCases with the same helper import. Do not
modify scripts/publish-release.mjs#L? unless separately required by the
shared-helper extraction.

In `@scripts/ci-workflow.test.mjs`:
- Around line 282-295: Update assertPinnedExternalActions to accept only 40- or
64-character hexadecimal commit SHAs, replacing the ranged length check with
exact SHA-1/SHA-256 alternatives. Load the contents of
.github/actions/setup/action.yml and invoke assertPinnedExternalActions for it
alongside the existing workflow assertion so composite-action references are
validated too.

In `@scripts/publish-release.mjs`:
- Line 99: Unify the runWithConcurrency contract used by
scripts/publish-release.mjs and scripts/check-framework-adapters.mjs: both call
sites must use the same argument shape and operation semantics. Share a single
implementation, or rename/export distinct helpers to avoid conflicting
definitions, then update each caller accordingly while preserving existing
concurrency behavior.

In `@scripts/release-workflow.test.mjs`:
- Around line 162-239: Extract job, needs, scalarList,
assertPinnedExternalActions, indentation, and escapeRegExp from both workflow
test files into a shared scripts/workflow-contract.mjs module, exporting each
helper. Remove the duplicate definitions and import the shared helpers in
scripts/ci-workflow.test.mjs and scripts/release-workflow.test.mjs, preserving
their existing behavior and assertions.

In `@scripts/verify-ci-success.mjs`:
- Around line 20-24: Update the repository assertion in verify-ci-success.mjs to
import and use the shared releaseRepositorySlug exported by release-security.mjs
instead of the hardcoded 'TanStack/charts' value, preserving the existing CI
gate validation.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 64db67d1-6e8d-484f-9639-d0892bf549eb

📥 Commits

Reviewing files that changed from the base of the PR and between fa9a61b and b73fb48.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (35)
  • .changeset/README.md
  • .changeset/config.json
  • .github/actions/setup/action.yml
  • .github/workflows/chart-library-benchmarks.yml
  • .github/workflows/release.yml
  • .gitignore
  • .nvmrc
  • API-FRICTION.md
  • CONTRIBUTING.md
  • README.md
  • nx.json
  • package.json
  • pnpm-workspace.yaml
  • project.json
  • scripts/benchmark/filters.mjs
  • scripts/benchmark/filters.test.mjs
  • scripts/check-framework-adapters.mjs
  • scripts/ci-workflow.test.mjs
  • scripts/compare-chart-libraries.mjs
  • scripts/compare-plot-catalog.mjs
  • scripts/publish-release.mjs
  • scripts/release-package-config.mjs
  • scripts/release-package-config.test.mjs
  • scripts/release-security.mjs
  • scripts/release-security.test.mjs
  • scripts/release-status.mjs
  • scripts/release-status.test.mjs
  • scripts/release-workflow.test.mjs
  • scripts/sync-release-changelog.mjs
  • scripts/sync-release-changelog.test.mjs
  • scripts/verify-ci-success.mjs
  • scripts/verify-ci-success.test.mjs
  • scripts/vitest-config.test.mjs
  • scripts/write-release-notes.mjs
  • vitest.config.ts

Comment thread .github/actions/setup/action.yml Outdated
Comment thread .github/workflows/chart-library-benchmarks.yml Outdated
Comment thread package.json Outdated
Comment thread scripts/publish-release.mjs Outdated
Comment on lines +99 to +110
async function runWithConcurrency(values, concurrency, operation) {
let nextIndex = 0
await Promise.all(
Array.from({ length: Math.min(concurrency, values.length) }, async () => {
while (nextIndex < values.length) {
const index = nextIndex
nextIndex += 1
await operation(values[index])
}
}),
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Let all workers settle before the publication step fails.

Promise.all rejects as soon as one worker throws. The other workers continue, and the module-level await rejects, so Node exits while an npm publish request is still in flight. The reported error also hides failures from the remaining workers.

Wait for every worker, then throw an aggregated error.

🛡️ Proposed fix
 async function runWithConcurrency(values, concurrency, operation) {
   let nextIndex = 0
-  await Promise.all(
+  const results = await Promise.allSettled(
     Array.from({ length: Math.min(concurrency, values.length) }, async () => {
       while (nextIndex < values.length) {
         const index = nextIndex
         nextIndex += 1
         await operation(values[index])
       }
     }),
   )
+  const failures = results
+    .filter((result) => result.status === 'rejected')
+    .map((result) => result.reason)
+  if (failures.length > 0) {
+    throw new AggregateError(failures, 'Artifact publication failed')
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function runWithConcurrency(values, concurrency, operation) {
let nextIndex = 0
await Promise.all(
Array.from({ length: Math.min(concurrency, values.length) }, async () => {
while (nextIndex < values.length) {
const index = nextIndex
nextIndex += 1
await operation(values[index])
}
}),
)
}
async function runWithConcurrency(values, concurrency, operation) {
let nextIndex = 0
const results = await Promise.allSettled(
Array.from({ length: Math.min(concurrency, values.length) }, async () => {
while (nextIndex < values.length) {
const index = nextIndex
nextIndex += 1
await operation(values[index])
}
}),
)
const failures = results
.filter((result) => result.status === 'rejected')
.map((result) => result.reason)
if (failures.length > 0) {
throw new AggregateError(failures, 'Artifact publication failed')
}
}
🤖 Prompt for 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.

In `@scripts/publish-release.mjs` around lines 99 - 110, Update runWithConcurrency
to wait for every worker to settle before propagating failure: collect each
worker promise with Promise.allSettled (or equivalent), gather all rejected
worker errors, and throw an aggregated error only after all operations finish.
Preserve the existing concurrency limit and operation ordering behavior.

Comment thread scripts/release-package-config.mjs
Comment thread scripts/release-status.mjs Outdated
Comment thread scripts/verify-ci-success.mjs
Comment thread scripts/verify-ci-success.test.mjs

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 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 `@scripts/verify-published-release.mjs`:
- Line 202: Update waitForAttestations() to catch fetch errors caused by
AbortSignal.timeout(requestTimeout), call delay(), and continue polling;
preserve the existing behavior of stopping on non-timeout failures. Add coverage
for an initial timed-out attestation request followed by a successful later
request.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 70aa9748-6008-4b13-85a9-c635119c6f02

📥 Commits

Reviewing files that changed from the base of the PR and between b73fb48 and b33a7af.

📒 Files selected for processing (31)
  • .changeset/compact-axis-titles.md
  • .changeset/config.json
  • .github/actions/setup/action.yml
  • .github/workflows/chart-library-benchmarks.yml
  • .github/workflows/release.yml
  • API-FRICTION.md
  • benchmarks/bundle-size/universal-baseline.json
  • benchmarks/comparison/bundle-baseline.json
  • benchmarks/conformance/cases/04-stacked-time-area/tanstack.ts
  • benchmarks/conformance/cases/21-streamgraph/tanstack.ts
  • benchmarks/conformance/cases/54-bump-ranking/tanstack.ts
  • docs/comparison.md
  • package.json
  • packages/charts-core/docs/comparison.md
  • packages/charts-core/src/scene-layout.test.ts
  • packages/charts-core/src/scene.ts
  • packages/octane-charts/src/CanvasChart.client.test.tsrx
  • scripts/check-framework-adapters.mjs
  • scripts/ci-workflow.test.mjs
  • scripts/compare-chart-libraries.mjs
  • scripts/publish-release.mjs
  • scripts/release-package-config.mjs
  • scripts/release-package-config.test.mjs
  • scripts/release-status.mjs
  • scripts/release-status.test.mjs
  • scripts/release-workflow.test.mjs
  • scripts/run-with-concurrency.mjs
  • scripts/run-with-concurrency.test.mjs
  • scripts/verify-ci-success.mjs
  • scripts/verify-ci-success.test.mjs
  • scripts/verify-published-release.mjs
💤 Files with no reviewable changes (4)
  • benchmarks/conformance/cases/21-streamgraph/tanstack.ts
  • benchmarks/conformance/cases/04-stacked-time-area/tanstack.ts
  • benchmarks/conformance/cases/54-bump-ranking/tanstack.ts
  • package.json
🚧 Files skipped from review as they are similar to previous changes (14)
  • scripts/release-package-config.test.mjs
  • scripts/verify-ci-success.test.mjs
  • scripts/check-framework-adapters.mjs
  • .github/actions/setup/action.yml
  • scripts/release-package-config.mjs
  • .changeset/config.json
  • scripts/verify-ci-success.mjs
  • scripts/release-status.test.mjs
  • .github/workflows/chart-library-benchmarks.yml
  • scripts/release-status.mjs
  • .github/workflows/release.yml
  • scripts/publish-release.mjs
  • scripts/release-workflow.test.mjs
  • scripts/ci-workflow.test.mjs

const response = await fetch(url, {
headers: { accept: 'application/json' },
redirect: 'error',
signal: AbortSignal.timeout(requestTimeout),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
fd -a 'verify-published-release\.mjs$' . || true

echo "== file outline/size =="
wc -l scripts/verify-published-release.mjs
ast-grep outline scripts/verify-published-release.mjs --view expanded || true

echo "== relevant lines 160-230 =="
sed -n '160,230p' scripts/verify-published-release.mjs | nl -ba -v160

echo "== search requestTimeout / waitForAttestations / fetch usages =="
rg -n "requestTimeout|waitForAttestations|AbortSignal\.timeout|fetch\(" scripts/verify-published-release.mjs

Repository: TanStack/charts

Length of output: 916


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== full relevant implementation around requestTimeout =="
python3 - <<'PY'
from pathlib import Path
p=Path('scripts/verify-published-release.mjs')
lines=p.read_text().splitlines()
for i,l in enumerate(lines,1):
    if 'requestTimeout' in l or 'waitForAttestations' in l or 'AbortSignal.timeout' in l or 'fetch(' in l:
        start=max(1,i-20); end=min(len(lines),i+35)
        print(f"\n--- {p}:{start}-{end} ---")
        for n in range(start,end+1):
            print(f"{n}: {lines[n-1]}")
PY

echo "== behavioral model of current loop shape from source =="
python3 - <<'PY'
from pathlib import Path
import re
s=Path('scripts/verify-published-release.mjs').read_text()
m=re.search(r'async function waitForAttestations\(.*?\)\s*\{(?P<body>.*?)\n\b\}', s, re.S)
if not m:
    m=re.search(r'function waitForAttestations\(.*?\)\s*\{(?P<body>.*?)\n\}', s, re.S)
print("found function:", bool(m))
print(m.group('body')[:2000] if m else "")
PY

Repository: TanStack/charts

Length of output: 11020


🏁 Script executed:

#!/bin/bash
set -euo pipefail

node - <<'JS'
const url = new URL('data:text/plain,hello')
const timeoutMs = 10
let controller
try {
  await fetch(url, {
    signal: AbortSignal.timeout(timeoutMs),
  })
  console.log('FETCH_RESOLVED')
} catch (error) {
  console.log(String(error.name) + ' ' + String(error.code) + ' ' + String(error.type))
  controller = error
}
if (controller && controller.name === 'TimeoutError') {
  console.log('timeout_matches')
} else {
  console.log('timeout_mismatch')
}
JS

Repository: TanStack/charts

Length of output: 1215


Retry timed-out attestation requests.

fetch can fail when AbortSignal.timeout(requestTimeout) expires, but waitForAttestations() has no error handling around the fetch(...). A timeout should call delay() and continue the polling loop; only non-timeout fetch failures should stop the polling. Add a test where an initial attestation request times out and a later request succeeds.

🤖 Prompt for 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.

In `@scripts/verify-published-release.mjs` at line 202, Update
waitForAttestations() to catch fetch errors caused by
AbortSignal.timeout(requestTimeout), call delay(), and continue polling;
preserve the existing behavior of stopping on non-timeout failures. Add coverage
for an initial timed-out attestation request followed by a successful later
request.

@tannerlinsley
tannerlinsley merged commit 170b465 into main Jul 31, 2026
23 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 31, 2026
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