publish-npm.yml publishes packages in alphabetical order, under set -euo pipefail. A failure partway through the loop leaves every package before it already on npm — including packages published ahead of their own dependencies.
The loop
for dir in packages/*/; do ... # validation pass — alphabetical
while IFS= read -r dir; do ... # publish pass — same order
( cd "$dir" && pnpm publish --access public --provenance ... )
packages/*/ expands in lexical order. Dependency edges don't respect it.
Two concrete inversions
| package |
depends on |
sorts |
@wave-av/adk |
@wave-av/kernel |
adk first, kernel 23rd |
@wave-av/sdk |
11 of its 44 deps |
sdk before search, sentiment, signage, slides, studio-ai, studio, transcribe, usb, vault, voice, zoom |
npm does not verify that a package's dependencies exist at publish time. So if the run dies after sdk and before zoom — a network blip, a registry 5xx, one package failing validation late, a cancelled job — @wave-av/sdk@3.0.0 is live and permanently broken: its dependencies were never published, and an npm version cannot be replaced once taken. The only remedy is to burn the version and publish a new one.
The same applies to adk, which sorts first in the whole workspace and depends on kernel.
Why the existing guards don't cover it
#45 makes validation atomic — the release is decided in full before anything publishes, so no package ships against a known-bad sibling. But the publish pass itself is still sequential and non-transactional. Atomic validation doesn't make execution atomic; it just means everything entering the loop was fine at the time.
Suggested fix
Publish in topological order. The repo already computes it — the build and pack steps use pnpm -r --filter "@wave-av/*", which topo-sorts:
- name: "Build all packages (pnpm -r topo-sorts: core then products then umbrella)"
run: pnpm -r --filter "@wave-av/*" build
So the ordering is available; the publish loop just doesn't consume it. Either drive the publish from pnpm -r directly, or have the validation pass emit publishable in dependency order instead of directory order.
A cheaper partial mitigation, if the full fix is too invasive: publish the umbrella last, since it is the package with the most inbound edges. That fixes sdk and leaves adk/kernel broken, so it's a stopgap rather than a repair.
Not fixing in #45
#45 is scoped to release validation and is already testable without CI. This one changes publish execution, and I can't verify an ordering change while org Actions are billing-locked — the failure mode it prevents is exactly a partially-executed publish, which is not something to ship on reasoning alone. Filing so it isn't lost.
Context: #42, #44, #45.
publish-npm.ymlpublishes packages in alphabetical order, underset -euo pipefail. A failure partway through the loop leaves every package before it already on npm — including packages published ahead of their own dependencies.The loop
packages/*/expands in lexical order. Dependency edges don't respect it.Two concrete inversions
@wave-av/adk@wave-av/kerneladkfirst,kernel23rd@wave-av/sdksdkbeforesearch, sentiment, signage, slides, studio-ai, studio, transcribe, usb, vault, voice, zoomnpm does not verify that a package's dependencies exist at publish time. So if the run dies after
sdkand beforezoom— a network blip, a registry 5xx, one package failing validation late, a cancelled job —@wave-av/sdk@3.0.0is live and permanently broken: its dependencies were never published, and an npm version cannot be replaced once taken. The only remedy is to burn the version and publish a new one.The same applies to
adk, which sorts first in the whole workspace and depends onkernel.Why the existing guards don't cover it
#45 makes validation atomic — the release is decided in full before anything publishes, so no package ships against a known-bad sibling. But the publish pass itself is still sequential and non-transactional. Atomic validation doesn't make execution atomic; it just means everything entering the loop was fine at the time.
Suggested fix
Publish in topological order. The repo already computes it — the build and pack steps use
pnpm -r --filter "@wave-av/*", which topo-sorts:So the ordering is available; the publish loop just doesn't consume it. Either drive the publish from
pnpm -rdirectly, or have the validation pass emitpublishablein dependency order instead of directory order.A cheaper partial mitigation, if the full fix is too invasive: publish the umbrella last, since it is the package with the most inbound edges. That fixes
sdkand leavesadk/kernelbroken, so it's a stopgap rather than a repair.Not fixing in #45
#45 is scoped to release validation and is already testable without CI. This one changes publish execution, and I can't verify an ordering change while org Actions are billing-locked — the failure mode it prevents is exactly a partially-executed publish, which is not something to ship on reasoning alone. Filing so it isn't lost.
Context: #42, #44, #45.