release-verification · git:20260829.ef3a006 · 2026-08-29 · sha256 aa9035217b33de16

release-verification git:20260829.ef3a006A

Immutable. This exact content is served forever at /api/v1/blob/aa9035217b33de16.

---
name: release-verification
description: 发布验证规范 — 覆盖版本、changelog、测试、pack、install smoke、commit/tag/push/publish 前确认与发布后 registry/tag 验收
---
# Release Verification Skill

## 职责

当用户明确要求 release / tag / publish / 版本发布时,执行发布前后验证链。它只做验证和确认边界,不自动执行真实发布动作。

## 触发条件

| 场景 | 是否触发 |
|------|:--------:|
| 用户明确要求 `release` / `publish` / `tag` | 🔴 必须 |
| 修改 package/plugin/version/changelog 口径 | 🟡 条件 |
| 普通未发布实现批次 | N/A,默认写 `changelogs/unreleased.md` |

## R0~R7 验证链

| 阶段 | 检查 |
|------|------|
| R0 | 确认目标版本、SemVer、tag 和 registry 唯一性;执行 `ReleaseAuthorityBeforeCompatibilityGate`,冻结 publishedState、consumerEvidence、authoritySources 与兼容决策 |
| R1 | 将 `changelogs/unreleased.md` 归档到 `changelogs/releases/vX.Y.Z.md`,并更新根 `CHANGELOG.md` |
| R2 | 同步 `package.json`、`package-lock.json`、`plugin.json`、Profile/README/website 版本口径;发布型 Profile 必须补齐 CI workflow/job 矩阵、tag/publish 触发链、失败恢复路径、外部消费者验证矩阵、dist 产物边界、registry/tag 验收与常见故障诊断;用户可交互发布面追加 `InteractiveSemanticProbe` |
| R2a | 执行 `CandidateFreezeGate`:冻结 candidate identity/generation、授权 scope、允许进入当前 release 的 mutation class 与 evidence dependency graph;冻结后新发现的非 P0/P1、非发布阻断治理项进入下一版本 |
| R3 | 执行 `npm test`(默认全链)|
| R3a | 执行 `CandidateDiffCompletenessGate`:先清点 tracked/untracked/ignored 边界,再使用临时 `GIT_INDEX_FILE` 物化本次授权范围,禁止改写用户真实 index;对隔离 snapshot 执行 `git diff --cached --check`、`git diff --cached --name-status`、项目策略要求的 secret-shape scan 和 intended scope 对账;最后验证用户 index digest 与 staged set 前后不变。普通 `git diff --check` 不能替代本门禁 |
| R3b | 执行 `npm run test:audit`,并完成 package completeness gate(`description`、`keywords`、`repository`、`homepage`、`bugs`、`license`、`files/exports/bin`、`publishConfig`、`engines`、`plugin.json` 元数据);包边界检查必须在构建/benchmark/codegen 完成后单独串行执行;公开打包脚本必须执行 `PackagedScriptDependencyClosureGate`,递归核对本地 `require()`、`path.join(ROOT,'scripts',...)` 或等价运行时脚本依赖都进入 tarball |
| R3c | 执行 `RemoteCIParityPushGate`:push / tag / release / publish 前先执行与远端 CI 同构的本地门禁;若项目存在远端 CI(如 GitHub Actions),确认目标 commit 对应 CI run 已完成且 conclusion 为 `success`;若存在独立消费者仓,再执行 `ConsumerValidationEngineeringGate`,证明 source event→consumer run、目标 SHA、身份新鲜度和全部适用分母 accepted;无远端 CI/消费者或无权限查询时必须写 `N/A + skipReason`,不得把普通测试通过替代 coverage、audit、examples、website、pack 或矩阵脚本 |
| R3e | Skill portfolio / V92:`generate-skill-portfolio --check` 必须在**与 CI 同语义**下通过——consumer 扫描仅用 **git-tracked** 文件;禁止在含 untracked 杂项的脏树按「全盘 walk」生成并提交 `skills/portfolio.json`;push 前建议 `git worktree add --detach` 于目标 SHA 复跑 `--check` |
| R3d | 执行 `ReleaseCriticalPathBudgetGate`、`ValidationEvidenceReuseGate` 与条件 `ReleaseReworkIncidentGate`;预算或复用不得削弱 immutable candidate、version、pack、registry 与 R7 证据 |
| R4 | 执行 `npm pack --dry-run` 与 `npm publish --dry-run`(遵循当前 `publishConfig`),并执行 `NativeCommandExitCodeGate` |
| R5 | 条件执行 pack install smoke,并执行 `IsolatedConsumerCwdGate`:显式 consumer manifest、真实 consumer cwd、source candidate identity 前后对账与真实命令退出码缺一不可 |
| R6 | commit/tag/push/publish 前输出确认,真实发布动作必须等待用户**当前消息**明确确认(`SharedStateMutationGate` / PI-119);一次历史发版授权不覆盖后续补丁 push;本会话自引入 CI 回归须先 `OwnIntroducedRegressionSelfFixGate` 本地修绿再进入 R6。负向:无用户确认却宣称「已 push」→ 违规;CI 自引入失败却「暂停不修」→ 违规(`classifyPushAuthorizationSample` / `classifyOwnIntroducedRegressionSample`) |
| R7 | 发布后验证 git tag、registry 版本、安装包边界和 `node scripts/validate.js` |

## PublisherCredentialTopologyGate

首次 publish、repository/owner/package name/registry/publisher/auth mode 变化、迁移发布 workflow,或用户要求“参考成功项目发布”时,必须在 R0~R3c 之间冻结发布凭据拓扑;普通 patch 且拓扑明确未变时可记录 `unchanged + evidence`,不得静默跳过。

| 字段 | 要求 |
|------|------|
| `publisherIdentity` | 实际发布主体/组织;不得包含 token 或 secret value |
| `repositoryIdentity` | owner/repository、workflow 所在仓库与可访问边界 |
| `packageIdentity` | package name、registry、package owner/access 与现存版本 |
| `authMode` | `trusted-publishing / workflow-secret / local-token / other` |
| `secretTopology` | 只记录 org/repo/environment/local scope、access policy 和传递/继承方式;禁止读取或复制 value |
| `workflowPermissions` | OIDC/trusted publishing 所需最小权限;无 workflow 时 `N/A + skipReason` |
| `referenceEvidence` | 参考成功仓库或最近成功 publish run 的身份、拓扑和结论;复制 YAML 不等于凭据等价 |
| `topologyParity` | `aligned / mismatch / unverifiable`、阻断原因与恢复动作 |

GitHub Actions secrets 的 org/repo/environment scope、access policy 与 precedence 必须作为拓扑事实;reusable workflow 的显式 secret 传递或 `secrets: inherit` 只在平台允许的边界内成立。npm registry 采用 trusted publishing 时,按官方条件验证 OIDC、runner、Node/npm 与 `id-token: write`;其他 registry 不得机械套用 npm trusted publisher 结论。

### ScopedRegistryResolutionGate

同一 scoped package 发布到多个 registry,或仓库/用户 `.npmrc` 已声明 `@scope:registry` 时,`--registry=<target>` 不能单独作为目标 registry 证据。每个 view/whoami/dry-run/publish/post-check 必须冻结 package scope、全局 registry、scope registry、userconfig 来源与命令级优先级,并以隔离 userconfig 或显式 `--@scope:registry=<target>` 绑定目标;双 registry 查询若返回完全相同版本集,先判定为可能被 scope 路由污染,禁止直接认定两个 registry 均已验证。

验证至少包含:默认配置下的污染复现、显式 scope override 后的目标 registry 结果、命令参数单测、真实退出码,以及不读取 token value 的 `whoami / package existence / ownership` 证据。npmjs primary 未通过身份与 scope 解析时,不得先发布 mirror 或创建 tag,避免半发布状态。

## ReleaseAuthorityBeforeCompatibilityGate

| 字段 | 要求 |
|------|------|
| `publishedState` | `released / unreleased / unknown`;用 tag、registry、release note、public docs 和目标 commit 交叉证明 |
| `consumerEvidence` | 稳定外部消费者、已公开示例/类型/配置、安装或升级路径;本地 fixture 不等于稳定消费者 |
| `authoritySources` | 每条发布或未发布结论的权威来源、时间/版本与冲突处理 |
| `decision` | released → 兼容/迁移评估;unreleased 且无稳定消费者 → 直接收敛 canonical contract;unreleased 但有产品取舍 → 用户决策;unknown → 阻断兼容结论 |

不得因为字段或行为曾在未发布分支、草稿文档、内部 fixture 或本地历史包中出现,就自动引入 alias、fallback 或迁移层。需要保留未发布兼容行为时,必须记录真实消费者证据或用户明确产品决策。

## ReleaseEfficiencyControlGate

### CandidateFreezeGate

在首次完整 qualification 前形成 `CandidateFreezeRecord`:

| 字段 | 要求 |
|------|------|
| `candidateIdentity` | commit/tree 或临时 staged snapshot digest、package version、pack-relevant inputs |
| `candidateGeneration` | 每次冻结后 mutation 单调递增;旧 generation 证据不得冒充当前候选 |
| `authorizedScope` | intended files、public surfaces、registry、target version 与明确排除项 |
| `allowedMutationClasses` | `release-blocker / P0-P1 / approved-scope / deferred`;冻结后 deferred 不进入当前版本 |
| `evidenceDependencyGraph` | mutation class → targeted/related/full/pack/CI/registry evidence 失效关系 |
| `freezeAt` | 时间、owner 与基线来源 |

冻结后发生 mutation,必须先更新 generation、分类变更并使依赖证据 stale,再选择重跑路线。禁止一边 qualification 一边继续吸纳非阻断治理项。

发布收口若含多个 defect,冻结前还必须执行 ConvergenceFirstValidationV1:先冻结完整 issue set,批量实施所有修复,再统一 affected V2;禁止每修一项就跑 qualification。只有 affected 与 ECR 全绿后才能形成最终 CandidateFreezeRecord,并只执行一次 V3/full。

### ReleaseCriticalPathBudgetGate

预算必须来自 Profile、最近可比较成功 release 或明确项目约束;字段为 `baselineWindow / qualificationBudget / remoteCiBudget / publishPostcheckBudget / totalBudget / budgetAuthority / budgetMode`。无可比较基线时只能 `measure-only/advisory`,不得把任意统一分钟数伪造成 blocking SLA。报告同时记录真实 elapsed、等待/执行拆分、streak reset 和超预算原因。

### ValidationEvidenceReuseGate

每个复用决策记录 `evidenceId / candidateIdentity / commandFingerprint / environmentIdentity / artifactDigest / freshness / dependencyCoverage / reuseDecision / invalidationReason`。只有 immutable identity、命令/环境等价、制品一致、未过期且 dependency graph 未命中失效边时可复用。远端 CI attestation 可减少同一 SHA 的重复 qualification,但不能替代版本唯一性、staged candidate、pack metadata、registry identity、publish exitCode 或 R7。

### ReleaseReworkIncidentGate

预算超限、candidate generation 连续重置达到项目阈值、同一 release blocker 重复逃逸或复用误判时,创建 `ReleaseReworkIncident`,记录 WorkUnit、双根因、失效证据、关键路径放大、冻结/降级动作和下一版本 prevention。当前修复后通过只关闭本 incident,不证明长期返工率已下降。

`mismatch` 或首次发布的 `unverifiable` 阻断 R6;不得通过读取 secret value 来证明等价。本地 token 路线只核对 auth/config 来源、发布身份与真实 dry-run/publish exitCode,不回显认证值。

## 安全边界

- 不主动索取 npm token、GitHub token 或私钥;若用户、registry、CI 或发布平台明确要求提供、写入或输出,按该显式策略处理并记录来源。
- `PublisherCredentialTopologyGate` 只检查身份、scope、access、inheritance、permission 与成功证据;禁止读取或复制 secret value,也禁止把“workflow 相同”当作凭据等价。
- 不把 `publish`、`push`、`tag` 设计为无确认自动动作。
- CandidateDiff 默认使用临时 `GIT_INDEX_FILE`:先对临时 index 执行 `git read-tree HEAD`,再仅加入授权路径;命令结束后比较真实 `.git/index` digest 和 `git diff --cached --name-status` before/after。只有用户明确授权把候选写入真实 staged set 时才允许使用真实 index,且仍须先保存快照并在报告记录差异。
- tag 或 registry 已存在时必须阻断发布动作。
- 有远端 CI 的项目,tag / release / publish 前必须确认目标 commit 远端 CI 绿色;若无法查询,应阻断正式发布或由用户基于风险另行确认,报告中不得标为 ✅。
- 发布失败时写报告和恢复路径,不静默重试凭据相关动作。
- 若 `publishConfig` 指向 GitHub Packages / restricted access,README 与安装文档必须显式保留认证步骤,禁止再宣称“匿名直接安装”。
- 若 `publishConfig` 指向 GitHub Packages,`test:audit` 必须显式使用 `https://registry.npmjs.org` 作为 audit registry,避免 publish dry-run / prepublishOnly 继承 GitHub Packages 的非审计端点;这不等于跳过审计。
- 完整 release gate 必须由绑定 `ValidationRunIdentityV1` 的 `VerificationExecutionLeaseV2` 授权 `ManagedValidationRunnerV2`,在冻结候选上执行一次并持久化 `ValidationExecutionTerminalProjectionV3`;`prepublishOnly` 只校验该稳定终态与当前 candidate/HEAD/dirty scope、plan/budget、release-pipeline 角色、V3/release/full 范围及 hard deadline 完全一致,禁止在 npm lifecycle 中无授权地重复启动全量验证。V1 仅可读,终态缺失、失败、过期或候选漂移一律阻断 publish。
- V3/full 通过后必须执行 `ExactReleaseArtifactV1`:原生 `npm pack` **只运行一次**生成精确 tarball,包外 `ExactReleaseArtifactReceiptV1` 绑定 source candidate、HEAD、release terminal receipt、npm name/version、tarball path、bytes、entry count、SHA-256 与 SHA-512/integrity。publish 前必须重新校验 receipt 与当前 tarball字节,再执行 `npm publish <exact-tarball> --ignore-scripts --provenance --access public`;禁止 bare directory publish、第二次 pack 或 publish lifecycle 重跑。registry 回读的 integrity/gitHead/provenance 必须与该 receipt 对账。
- `npm publish` 与发布收尾是两个事务边界。publish 命令成功后必须立即形成并持久化 `PublishedArtifactReceiptV1`;registry 可见性等待、provenance 回读和 GitHub Release 创建只允许在 `finalize` 中幂等重试。registry 未返回可选 `gitHead` 时记录 WARN;返回且与候选不一致时 BLOCK;integrity、shasum 或 provenance 不一致时始终 BLOCK。finalize 超时不得再次 publish,只能携带既有发布回执走 `finalize-only`;启动新 publish 前若精确版本已存在,只有制品身份一致时才可跳过 publish 并转入 reconcile/finalize。
- 按 `ConcurrencyPolicy`,只读准备和隔离验证可并行;`npm pack --dry-run`、package boundary check、files/exports/bin 检查不得与任何会删除、重建或写入 `dist` 的命令并行;若曾出现并行读写竞争,报告必须以重新单独执行的 pack 结果为准,并记录旧结果作废。
- ReleaseVerification 完成前必须盘点无关 dirty、旧验证残留和本轮生成但不属于交付范围的产物。只有具备本任务可回读 ownership receipt 且位于明确任务范围内的对象才可清理;DevCodex 不建立影子权限判断,实际操作权限服从宿主策略,同时发布流程禁止自动删除、reset、checkout、stash 或覆盖无归属、用户或并行任务文件。此类文件只能报告、冻结在 candidate 外并给出处置建议,禁止以发布为由扩大任务范围。残留不能安全隔离时阻断 candidate。
- 发布前必须执行 `PublicSurfaceClosureGate`:分类 npm pack 历史公开内容,反查 README 隐藏文档链接、public types 兼容 API 标注、examples/sidebar/nav、搜索索引源文档和 historical pack surface;不得只检查当前源码目录。
- 发布包若包含 `scripts/*.js`、CLI helper、profile validator、migration tool 或公开验证脚本,必须执行 `PackagedScriptDependencyClosureGate`:用 tarball / 临时安装后的真实路径验证公开脚本可执行,缺少本地 helper、spawn 目标脚本或运行时依赖时阻断发布;不得只因源码目录 `npm test` 通过就认定包消费者可用。
- 发布、pack、install smoke、CLI replay、curl/git/npm/node 等原生命令必须执行 `NativeCommandExitCodeGate`:PowerShell 下不能只依赖 `$ErrorActionPreference` 或后续 `Write-Host OK`,必须检查 `$LASTEXITCODE` 或使用会向外传播非零退出码的 wrapper;Bash/类 Unix shell 必须避免管道或子命令吞掉失败。证据至少记录 command、shell、cwd、exitCode、auth/config 来源(如 `.npmrc` / `--userconfig`)、`ScopedRegistryResolutionGate` 的 scope override(若适用)以及失败证据是否已排除;命令失败但脚本继续打印成功文案的结果无效。
- pack install / fresh consumer smoke 必须执行 `IsolatedConsumerCwdGate`:先在隔离 consumer 根创建或核验显式 `package.json`,再用工具 `workdir`、`Push-Location` 或等价方式把每个 `npm init/install/exec` 的真实 cwd 切到 consumer;`npm init --prefix <consumer>`、只传 `--prefix` 却仍在 source cwd 执行,或 consumer manifest 缺失时一律不能作为隔离证据。执行前后必须重算 source candidate identity 与 dirty/staged 边界;发现 source mutation 时立即作废 smoke 与后续发布证据,恢复授权 candidate、提升 generation 或精确恢复原 identity 后,按 evidence dependency graph 重跑受影响门禁。
- DevCodex 仓库维护脚本的默认实现适配器为 `scripts/lib/checked-command.js`;双 registry 候选验证由 `scripts/publish-dry-run.js` 复用该适配器。适配器通过不等于 registry 发布成功,真实 publish 仍须 PublisherCredentialTopologyGate、R6 授权与 R7 后验收。

## 输出格式

```markdown
## ReleaseVerification

| 阶段 | 状态 | 证据 |
|------|------|------|
| R0 | ✅/⚠️/N/A | |
| ReleaseAuthorityBeforeCompatibilityGate | ✅/⚠️/N/A | publishedState/consumerEvidence/authoritySources/decision |
| InteractiveSemanticProbe | ✅/⚠️/N/A | role/name/focusability/Enter-Space-Escape/focus recovery;截图不作为替代证据 |
| R1 | ✅/⚠️/N/A | |
| R2 | ✅/⚠️/N/A | |
| CandidateFreezeGate | ✅/⚠️/N/A | candidate identity/generation、authorized scope、allowed mutations、evidence dependency graph |
| R3 | ✅/⚠️/N/A | |
| CandidateDiffCompletenessGate | ✅/⚠️/N/A | inventory、staged snapshot、cached diff check、name-status review、secret-shape scan、intended scope match |
| R3b | ✅/⚠️/N/A | package completeness gate |
| R3c | ✅/⚠️/N/A | remote CI green |
| ReleaseCriticalPathBudgetGate | ✅/⚠️/N/A | baseline/budget/mode、elapsed、reset、decision |
| ValidationEvidenceReuseGate | ✅/⚠️/N/A | identity/command/environment/artifact/freshness/dependency/reuse |
| ReleaseReworkIncidentGate | ✅/⚠️/N/A | incident 或 N/A + threshold evidence |
| PublisherCredentialTopologyGate | ✅/⚠️/N/A | publisher/repository/package/auth/secret scope/workflow permission/reference run;不含 secret value |
| ScopedRegistryResolutionGate | ✅/⚠️/N/A | packageScope/globalRegistry/scopeRegistry/userconfig/commandOverride/resolvedTarget/independentChannelEvidence |
| ConsumerValidationEngineeringGate | ✅/⚠️/N/A | repository binding / source-consumer identity / denominators / packed artifact / cross-repo CI / freshness;无独立仓写 skipReason |
| R4 | ✅/⚠️/N/A | command/shell/cwd/exitCode |
| R5 | ✅/⚠️/N/A | command/shell/cwd/exitCode |
| IsolatedConsumerCwdGate | ✅/⚠️/N/A | explicit consumer manifest、consumer cwd、禁止 npm init --prefix、source identity/dirty/staged before-after |
| R6 | ✅/⚠️/N/A | |
| R7 | ✅/⚠️/N/A | |
```

## 报告要求

正式发布报告必须包含 ReleaseVerification R0~R7 状态、`CandidateDiffCompletenessGate` staged candidate 证据、`R3b` package completeness gate 证据、`NativeCommandExitCodeGate` 退出码证据、失败恢复路径、发布后 registry/tag 验收证据和关联 commit/tag。