Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
286 changes: 286 additions & 0 deletions .github/workflows/release-recovery.yml

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,12 @@ Reconcile exact assets and obtain owner disposition before changing an existing
release. Preserve failed runs, tags and artifact bytes. A later npm dist-tag or
GitHub Latest change needs authoritative readback, not a rebuild.

The protected finalization-only recovery workflow runs from reviewed `main` and
separately verifies the original tag, qualified candidate and successful npm
publish step. It cannot publish npm or overwrite an existing GitHub Release.
Retain the original failed workflow as evidence and bind the recovery source
separately. Follow the narrower recovery procedure in `docs/release.md`.

## Engineering rules

- Node.js 24.20.0, TypeScript, ESM, strict types, and exact dependency pins.
Expand Down
44 changes: 38 additions & 6 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,15 @@ It does not rebuild or repack the local candidate. Bounded read-only retries
wait for npm's exact version, integrity, provenance metadata and `latest` tag,
then package installation and signature verification. A conflicting immutable
version or integrity fails immediately; publication itself is never retried. The
job downloads and requalifies the registry artifact, creates a plainly labelled
draft public-alpha release with the same tarball/checksum/SBOM/evidence, and
verifies the downloaded GitHub asset. It uploads draft evidence before
publishing the normal GitHub Release with `--latest`. Fresh npm and GitHub
Latest readbacks then supply the final evidence, which is uploaded last.
metadata reader allows twenty attempts thirty seconds apart, with a separate
sixty-second limit per request. The v0.7.1 publication exposed a propagation
delay beyond the previous twelve-attempt, ten-second interval. The wider budget
changes only reads; it grants no retry of publication. The job downloads and
requalifies the registry artifact, creates a plainly labelled draft public-alpha
release with the same tarball/checksum/SBOM/evidence, and verifies the
downloaded GitHub asset. It uploads draft evidence before publishing the normal
GitHub Release with `--latest`. Fresh npm and GitHub Latest readbacks then
supply the final evidence, which is uploaded last.

### 5. Close the release

Expand Down Expand Up @@ -299,6 +303,29 @@ architecture follow-through canary evidence.

## Withdrawal

### Recover publication before GitHub Release creation

If npm publication succeeded but metadata readback exhausted its budget, do not
rerun the publish job. The protected `release-recovery.yml` workflow can finish
the narrower case where the original publish step succeeded, the candidate and
trusted-verifier artifacts remain available, and no GitHub Release exists for
the tag. Dispatch the reviewed recovery workflow from `main` with the exact tag,
candidate run ID and original publish run ID.

Recovery verifies those identities and the existing npm version, signatures and
provenance, then runs the registry artifact's full canary before creating a
draft. Final evidence retains the original publish run. A separate recovery
record identifies the recovery workflow and its source commit; a green recovery
does not rewrite the original failed run. Any existing release, ambiguous
creation result, missing artifact or identity conflict blocks this route.

The v0.7.1 incident used candidate `35466952501` and original publish
`35467443471`. Its successful immutable publish step preceded metadata
propagation; no release had been created. Its tag and npm bytes remain
unchanged.

### Other interrupted or unsafe releases

First classify an interrupted publication from provider readback; do not rerun
the publish workflow. If npm and registry qualification succeeded but GitHub
finalization is incomplete, inventory all release records for the tag by numeric
Expand All @@ -316,7 +343,12 @@ If prepublication qualification fails, do not publish. Delete an unpushed local
tag, fix through a new reviewed PR, and restart with a new exact candidate. If a
remote tag exists, retain it as evidence and use a new version.

If publication succeeded but readback or postpublication qualification fails:
If provider readback is unavailable, stop further effects and reconcile it. A
verified existing publication with no GitHub Release may use the recovery route
above. A timeout alone is not proof that the package is unsafe.

If readback proves an artifact or identity mismatch, or the published artifact
fails qualification:

1. stop the workflow before making a public support claim;
2. deprecate the exact npm version with a concise safety message;
Expand Down
19 changes: 19 additions & 0 deletions product/admission-evidence-hardening.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,22 @@ No new support tuple, customer operation, downstream product implementation,
daemon, parallel runtime writer, deployment, credential sharing or review bypass
is authorized. Product readiness remains conditional on external evidence and
owner decisions; software tests cannot close those gates.

## Observed publication recovery

On 2026-09-19, candidate run `35466952501` passed all four release gates for tag
`v0.7.1`, commit `50873b47574e9a46ca009c514186532332f385eb`. Publish run
`35467443471` completed the immutable npm publication, then exhausted its twelve
metadata reads before npm exposed the version. Subsequent registry readback
confirmed the exact artifact integrity, provenance and `latest` pointer. No
GitHub Release was created by that run.

The owner's end-to-end repair and release instruction includes completing this
known publication and fixing the observed recovery gap. Extend the bounded read
window and add a protected, finalization-only workflow. It must prove the
original successful publish step and qualified artifact, verify the existing
registry version, and preserve the original publish run in release evidence.
Record the recovery workflow's separate source identity. The first recovery
route requires the GitHub tag's release to be absent; an existing or ambiguous
release blocks it. Never repeat publication, replace artifacts, move the tag,
invent a successful original run, or bypass the protected environment reviewer.
Loading