Skip to content

fix(ci): publish in topological order so a mid-run failure cannot strand a package ahead of its deps - #47

Open
yakimoto wants to merge 2 commits into
fix/publish-version-guardfrom
fix/publish-topological-order
Open

yakimoto wants to merge 2 commits into
fix/publish-version-guardfrom
fix/publish-topological-order

Conversation

@yakimoto

@yakimoto yakimoto commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

User description

Closes #46. Stacked on #45 (base is fix/publish-version-guard, not main) — both change the same publish step, so basing this on main would conflict.

The defect

The publish loop iterates packages/*/, which globs alphabetically. That is not dependency order, and the loop runs under set -euo pipefail — so a failure partway through leaves every package before the failure point already live on npm.

Measured on this workspace:

workspace packages: 49
dependency cycles:  0
ALPHABETICAL VIOLATIONS (package sorts before its own dependency): 23
  @wave-av/adk (0) before dep @wave-av/kernel (22)
  @wave-av/audience (1) before dep @wave-av/core (12)
  … 12 packages sort ahead of @wave-av/core

npm does not validate that a dependency exists at publish time, and a published version can never be replaced. So an interrupted alphabetical run can leave a permanently-broken package sitting on latest.

The fix

Sort the already-validated publishable set topologically before executing it. Only edges to packages in this release constrain the order — a dependency already on the registry is satisfied regardless of when we publish, so it imposes nothing.

Nothing else changes: auth (OIDC, no token), permissions, the publish command, and all three existing guards from #45 (backwards-version, unresolved-dependency, tarball-size) run unmodified in the earlier validation pass. This only reorders a set that has already been approved.

Three deliberate hardening choices, since this is the last thing standing between a tag push and npm:

  • Fail closed on a cycle. No publish order is safe if one exists, so it errors and publishes nothing rather than picking arbitrarily.
  • Re-validate each path against ^packages/[a-z0-9][a-z0-9._-]*/$. The dirs come from the workflow's own glob, but this script builds a filesystem path from each one, and provenance is not a substitute for validation.
  • Null-prototype maps. Package names are used as object keys; a package named __proto__ would corrupt the lookup rather than merely being wrong.

The node program is a fixed single-quoted argv with input on stdin — no ${{ }} interpolation, and no package-controlled data is ever assembled into code.

Verification

CI cannot run — the whole org is under a GitHub billing lock ("The job was not started because your account is locked due to a billing issue."), which affects public repos too. So this was verified locally against the exact bytes extracted from the workflow file, not a copy:

TEST 1 — real workspace (all 49 packages)
  PASS  all 49 packages present (none dropped)
  PASS  0 ordering violations (was 23 alphabetically)
        first 6 published: kernel adk core audience autopilot billing
TEST 2 — dependency cycle must fail closed
  PASS  exit 1 — cycle rejected
  PASS  names the cycle: @wave-av/alpha -> @wave-av/beta -> @wave-av/alpha
TEST 3 — path outside packages/ must fail closed
  PASS  exit 1 — traversal path rejected
TEST 4 — partial release (core, adk, kernel only)
  PASS  kernel(1) before adk(2)

RESULT: 6 passed, 0 failed

This should not be merged until CI can actually run it. Branch protection is currently unenforced org-wide as a side effect of the same billing lock, so a green tick here would mean the gate vanished, not that the change passed.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Note

Medium Risk
Touches the final npm publish step for coordinated releases; mis-ordering or sort bugs could still block or mis-sequence publishes, though the change is designed to fail closed.

Overview
The npm publish job no longer runs pnpm publish over the validated publishable list in glob order (packages/*/). It first pipes that list through an inline Node topological sort that only considers @wave-av/* edges between packages in the same release; dependencies already on the registry do not affect order.

The publish loop now consumes $topo_sorted instead of $publishable. If sorting fails, returns empty output for a non-empty release, finds a cycle, or sees an unexpected package path, the workflow errors and publishes nothing (cycle path is logged). Package directory paths are re-validated and name lookups use null-prototype objects to avoid key pollution.

Validation, auth, and per-package publish flags are unchanged—only execution order after eligibility checks.

Reviewed by Cursor Bugbot for commit a880b86. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Publishes release packages in dependency order so a mid-run failure can't leave a package live on npm ahead of its own dependencies. The publish loop previously iterated packages/*/ alphabetically, which violates dependency order for 23 of 49 packages in this workspace; npm allows publishing a package whose deps don't exist yet, and a published version can't be replaced, so an interrupted run could strand a broken latest.

The new topo-sorted order is computed only from the already-validated publishable set and only edges to packages in this same release constrain ordering. It fails closed on dependency cycles, re-validates package paths, and uses null-prototype maps to avoid key pollution. All existing validation guards and auth are unchanged.

Verification

  • Ran locally against the exact workflow script bytes: all 49 packages preserved, 0 ordering violations (was 23), cycle/path/partial-release tests pass (6 total).
  • CI couldn't run at the time due to org-wide GitHub billing lock; merge should wait until CI passes.

Written for commit a880b86. Summary will update on new commits.

Review in cubic


CodeAnt-AI Description

Publish packages in dependency order to prevent broken releases after failures

What Changed

  • Packages are published only after any dependencies included in the same release
  • Publishing stops without releasing packages if a dependency cycle or invalid package path is detected
  • A failed or empty publish-order calculation now prevents partial or unsafe releases

Impact

✅ Fewer broken packages after interrupted releases
✅ Dependencies are available before dependent packages go live
✅ Safer release failures with no partial publish

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@changeset-bot

changeset-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1d1a4fe

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cursor

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_74b087d7-a5b8-4494-b0ea-39a67ad9cdf0)

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 63c0cc1c-a0fe-430c-84b5-bf16708b5bb1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/publish-topological-order
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/publish-topological-order

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

@codeant-ai

codeant-ai Bot commented Sep 8, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR a880b86 Sep 08, 2026 · 18:23 18:26

@codeant-ai

codeant-ai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_09e0c9f7-c1e4-4cbd-95af-b7fe6a4eb689)

@codeant-ai codeant-ai Bot added the size:M This PR changes 30-99 lines, ignoring generated files label Sep 8, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 8, 2026

Copy link
Copy Markdown

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes the npm release workflow’s production behavior by introducing dependency-based ordering and new conditions that can prevent an entire release from publishing. The implementation is confined to one file, but it controls irreversible package publication and is owned by a separate team, so designated human review is appropriate.

Not approved because:

  • Credit balance exhausted. Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more.

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

Labels

size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant