# State 与 recovery
## Publication decision matrix
```text
State GitHubReleasePublisher GitHubMavenPublisher
ABSENT create release / upload assets deploy exact prepared version
COMPLETE Verify, then idempotent skip Verify, then idempotent skip
PARTIAL verify present bytes, upload missing STOP; never redeploy version
INVALID STOP STOP
```
`COMPLETE` 只有在 release 已由 remote annotated tag seal 时才可跳过。若 next candidate version
已有完整 artifacts、却没有对应 tag,工具将其视为 orphan publication 并停止,不自动“认领”。
## Tag state
```text
remote same annotated tag -> expected commit
success;复用 tag
remote same tag -> other commit / lightweight ref
stop;不 force、不 delete
push reports failure + remote tag complete
reconcile 为 success
push reports failure + remote tag absent
local annotated tag 保留;修复权限/网络后运行同一 command
direct/peeled refs 缺失、歧义或无法读取
stop;不要自动重试 remote write
```
检查命令:
```bash
git ls-remote --tags origin 'refs/tags/YYYY.MM.DD.N*'
git cat-file -t refs/tags/YYYY.MM.DD.N
git rev-parse 'refs/tags/YYYY.MM.DD.N^{commit}'
```
## GitHub Release partial
```text
1. Inspect expected asset names。
2. 下载所有已存在的 expected assets。
3. 与 Prepared ArtifactManifest SHA-256 比较。
4. 全部一致:只 upload missing names。
5. 任一不一致:INVALID,停止;不使用 --clobber。
```
其它 target 的 asset 可以共存于同一个 GitHub Release,不属于当前 target 的文件不会被删除。
`gh release create` 内部可能经历 draft/upload/publish 多次 API write。发现遗留 draft 时返回
`INVALID` 并停止,避免把“assets 已上传”误判为公开 release 已完成;人工确认前不自动切换 draft。
## GitHub Maven partial
GitHub Packages 的 version/artifact bytes 视为 immutable。一个 version 只存在部分 jar/pom 时,工具
拒绝猜测 deploy 是否能安全续传:
```text
PARTIAL -> stop -> 人工调查 publisher/server state
```
不得删除 package version 后让工具重试;删除/覆盖不属于自动 recovery contract。
## Response lost after remote write
```text
write command/network error
-> Inspect remote identity
-> COMPLETE
-> Verify exact bytes
-> success receipt
-> ABSENT/PARTIAL/INVALID/unreadable
-> return original write error + observed state
```
这条规则同时用于 tag push、GitHub Release write 和 Maven deploy。
## Safe retry
```bash
# 先 read-only 确认 candidate 与 remote state
release-tool plan --release
release-tool doctor
# 使用原命令;不要手工递增 tag
release-tool publish --release
```
只有错误明确指出 local-only tag retained 时,local tag 才是可自动恢复的中间状态。其它不一致先
停止并人工检查。