release-tool 0.4.0

Configuration-driven release lifecycle for computed-parameter repositories
Documentation
# 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
  ABSENT | COMPLETE | PARTIAL | INVALID

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 中删除它。