Fail the npm already-published check closed
release-typescript.yml.tmpl decides whether to publish with if npm view "<pkg>@<ver>" version 2>/dev/null. npm view exits non-zero for an absent version (E404), but also for a DNS failure, an auth error, a registry 5xx or a timeout, so every one of those read as "not published" and the workflow went on to npm publish. npm refuses to overwrite an existing version, so the realistic damage was a confusing failure at the wrong step rather than a duplicate publish, but the shape is wrong, and the Rust release template that follows will carry a crates.io check of the same shape, so the seed should show the fail-closed form.
Now: publish only when npm positively answers E404; a 0 exit with a version string is "already published" (skip); anything else prints npm's output, fails the job, and leaves a re-run of the same push run as the recovery (the orchestrator in #9 tells you how). The step reads the version through env: rather than ${{ }} expansion inside run:.
Consumer reach
Seed template only — copied at instantiation. fizzy-sdk and basecamp-sdk carry the same check in their own release-typescript.yml (hey-sdk has no TypeScript); flagging that to the Rust lanes for those repos rather than changing them here.
Gates
Rebased on main past #11 and #14. Rendered with hack/render-seed.sh and run through the seed job's own steps: zizmor (--min-severity high, seed config) clean; the step script shellchecks clean. actionlint fails on every rendered release template's uses: $/.github/workflows/smithy-verify.yml — that is #14's syntax, red on main since it merged (actionlint 1.7.12 predates the $/ form), and #18 carries the seed/.github/actionlint.yaml that clears it; verified locally that rendering with that file makes actionlint pass. So the "Seed templates" check here stays red until #18 lands, for a reason this PR does not touch.