Commit Graph
10 Commits
Author SHA1 Message Date
Devin Foley bfb4ceabbb perf(release): wait for npm registry visibility of all packages concurrently (#13495)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The release system publishes ~33 public npm packages per release
across the canary, nightly, beta, and stable channels
> - `scripts/release.sh` publishes them strictly sequentially: publish
one package, poll npm until that version is registry-visible, then start
the next
> - npm accepts a publish in seconds, but registry packument propagation
can lag minutes per package (the CI budget was raised to 30 minutes per
package after two aborted releases), so the total publish time is the
sum of every package's lag — about two hours on a bad npm day, paid by
every channel run including every canary on every master push
> - This pull request keeps the publishes sequential but runs all the
registry visibility polls concurrently once every publish is accepted
> - The benefit is that the wall-clock cost of npm propagation drops
from the sum of all packages' lag to the single slowest package's lag,
with every existing safety property preserved

## Linked Issues or Issue Description

No existing issue. Description follows the enhancement template:

**What existing behavior does this improve?**
The npm publish step of `scripts/release.sh` (Step 5), used by every
release channel.

**Subsystem affected**
Release tooling (`scripts/release.sh`, `scripts/release-lib.sh`).

**Current behavior**
Packages publish one at a time, and after each publish the script polls
npm until that package's version is visible in the registry packument
before publishing the next. With per-package propagation lag of minutes
(observed up to ~15 minutes; per-package CI budget is 30 minutes), the
full 33-package set takes up to ~2 hours of mostly idle waiting.

**Proposed behavior**
Phase 1 publishes every package sequentially exactly as today (a
rejected publish still aborts the batch immediately with exact
attribution). Phase 2 then polls registry visibility for all packages
concurrently. Each package keeps its own `NPM_PUBLISH_VERIFY_ATTEMPTS` ×
`NPM_PUBLISH_VERIFY_DELAY_SECONDS` budget, and any version that never
becomes visible still hard-fails the release, now naming every
straggler.

**Reason and benefit**
Total publish wait becomes the slowest single package's lag instead of
the sum of all lags — typically minutes instead of hours. This shortens
every canary, nightly, beta, and stable run and reduces exposure to job
timeouts during npm slowdowns.

**Breaking changes**
None. Dry-run output is byte-identical in structure, dist-tags are still
applied at publish time (`--tag`), the Sigstore TLOG duplicate-recovery
path is untouched, and the later dist-tag integrity check
(`wait_for_release_registry_state`) is unchanged.

## What Changed

- `scripts/release-lib.sh`: replaced `publish_package_to_npm_and_wait`
with `wait_for_npm_package_versions`, which takes the package tuple list
and polls every package's visibility in background subshells, each
reusing the existing `wait_for_npm_package_version` poll (same
per-package budget), then reports per-package success or fails naming
all stragglers
- `scripts/release.sh` Step 5: the publish loop calls
`publish_package_to_npm` only (sequential, fail-fast on a rejected
publish), followed by one call to `wait_for_npm_package_versions` for
the whole set; Step 6's recap line updated to match
- `scripts/release-lib.test.mjs`: the registry-visibility and
workflow-budget tests now drive the new function (same assertions on
`npm view` counts, virtual sleeps, and the fail-closed message, which
now names the straggler); a new cross-visibility test proves concurrency
— two fake packages that each become visible only after the other has
been polled can only converge when polled in parallel, so the test fails
if the waits ever serialize again

Safety analysis for the ordering change: nothing in the publish loop
resolves sibling packages from the registry.
`prepare-bundled-package.mjs` bundles and patches from the local
workspace tree, and the TLOG duplicate-recovery path only queries the
package it just published. The only consumer of the "visible before next
publish" invariant was the release script's own final verification,
which still runs against the full set.

## Verification

- `node --test scripts/release-lib.test.mjs` — 15 tests pass, including
the new concurrency proof and the existing 15-minute-20-second budget
tolerance test against the new function
- `npm run test:release-registry` — full lane, 140 tests pass
- `bash -n` on both scripts; `shellcheck` reports no findings beyond the
three pre-existing ones on master (verified by comparing counts against
`origin/master` copies)
- A real-release exercise happens on the next master push: every canary
run executes this exact path

## Risks

- Low. The failure mode most worth watching is a release where some
packages become visible and others never do: previously the run stopped
at the first invisible package with later packages unpublished; now all
packages are accepted before visibility is enforced, and the run fails
naming every straggler. Recovery is identical in both worlds (the next
attempt derives a new version number), and the accepted-but-lagging
packages carry the correct dist-tag either way.
- Publish jobs run the source commit's copy of `release.sh`, so this
change takes effect for a given channel only once its source commit
includes this merge — promoted nightlies/betas cut from older commits
keep the old sequential behavior until their trains catch up.

## Model Used

Claude Fable 5 (`claude-fable-5`), extended thinking with tool use
(Claude Code).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-09-15 16:09:51 -07:00
Devin FoleyandPaperclip 52d120f68d fix(release): wait 30 minutes for npm to expose a published version (#13436)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Every release publishes a batch of npm packages and then waits for
each one to become visible before continuing
> - npm accepts a publish immediately but exposes it later, so that wait
exists to keep a release from continuing past a package nobody can
install yet
> - Today that wait was too short twice in a row, and each timeout
aborted the release with the batch half-published
> - Version numbers are derived from what is already on npm, so every
retry moves to a new number and meets the same lag
> - Two canary attempts burned two versions this way and shipped nothing
> - This pull request raises the per-package budget from ten minutes to
thirty
> - The benefit is that ordinary registry lag costs waiting instead of a
failed, half-published release

## Linked Issues or Issue Description

No existing issue. The problem, in the bug report format:

**What happened**
`publish_canary` failed twice in a row with the batch half-published:

```
Warning: npm accepted @paperclipai/server@2026.914.0-canary.2, but the version did not become registry-visible.
Error: stopping release: npm did not publish and expose @paperclipai/server@2026.914.0-canary.2
```

The version was accepted at 17:49:09 and became visible at 18:04:29 —
about five minutes after the poll gave up. `shared`, `db` and
`adapter-utils` published at that version; `server`, `paperclip-runner`
and the root package did not.

**Expected behavior**
Ordinary registry propagation delay costs the release some waiting, not
a failure. A package that becomes visible after 15 minutes must not
abort the batch because of the old 10-minute wait. Longer registry
outages can still leave a partial batch.

**Steps to reproduce**
1. Publish any channel while npm is propagating slowly.
2. A package takes longer than `NPM_PUBLISH_VERIFY_ATTEMPTS *
NPM_PUBLISH_VERIFY_DELAY_SECONDS` to become visible.
3. The release aborts, that version is half-published, and the retry
picks a new version number and meets the same lag.

**Paperclip version or commit**
Present on master. Observed on 2026-09-14 across canary runs in workflow
run 34869494325.

## What Changed

- Increase npm visibility checks from 60 to 180, retaining the 10-second
delay: about 30 minutes per package.
- Increase canary, nightly, beta, and stable publish job timeouts from
90 to 150 minutes.
- Add offline regression tests using the workflow's actual settings.
They cover the observed 15-minute 20-second delay, immediate visibility,
exhausted retries, and job timeout sizing.
- Load the access router in test setup so its cold transform does not
consume the first permission test's 10-second timeout. The permission
assertions are unchanged.

## Verification

- `node --test scripts/release-lib.test.mjs`: 14 passed.
- `pnpm run test:release-registry`: 129 passed.
- `pnpm exec vitest run
server/src/__tests__/access-routes-permissions-upgrade.test.ts`: 3
passed.
- Regression proof in temporary fixtures: restoring 60 attempts fails
the observed-delay test; restoring 90-minute jobs fails the
timeout-budget test.
- [CI run
34916632804](https://github.com/paperclipai/paperclip/actions/runs/34916632804):
all jobs passed, including typecheck/release registry, build, all
general and serialized server shards, browser tests, runner
verification, and canary dry run. The PR has 31 successful checks and
two expected Storybook skips at `a27f5e896`.
- [Previously failing serialized
shard](https://github.com/paperclipai/paperclip/actions/runs/34916632804/job/104215809616):
all three access-route permission tests passed in CI after preloading
the router.
- Greptile's final review is 5/5 with no outstanding findings. Both
review threads are resolved.
- Local limits: `pnpm -r typecheck` and `pnpm build` stop at the runner
package because this machine has no Rust `cargo` executable. The
duplicate full local `pnpm test:run` was interrupted while the complete
CI matrix ran. Targeted local results are listed above; full validation
is from CI.

The previous CI failures were unrelated to npm propagation:

- [PR
review](https://github.com/paperclipai/paperclip/actions/runs/34891770396)
required a test file for this fix.
- [Serialized server shard
3](https://github.com/paperclipai/paperclip/actions/runs/34891773736/job/104136392196)
timed out in the first access-route permission test at 10 seconds. The
other two tests in that file passed.
- The canary dry run passed in that same CI run.

## Risks

Low risk. Production behavior changes only in release waiting budgets.

- Polling exits as soon as npm exposes the version, so healthy publishes
do not wait longer.
- An unavailable version now takes about 30 minutes to report. Polls
remain bounded and still fail the release on exhaustion.
- The 150-minute jobs leave roughly 30 minutes for setup/build plus four
full polling windows. npm command runtime and later release steps also
consume that budget; a broader outage can still interrupt a batch.
- The permission-test change moves module loading into a bounded setup
hook; it does not relax authorization assertions.
- No schema changes or operational migrations.

## Model Used

- Claude Fable 5 (`claude-fable-5`), 1M context, extended thinking, run
through Claude Code with tool use and code execution.

- OpenAI GPT-6 (Codex), with reasoning, tool use, and code execution,
for the CI follow-up. Context-window size is not exposed in this
session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass — targeted checks listed
above; full validation passed in CI
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes —
workflow comments and verification details
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-14 20:16:29 -07:00
DottaandPaperclip a34c615cc1 fix(release): skip lifecycle scripts for bundle staging (#12585)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The release system builds the workspace before it prepares npm
packages.
> - Bundled packages then move the built files and runtime dependencies
into a standalone staging directory.
> - npm pack and npm publish still run package lifecycle scripts in that
directory.
> - The server `prepack` script requires the source workspace and cannot
run from the standalone directory.
> - This pull request disables lifecycle scripts only for npm operations
on prepared bundled packages.
> - The benefit is that release packaging uses the artifacts that the
release already built.

## Linked Issues or Issue Description

Refs #12584

**What happened?**

The canary dry run passed bundled dependency installation and then
failed while it packed `@paperclipai/server`. npm ran the server
`prepack` script in the standalone staging directory. That script called
`pnpm run prepare:ui-dist && pnpm run build`, which requires files from
the source workspace. See the [failed canary dry-run
job](https://github.com/paperclipai/paperclip/actions/runs/33399041712/job/99510762364).

**Expected behavior**

Bundled package packing and publishing must use the artifacts that the
release already built. They must not run workspace-only package
lifecycle scripts from the standalone staging directory.

**Steps to reproduce**

1. Build the Paperclip workspace.
2. Prepare the bundled server package in a temporary directory.
3. Run npm pack from that directory.
4. Observe that npm runs the server `prepack` script outside the source
workspace.

**Paperclip version or commit**

`08af15bd7629790a618e8787c11490c96a1b619a`

## What Changed

- Add `--ignore-scripts` to npm pack for prepared bundled packages.
- Add `--ignore-scripts` to both normal and no-provenance npm publish
attempts for prepared bundled packages.
- Update release helper tests to require this behavior.

## Verification

- `node --test scripts/acpx-patch-packaging.test.mjs
scripts/release-lib.test.mjs` (22 passed)
- `pnpm test:release-registry` (98 passed)
- `git diff --check`
- The full test suite and build were not run locally. GitHub runs the
canary dry run and full matrix.

## Risks

- Low risk. The flag applies only to bundled packages that the release
prepares after the workspace build.
- Normal pnpm package publishing is unchanged.
- Package lifecycle scripts remain in the published manifest.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex with `gpt-5.6-sol`. The model used agentic reasoning,
tool use, and code execution. The context window size is not exposed in
this environment.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-31 09:14:08 -05:00
fc5a30805e feat(cli): add managed install, update, and service lifecycle (#10045)
## Thinking Path

> - Paperclip is the open source control plane people use to manage
AI-agent companies
> - Operators need a predictable installation path that survives beyond
an ephemeral `npx` process
> - A durable installation needs an owned per-user payload store, stable
command shim, safe shell integration, and supported service lifecycle
> - Updates must preserve recoverability by backing up data, installing
side-by-side, verifying the new payload, and retaining rollback state
> - Bootstrap scripts and privileged service operations must fail closed
across download, filesystem, ownership, and consent boundaries
> - This pull request integrates managed install, update, rollback,
service, uninstall, doctor, bootstrap-installer, and runtime-serving
support into one workflow
> - The benefit is a recoverable, inspectable, and documented
installation lifecycle with explicit safety boundaries across Linux,
macOS, containers, WSL, npm, npx, and source checkouts

## Linked Issues or Issue Description

### Problem

Paperclip lacks a first-class durable installation and lifecycle
workflow. Operators currently have to assemble npm/npx installation,
PATH setup, background-service management, updates, rollback,
diagnostics, and uninstall behavior themselves. That makes upgrades
harder to recover, creates inconsistent behavior across platforms, and
leaves shell/download/service trust boundaries without one documented
implementation.

### Proposed Solution

Add a managed per-user install store and stable shim, a verified shell
bootstrap installer, service lifecycle commands, install-mode-aware
update/rollback behavior, doctor checks, and documentation. Managed
updates back up the database, install and smoke-test a side-by-side
payload, atomically switch `current`, and retain prior payloads. The
shell installer pins registry/download trust boundaries and requires
explicit consent for non-interactive privileged actions.

### Alternatives Considered

- Keep recommending `npx`: simple for evaluation, but ephemeral and
unsuitable for stable services, atomic updates, or rollback.
- Require global npm installation only: familiar, but cannot provide the
owned side-by-side payload store and retained rollback semantics.
- Split the capability across multiple PRs: rejected because install,
update, service, uninstall, bootstrap, and serving behavior share
contracts and security boundaries that need review together.

### Related Pull Requests

- Supersedes #10042 and #10044 with one integrated final diff.
- Incorporates and replaces the closed preparatory work in #10032 and
#10034.

## What Changed

- Added `paperclipai install`, `update`/`upgrade`, rollback, uninstall,
service lifecycle, onboarding integration, and managed-install doctor
checks.
- Added a private managed payload store, verified manifest/marker
ownership, exclusive mutation locks, atomic manifest/current/shim
writes, retained previous payloads, and provenance validation.
- Added npm and GitHub-ref install sources with exact target resolution,
registry isolation, database backup, side-by-side verification, atomic
activation, service restart coordination, and failure rollback.
- Made managed-update backups report actionable service-start and
`--no-backup` recovery guidance for unreachable databases, while clean
never-onboarded instances skip an empty backup.
- Added systemd user and launchd service definitions, status/health/log
commands, single-instance coordination, stale-port recovery, and
explicit sudo/lingering consent handling.
- Added the `scripts/install.sh` bootstrap path with checked two-stage
downloads, pinned public npm registry usage, platform checks,
dry-run/non-interactive controls, and Docker fixtures.
- Added embedded Postgres/native bootstrap integration,
hot-restart/systemd-notify serving support, passive update notices,
configuration contracts, README/CLI/install documentation, and focused
regression tests.
- Security re-review should explicitly re-verify: (1)
`addManagedPathBlock`/`removeManagedPathBlock` reject symlinked or
non-regular rc files, assert current-user ownership, preserve
restrictive modes, and replace atomically; (2) managed shim replacement
rejects unsafe parents, foreign-owned or multiply linked files, and uses
checked atomic replacement; (3) the shell installer and sudo path
preserve explicit consent and checked downloads; and (4) installed
service/runtime serving remains bound to the validated managed shim and
instance configuration.

## Verification

- `bash -n scripts/install.sh scripts/clean-install-git.sh
scripts/clean-install-npm.sh scripts/test-install-sh-docker.sh`
- `pnpm exec vitest run cli/src/__tests__/install-store.test.ts
cli/src/__tests__/install-command.test.ts
cli/src/__tests__/managed-install-check.test.ts
cli/src/__tests__/onboard-service.test.ts
cli/src/__tests__/service-health-check.test.ts
cli/src/__tests__/service-manager.test.ts
cli/src/__tests__/update-command.test.ts
cli/src/__tests__/update-notice.test.ts
packages/db/src/embedded-postgres-native.test.ts` — 9 files, 66 tests
passed
- `pnpm --dir cli typecheck`
- `pnpm --dir cli build`
- Follow-up verification: `pnpm exec vitest run
cli/src/__tests__/update-command.test.ts` (14/14), `pnpm --dir cli
typecheck`, `pnpm --dir cli build`, and `pnpm --filter
@paperclipai/server typecheck`.
- `pnpm -r typecheck`
- `pnpm build`
- Full `pnpm test:run` exercised all suites; an injected static AWS
credential changed one unrelated doctor expectation, which passed when
those credentials were removed. A second run cleared that case and
exposed stale pre-existing adapter-utils `dist` output; rebuilding
`@paperclipai/adapter-utils` made the isolated test pass. The updated PR
CI is the authoritative clean-workspace full-suite run.

## Risks

- Installer/update code writes executable shims, symlinks, shell rc
blocks, service definitions, and managed payloads; ownership,
regular-file, symlink, hard-link, marker, and path-containment checks
fail closed before destructive changes.
- The bootstrap installer executes downloaded tooling; downloads are
staged and checked before execution, npm traffic is pinned to the public
registry, and non-interactive privileged behavior requires explicit
consent.
- Linux lingering may invoke `sudo`; the command is surfaced and
confirmed before execution, and unsupported service managers fall back
to foreground-run guidance.
- Database migrations remain forward-only; payload rollback does not
reverse migrations, so managed updates create a backup before activation
unless explicitly disabled.
- Service restart and runtime serving touch process/port ownership;
lifecycle locks, health/version checks, and stable-shim service
definitions reduce split-brain and stale-process risk.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex coding agents using GPT-5.5 and GPT-5.6-sol, with
reasoning, repository/API access, shell execution, and test tooling. The
runtime did not expose a reliable context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 18:52:23 -07:00
DottaandPaperclip 204c416478 fix(release): publish bundled packages with trusted npm staging (#10047)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip publishes its CLI, server, adapters, and shared packages
through automated canary and stable release workflows.
> - `@paperclipai/adapter-utils` bundles the patched `acpx` runtime, so
it must use npm 11 for OIDC trusted publishing.
> - The prior staging directory contained pnpm's `.pnpm` symlink forest,
which crashes npm 11's directory-pack step on GitHub runners and
produces a consumer-broken bundled dependency tree.
> - This pull request rebuilds staged production dependencies as a
physical npm tree, reapplies repository patches, and publishes that
clean directory directly with npm 11 trusted publishing.
> - The benefit is a release path that retains GitHub Actions OIDC
trusted publishing while shipping a working patched acpx runtime to
consumers.

## Linked Issues or Issue Description

Refs: #9980, #10030, #10041

No public GitHub issue exists for this release failure.

### What happened?

Canary and stable publishing began routing `@paperclipai/adapter-utils`
through npm after it declared `bundleDependencies: ["acpx"]`. Publishing
the pnpm-deployed directory with npm 11 crashes during npm's
directory-pack phase on GitHub runners with `Exit handler never
called!`. The same staged shape also produces a broken consumer artifact
because acpx cannot resolve transitive runtime dependencies after
installation.

### Expected behavior

Bundled packages publish directly from a self-contained staging
directory through npm 11 OIDC trusted publishing, and consumers receive
a working patched acpx runtime with its transitive dependencies.

### Steps to reproduce

1. Stage `packages/adapter-utils` using the old `pnpm deploy`-only
shape.
2. Publish that directory with npm 11 on a GitHub runner.
3. npm crashes before registry/OIDC activity while walking the `.pnpm`
symlink forest.
4. Install an artifact packed from that old shape into a fresh npm
project and run acpx; its runtime dependency resolution fails.

### Deployment mode

GitHub Actions canary/stable release workflow.

### Relevant logs or output

```text
npm error Exit handler never called!
```

## What Changed

- After `pnpm deploy`, remove the staged pnpm `node_modules` tree and
run `npm install --omit=dev --ignore-scripts --no-audit --no-fund` to
create a physical hoisted production tree.
- Apply every root `pnpm.patchedDependencies` patch whose package is
declared in the staged package's bundled dependencies, failing staging
if any patch cannot apply.
- Assert the staged acpx runtime contains the required `onAgentStderr`
patch marker.
- Publish the clean staging directory directly with pinned npm 11.18.0,
retaining GitHub Actions OIDC trusted publishing, verbose diagnostics,
and the duplicate-transparency-log retry without provenance.
- Keep pinned npm 10.9.7 packing only for local/dry-run payload
verification; registry publishing does not use a tarball argument.
- Add focused coverage for npm-tree staging, patch application, direct
directory publish arguments, and bundled tlog retries.

## Verification

- `bash -n scripts/release-lib.sh scripts/release.sh`
- `node --test scripts/release-lib.test.mjs
scripts/acpx-patch-packaging.test.mjs` — 12/12 passed.
- `pnpm test:release-registry` — 68/68 passed.
- Real staging smoke: `node scripts/prepare-bundled-package.mjs
packages/adapter-utils <stage>` produced a real `node_modules/acpx`
directory, no `.pnpm` directory, and the `onAgentStderr` patch marker.
- Real npm 11 directory-publish smoke: `npx --yes npm@11.18.0 publish
--dry-run --tag canary --access public --loglevel verbose` packed 26
bundled dependencies and reached the expected existing-version registry
rejection without `Exit handler never called!`.
- The merge-triggered `publish_canary` workflow remains the live OIDC
trusted-publishing verification.

## Risks

- The live GitHub Actions trusted-publishing path can only be fully
proven by the merge-triggered canary run; npm debug-log upload remains
available if it fails.
- Bundling acpx continues to freeze platform-specific transitive
artifacts such as esbuild binaries from the Linux release runner. This
is a pre-existing consequence of the bundling decision in #9980 and is
not expanded here.
- Rebuilding dependencies with npm depends on the exact bundled
dependency versions in the staged manifest; staging fails hard if
repository patches no longer apply.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.6-sol`, high reasoning mode, with
repository tool use and code execution. The harness did not expose a
model context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-22 17:01:11 -05:00
DottaandPaperclip 4e8cd757eb fix(release): add npm publish crash diagnostics (#10041)
## Thinking Path

> - Paperclip publishes a coordinated set of packages through its
release workflows
> - Bundled packages use a pinned npm CLI so trusted publishing works
consistently
> - The canary publisher now crashes deterministically inside npm before
useful output reaches the workflow log
> - The npm debug log that contains the underlying failure disappears
with the hosted runner
> - This pull request upgrades the pinned publish CLI and preserves both
verbose HTTP activity and npm debug logs on failure
> - The benefit is that the plausible HTTP-layer fix ships immediately,
while any remaining CI-only failure becomes diagnosable

## Linked Issues or Issue Description

- **Problem:** The canary release workflow fails on the first bundled
package with `npm error Exit handler never called!` and no preceding
diagnostic output.
- **Expected behavior:** Bundled packages publish through trusted
publishing, or the workflow retains enough npm diagnostics to identify
the actual failure.
- **Reproduction:** Run the canary release workflow in GitHub Actions;
the failure reproduced on both attempts of run 29948506814.
- **Version/commit:** Current `master` after #10024 and #10030.
- **Deployment mode:** GitHub-hosted release workflow using Node.js 24
and npm trusted publishing.
- Related: #10024, #10030.

## What Changed

- Bumped the bundled publish CLI from npm 11.16.0 to npm 11.18.0.
- Added `--loglevel verbose` to bundled npm publish invocations.
- Dumped the last 300 lines of every npm debug log after failed canary
or stable publishes, with common registry credential forms redacted.
- Updated release assertions to pin npm 11.18.0 and verify verbose
logging.

## Verification

- `pnpm test:release-registry` — 66 tests passed.
- `bash -n scripts/release-lib.sh`.
- Parsed `.github/workflows/release.yml` with Python/PyYAML.
- Smoke-tested npm log redaction with representative Authorization,
`_authToken`, and token environment values.
- Smoke-tested npm debug-log redaction against Authorization,
`_authToken`, and `npm_token` examples.
- `git diff --check origin/master...HEAD`.
- The merge-triggered canary workflow remains the live
trusted-publishing verification.

## Risks

- Low code risk: changes are isolated to the release publisher and its
workflow diagnostics.
- npm 11.18.0 could expose a different registry/runtime regression;
failure-time debug log dumping makes that actionable.
- Verbose npm output increases release log volume but does not change
package contents or dist-tags; common credential forms are redacted
before debug logs are printed.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, GPT-5.3 Codex, tool-enabled coding agent with repository
and shell execution; context window size is not exposed in this
environment.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-22 14:48:54 -05:00
DottaandPaperclip 47c38777d8 fix(release): use trusted publishing npm for bundled packages (#10030)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip publishes canary and stable packages through a shared
release script
> - GitHub Actions authenticates those publishes through npm trusted
publishing and an OIDC identity token
> - Bundled-dependency packages recently moved from pnpm publish to a
pinned npm CLI to preserve their bundled files
> - That pin selected npm 10, which cannot use trusted publishing, so
the first bundled package failed with `ENEEDAUTH`
> - This pull request keeps bundled-package packing on npm 10 while
routing actual publishing through the trusted-publishing-capable npm 11
version
> - The benefit is bundled packages keep their required npm packaging
behavior while canary and stable releases authenticate successfully

## Linked Issues or Issue Description

**What happened**

The canary release job failed while publishing
`@paperclipai/adapter-utils` with `ENEEDAUTH`. The package has bundled
dependencies, so the release helper selected pinned `npm@10.9.7`; the
workflow provides OIDC trusted publishing rather than an npm token, and
npm 10 cannot use that authentication path. Because this is the first
package attempted, the release exited before trying the remaining
packages.

**Expected behavior**

Bundled-dependency packages should publish with an npm CLI that both
preserves bundled dependencies and supports GitHub Actions trusted
publishing.

**Steps to reproduce**

Run the canary release workflow from master after PR #9980. The
`publish_canary` job reaches `@paperclipai/adapter-utils`, invokes `npx
npm@10.9.7 publish`, and fails with `ENEEDAUTH`.

**Deployment mode**

GitHub Actions canary and stable npm release workflows.

Refs #9980.

## What Changed

- Kept bundled-package dry-run packing on npm `10.9.7`, which
successfully produces the staged tarball.
- Routed bundled-package publishing through npm `11.16.0`, which
supports GitHub Actions trusted publishing.
- Split the pack and publish helpers so future npm changes cannot
silently couple the two compatibility requirements.
- Updated focused release and ACPX packaging tests to enforce both
versions and call paths.

## Verification

- `pnpm test:release-registry` — 67 passed locally.
- Initial all-npm-11 PR head: Canary Dry Run reproduced an npm-internal
crash during bundled `pack`.
- Current head `5b3961ed13dd26ed2d6b1096ea23fd91b32e4353`: Canary Dry
Run passed with split npm pack/publish helpers.
- All PR checks passed, including build, typecheck + release registry,
server/workspace suites, both e2e shards, security gates, and Greptile.
- Greptile reviewed the current head at 5/5 confidence with no blocking
issues.

## Risks

- Low risk: the change only separates the npm CLI used for
bundled-package packing from the CLI used for publishing.
- The versions remain explicitly pinned because npm 11.16.0 currently
crashes on the bundled pack payload, while npm 10.9.7 cannot perform
trusted publishing.
- Focused tests assert both pins and both helper call paths, and the
full Canary Dry Run passes on the current head.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.6-sol`, high reasoning mode, with
repository, shell, GitHub CLI, and code-execution tools.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-22 13:19:15 -05:00
DottaandPaperclip d31a28828b fix(acpx): support Windows agent spawning (#9980)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Local Claude, Codex, Gemini, and custom ACP adapters run through the
shared embedded ACPX engine
> - That engine wrapped every local agent command in a generated Bash
script to inject environment variables and filter child stderr
> - Windows cannot directly spawn that Bash wrapper, and npm/pnpm ACP
binaries are exposed through `.cmd` shims there
> - ACPX 0.12 already supports per-session child environment variables,
so the wrapper is unnecessary
> - This pull request registers agent commands directly, injects env
through ACPX session options, captures child stderr in-process, and adds
a real Node ACP spawn smoke on Ubuntu and Windows
> - The benefit is one cross-platform spawn path with a reusable smoke
test instead of parallel shell-wrapper implementations

## Linked Issues or Issue Description

Fixes #9941.
Refs #9428 and #9771.

**What happened**

ACPX-backed local agents failed to start on Windows because Paperclip
registered a generated POSIX `.sh` wrapper as the agent command. Windows
also needs the `.cmd` npm/pnpm shim when resolving built-in ACP
binaries, and symlink creation can fail with `EPERM` for seeded
auth/skill files.

**Expected behavior**

The same ACPX engine path should spawn a real ACP agent on Windows and
Linux, forward Paperclip/runtime env without mutating `process.env`,
preserve filtered/unfiltered child stderr behavior, and fall back to
copies where Windows symlinks are unavailable.

**Steps to reproduce**

Run a local ACPX adapter on Windows with the prior wrapper path. ACPX
attempts to spawn the generated `.sh` file and the agent never
initializes.

**Deployment mode**

Local Paperclip adapters using
`packages/adapter-utils/src/acpx-engine/`.

## What Changed

- Removed generated Bash agent/env wrappers and registered local
commands directly with ACPX.
- Passed the resolved child environment through ACPX
`sessionOptions.env`, including resume retry paths.
- Added a minimal `acpx@0.12.0` package patch exposing child stderr
callbacks and allowing documented uppercase env-map keys in persisted
session options.
- Moved stderr tee/filter behavior in-process: raw stderr remains in the
per-run file while benign `nes/close` noise is omitted from live stderr.
- Preferred `.cmd` ancestor binaries on Windows and added `EPERM` copy
fallbacks for Codex auth seeding and Gemini skill materialization.
- Added a real Node ACP echo-agent spawn smoke that can run directly on
any supported platform.

## Verification

- `pnpm exec vitest run
packages/adapter-utils/src/acpx-engine/execute.test.ts
packages/adapter-utils/src/acpx-engine/spawn-smoke.test.ts` — 57 passed.
- `pnpm --filter @paperclipai/adapter-utils typecheck` — passed.
- `node --test scripts/acpx-patch-packaging.test.mjs
scripts/release-lib.test.mjs` — 10 passed.
- Full canary release dry run under Node 24.18.0 / npm 11.16.0 — passed
in an isolated scratch clone.
- `git diff --check` — passed during implementation verification.
- One-time GitHub Actions proof: [Ubuntu ACPX spawn
smoke](https://github.com/paperclipai/paperclip/actions/runs/29924348927/job/88937774579),
[Windows ACPX spawn
smoke](https://github.com/paperclipai/paperclip/actions/runs/29924348927/job/88937774558),
and [Canary Dry
Run](https://github.com/paperclipai/paperclip/actions/runs/29924348927/job/88937774497)
passed on head `f345ac69f2`; the dedicated smoke jobs are intentionally
not retained in the recurring PR workflow.

## Risks

- The ACPX stderr callback and env persistence exemption are carried as
a pnpm dependency patch until ACPX exposes/fixes those behaviors
upstream.
- Child stderr is synchronously appended to preserve ordering and
failure diagnostics; unusually high-volume agent stderr could briefly
block the Node event loop.
- The Windows-specific `.cmd` resolution and symlink `EPERM` branches
are proven by the standalone smoke test and the linked one-time
`windows-latest` run rather than a permanent CI gate.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI GPT-5.4 via Codex CLI, medium reasoning, repository/tool
execution enabled; context-window size is not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-22 10:22:29 -05:00
Devin FoleyandClaude e68ee09809 perf(release): batch npm registry version queries (#9202)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The release subsystem publishes the public workspace packages and
also powers release-related CI validation.
> - The release flow currently asks npm for package versions one package
at a time in multiple places.
> - That serial registry latency slows the PR Canary Dry Run path and
real release invocations even though the checks are independent.
> - This pull request batches npm registry version lookups with bounded
concurrency and reuses the result for version calculation.
> - The benefit is shorter non-build release-script time while
preserving the fresh target-version existence check before publishing.

## Linked Issues or Issue Description

- No public GitHub issue exists for this release-script performance
cleanup.

### Problem or motivation

Release validation spends avoidable time on repeated serial `npm view`
calls across the public package set. The slow path affects PR release
validation and real release invocations because version discovery waits
on independent registry reads one at a time.

### Proposed solution

Fetch package version maps concurrently with bounded parallelism, reuse
that map for stable/canary version calculation, and keep a fresh
parallel absence check for the target publish version.

### Alternatives considered

Keeping the existing serial shell loop is simpler, but it preserves the
CI latency cost. Caching the final target-version existence check was
rejected because release publish safety should still query npm freshly
before publishing.

### Roadmap alignment

This is a small release-tooling performance improvement. It does not
duplicate any planned core product work found in `ROADMAP.md`.

## What Changed

- Added `scripts/release-registry-versions.mjs` to fetch npm package
version maps and assert target-version absence with bounded parallelism.
- Updated `scripts/release.sh` to prefetch package versions once and to
batch the final target-version absence check.
- Updated `next_stable_version` and `next_canary_version` to use the
prefetched version map when present, with the existing per-package npm
fallback preserved.
- Added release-registry helper coverage and included it in `pnpm run
test:release-registry`.
- Hardened the release publish helper tests so their fake `pnpm`/`npm`
fixture PATH is preserved under non-login shell execution.

## Verification

- `node --test scripts/release-registry-versions.test.mjs`
- `pnpm run test:release-registry`
- `bash -n scripts/release.sh scripts/release-lib.sh`
- `git diff --check`
- Safety scan before push: searched changed files for common
key/token/password patterns and PII markers; only benign script-name
text matched (`secrets:migrate-inline-env`).
- Remote PR checks on the latest head passed, including `Typecheck +
Release Registry`, `Canary Dry Run`, build, tests, e2e, policy, security
scans, and commitperclip review.
- Greptile reviewed the latest head with Confidence Score 5/5 and no
blocking issues.

## Risks

- Low risk. The release version helpers keep their original npm fallback
when no prefetched version map is supplied.
- The existence check remains fresh and uncached before publish, but now
reports all matching package/version pairs from a parallel check.
- If npm has transient failures during the prefetch step, missing or
failed packages still map to an empty version list, matching the old
helper behavior.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex coding agent using GPT-5, with shell/tool execution in
the local repository.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Claude <noreply@paperclip.ing>
2026-07-08 08:04:39 -07:00
DottaandPaperclip ce7b49e4f1 [codex] Recover duplicate npm provenance canary publishes (#7839)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The release workflow publishes canary npm packages on every push to
`master`
> - The failing canary job built successfully and published several
packages before npm failed on `@paperclipai/mcp-server`
> - The concrete failure was npm trusted-publishing provenance returning
`TLOG_CREATE_ENTRY_ERROR` because an equivalent Sigstore
transparency-log entry already existed
> - The package version was not visible on npm afterward, so the release
script could not safely treat that error as success by itself
> - This pull request adds a narrow recovery path for that npm
provenance failure and keeps the existing registry verification as the
final source of truth
> - The benefit is that transient duplicate transparency-log failures do
not break canary publication when a package can be republished without
provenance or is already visible on npm

## Linked Issues or Issue Description

Bug fix, no public GitHub issue found in duplicate search.

- What happened: the Release workflow canary publish failed in
`publish_canary` after npm returned `TLOG_CREATE_ENTRY_ERROR` while
publishing `@paperclipai/mcp-server@2026.609.0-canary.2`.
- Expected behavior: canary publishing should either recover from npm's
duplicate transparency-log failure when the package can still be
published, or fail later in registry verification if the package never
appears.
- Steps to reproduce: inspect
https://github.com/paperclipai/paperclip/actions/runs/27230012891/job/80411422155
from push `05cb18cf28074a6d1074c7575c5a44133146e368`.
- Deployment mode: GitHub Actions Release workflow, npm trusted
publishing.
- Duplicate search: no open PRs or issues found for `canary publish TLOG
provenance release` or the failing run/job IDs.

## What Changed

- Added `publish_package_to_npm` in `scripts/release-lib.sh` to wrap
canary/stable package publishing.
- Detects npm's duplicate Sigstore transparency-log error and checks
whether the package version is already visible on npm.
- Retries that exact package once with `--provenance=false` when npm hit
the duplicate tlog error but the version is not visible yet.
- Keeps unrelated publish failures as hard failures.
- Added shell-helper tests with fake `pnpm` and `npm` commands, and
included them in `pnpm test:release-registry`.

## Verification

- `node --test scripts/release-lib.test.mjs`
- `pnpm test:release-registry`
- Confirmed `pnpm publish --dry-run --no-git-checks --tag canary
--access public --provenance=false` is accepted by pnpm 9.15.4.

## Risks

- Low risk: the recovery only triggers when npm output contains both
`TLOG_CREATE_ENTRY_ERROR` and the duplicate transparency-log message.
- Publishing without provenance is a fallback for canary continuity; if
npm still does not expose the package, the existing registry
verification step still fails the release.
- The same helper is used by stable publishing too, but only for this
exact npm provenance failure path.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

This is a release reliability bug fix. I checked `ROADMAP.md`; it does
not duplicate planned core product work.

## Model Used

OpenAI Codex coding agent, GPT-5-class model, tool-enabled local shell
and GitHub CLI workflow, medium reasoning mode.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-06-09 15:35:07 -05:00