# Release lifecycle contract
```text
Resolve → Doctor → Inspect → Prepare → Seal → Publish → Verify
```
phase 名称是工具内部的固定状态转换,不是 config 中可重排的 commands。
## Progress 与 child output
`publish` 默认把 lifecycle progress 逐行写入 `stderr` 并立即 flush;输出使用固定 phase 名称,
在 non-TTY/CI 中不依赖 spinner 或 ANSI control sequence。
```text
[release-tool] Resolve: repository snapshot
[release-tool] Doctor: tools and GitHub permissions
[release-tool] Inspect: target app is ABSENT
[release-tool] Prepare: project preflight
[release-tool] Prepare: target app
[release-tool] Seal: tag 2026.08.24.2
[release-tool] Publish: target app
[release-tool] Verify: target app
```
```text
Inherit native stdout/stderr
project preflight
Docker build / local_check
Maven reactor verify
OCI image builders
Capture inside release-tool
output used as machine-readable input
Git/GitHub/Docker inspection
commands receiving tool-injected credentials
```
credential-bearing output 在 render error 前完成 redaction;不得为了显示进度而直接 inherit。
幂等重跑只报告实际执行的 phases,不伪造被跳过的 phase。OCI target 必须在 Prepare 重新运行
`reuse_check`,才能确认 existing image 仍满足当前 dependency context。
## 1. Resolve
```text
Input
ReleaseIntent + selected target names + repository config
clean Git snapshot + origin branch/tags
Output
ReleaseCandidate + TargetPlan[] + release-tool version
Allowed side effects
none
Failure
wrong/detached/dirty branch;HEAD != origin branch;tag 格式或 identity 歧义;
unknown target;adapter 无法确定唯一 artifact inventory。
```
从 `git ls-remote --tags origin` 数字排序 `YYYY.MM.DD.N`。历史 lightweight tag 可以参与
next-version calculation;当前 release identity 必须是 annotated tag。
branch identity 由当前 branch name 与 `origin` 的 direct branch ref 建立;不依赖本地
upstream/tracking 配置。
## 2. Doctor
```text
Input
Config + resolved repository facts + local environment
Output
CapabilityReport + authenticated actor + in-memory Secret token
Allowed side effects
tool-owned temporary probe file(退出 phase 即删除)
Failure
incompatible config;missing commands/settings;origin identity mismatch;
gh authentication failure;repository permission below WRITE;repository state changed。
```
read/push repository capability 可验证;不产生 remote write 就不能证明的 destination write
capability 显示 `UNVERIFIABLE`。token 来自 `gh auth token --hostname github.com`,不落盘。
## 3. Inspect
```text
Input
TargetPlan.artifact identities
Output
Allowed side effects
remote reads / temporary verification downloads
Failure
remote unreadable;metadata 冲突;state 无法唯一判断。
```
```text
COMPLETE -> Verify -> skip Prepare/Publish
ABSENT -> Prepare
PARTIAL -> publisher-specific policy
INVALID -> stop
```
Publisher 在实际 write 内再次 Inspect,以关闭 Prepare 期间的 TOCTOU window。
## 4. Prepare
```text
Input
frozen ReleasePlan
Output
ArtifactManifest[](identity + path + SHA-256)
Allowed side effects
tool-owned temporary staging;被 Git ignore 的 compiler/build caches
Forbidden
tracked source、HEAD、Git refs、remote tags、Release/Package writes
Failure
preflight/build/local check 失败;artifact inventory/digest 不确定;
tracked worktree、HEAD、origin branch、candidate tag 或 next tag 变化。
```
Prepare 前要求 clean worktree;结束时任何新的 non-ignored untracked file 也会失败。需要保留的
build cache/output 必须由项目明确 ignore,最终发布文件由 adapter 复制到 tool staging。
`preflight` 只运行一次。每个 target 只能准备 plan 已声明的 artifacts。
选择 target 时自动包含 transitive dependencies。所有 selected targets 按稳定拓扑顺序 Prepare;
downstream 获得 direct dependencies 的 reference 与 config digest。upstream Build 提供已验证的
local candidate tag,Reuse/Existing 提供 digest-pinned remote reference。每个 target 的 metadata
写入 tool-owned staging,Publish 不重新运行 builder 或 `reuse_check`。
## 5. Seal
```text
Input
valid PreparedRelease + confirmation
Output
SealedRelease(remote annotated tag -> exact commit)
Allowed side effects
New only: local annotated tag + push that one tag ref
Forbidden
source/version file/commit/branch write;tag force/move/delete
Failure
candidate race;same tag points elsewhere;tag type/peeled commit mismatch;
push result 无法从 remote refs 确认。
```
`Existing` 复核 remote tag 后跳过 write。push 报错但 remote 已完整时视为成功;remote 未修改时
保留可证明的 local-only annotated tag,下一次同命令复用。
## 6. Publish
```text
Input
SealedRelease + immutable ArtifactManifest[] + latest PublicationState
Output
PublicationReceipt[]
Allowed side effects
仅创建 manifest 声明的 remote artifact identities
Forbidden
rebuild;重新选择 version/target/input;覆盖/删除 artifact;移动 tag
Failure
local manifest digest 变化;remote state 不兼容;write 后 remote 不完整或不匹配。
```
write command 返回失败时不盲重试:先重新 Inspect。远端已 COMPLETE 且 bytes 验证通过则成功;
否则返回原 write error,并附 reconciliation state。
Lifecycle 按 target topology 调用 publisher。OCI publisher 一次处理一个 target:Build 执行 push,
Reuse 执行 exact remote-retag,Existing 不写;每次 write 后重新 Inspect manifest/config/platform。
普通 registry tag write 没有通用 compare-and-swap,因此同一个 release 必须由 single writer
串行发布,或由 registry 提供 immutable-tag enforcement。
## 7. Verify
```text
Input
SealedRelease + prepared manifest 或 resolved identities
Output
VerificationReport / VerifiedRelease
Allowed side effects
remote reads + tool-owned temporary downloads
Forbidden
tracked source、Git refs、remote writes
Failure
tag/commit 前置条件变化;identity missing;metadata/digest/provenance mismatch;
project remote_check 失败或修改 repository preconditions。
```
COMPLETE 的幂等重跑走同一个 Verify contract;“已经存在”不是跳过校验的理由。dependency target
也必须 Verify;只允许跳过其 Build,不允许从 selected closure 中删除它。