sprawling-wire 0.0.12

The process boundary of a sprawling city: the frames its clients speak, and the server that answers them.
Documentation
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
-- Copyright (c) 2026 2youg1 and the sprawling contributors

/-!
# wire::answer::release

规定 `crates/wire/src/answer/release.rs` 的帧,以及 `client/src/views/release/answer.svelte`
手动选择更新命令时的性质。帧形状由 Rust 类型、schema hash 和 wire 合约检查守住;
下面的选择模型证明候选限制在任意操作轨迹上保持,环境中的注册表 HTTP 与进程来源识别
由 `crates/sprawling/src/release.rs` 的回环回归和真实安装验收检查,不属于该证明。
-/

/-!
### 8-36 这座城的版本与原安装渠道:`Query::NewestRelease`

```rust
pub struct ReleaseLine { pub version: String, pub released: String }
pub enum ReleaseAnswer {
    Stands { mine: ReleaseLine, newest: ReleaseLine, registries: Vec<RegistryNewest>, verdict: ReleaseVerdict, update: UpdateHint },
    Unreleased { registries: Vec<RegistryNewest>, update: UpdateHint },
    Unconfirmed { mine: ReleaseLine, registries: Vec<RegistryNewest>, update: UpdateHint },
    Refused { refusal: AxError },
}
pub struct RegistryNewest { pub registry: Registry, pub reading: RegistryReading }
pub enum Registry { Npm, CratesIo, Github }
pub enum RegistryReading { Read { newest: ReleaseLine }, Refused { refusal: AxError } }
pub enum InstallChannel { Npm, Bun, Binstall, Unknown, Package, CargoOrBinstall, Cargo, Archive, Aur, Source }
pub struct UpdateHint { pub channel: InstallChannel, pub command: Option<String>, pub alternatives: Vec<String> }
```

人按下检查按钮或运行 `status --check` 才查询,没有定时、连接时查询或自动更新。
`Stands.newest` 是 Rust 判定实际使用的版本,终端与页面直接画它,不再另挑注册表行。
`registries` 另外显示每个来源的成功或拒绝;判定来源无法读取时答 `Refused`。
Cargo 的裸版本号由 `Version` 判,不与 npm 的预发布串直接比较;日期未知时为空,
未带发行 tag 的 Cargo 源码安装仍比较已编译版本,不制造发布日期。
开发构建答 `Unreleased`,保留实际已知安装来源与手动命令但不给 verdict;来源未知的发行二进制答 `Unconfirmed`,不猜一个 verdict。
更新命令只供人选择、复制和运行,查询与选择不下载或覆写二进制。归档更新命令将实际发布 tag 同时固定到脚本源码 ref 和 SPRAWLING_VERSION,不从 Release 的当前成熟度重造历史 tag。
-/

/-!
### 8-47f 查询按它回答的东西命名:`Query::NewestRelease`

查询线上拼作 `newest_release`,答复仍为 `Answer::Release`。
查询名与释放关停范围的 `Command::Release` 区分,保留一条查询拼法。
字段换形保持查询名时按 wire D1 升 `WIRE_V`,schema hash 与生成客户端同步。
-/

/-! D24 来源、比较版本与更新命令由服务端一处决定

npm/Bun/Package 读 npm latest;Cargo/Binstall/CargoOrBinstall 读 crates.io;Archive/Aur
读 GitHub 发布列表首个非 draft 的发布,与脚本安装器的列表来源一致,包含 prerelease。
GitHub 的 latest 排除 prerelease,不能用于本项目归档检查;没有可用发布时拒绝判定。
两种历史成熟度的 tag 通过 `Release::from_published_tag` 的同一 tag 解码器读取。
GitHub API、归档脚本与发行页面的 repository 身份取自根清单并经 Cargo 的
`CARGO_PKG_REPOSITORY` 进入 release 模块,不在 HTTP URL 中另写 owner/repo。

包入口只把明确的 npm/Bun 选择或 `.bun`、`_npx` 缓存来源交给二进制,不能把运行时
当安装器;通用包目录答 Package,需要在 npm/Bun 命令中选择。
Cargo bin 目录答 CargoOrBinstall,需要在 Cargo 编译与 binstall 下载中选择。
归档安装器复制二进制后写来源标记,卸载移除标记;标记名只由
`sprawling::release::ARCHIVE_ORIGIN_FILE` 定义,旁边仍有 skills 的解压归档同属 Archive。
明确的 `SPRAWLING_INSTALL_CHANNEL` 手动选择接受 npm/bun/cargo/binstall/archive/aur。
Aur 的识别与安装布局由 sprawling Install D56 规定;GitHub 比较不保证外部包定义已同步。

`command` 只有来源明确时才给出;`alternatives` 给出不明确来源允许的精确命令。
页面选择必须是候选之一,清空或收到新答复后没有默认选择,Copy 只接收明确命令
或已确认的候选。被否:Cargo 路径自动选源码编译、Bun 运行时自动认作 Bun 安装器、
客户端另设版本选择与排序规则,这些都会让安装方式或显示版本漂离实际比较来源。
重开条件是新增安装器或注册表,此时扩展枚举、来源适配与相应生产验收。
-/

namespace Wire.ReleaseChoice

structure Selection where
  candidates : List String
  chosen : Option String

inductive Action where
  | choose (command : String)
  | refresh (candidates : List String)
  | clear

def valid (state : Selection) : Prop :=
  ∀ command, state.chosen = some command → command ∈ state.candidates

def step (state : Selection) : Action → Selection
  | .choose command => { state with chosen := if command ∈ state.candidates then some command else none }
  | .refresh candidates => ⟨candidates, none⟩
  | .clear => { state with chosen := none }

def trace (state : Selection) : List Action → Selection
  | [] => state
  | action :: rest => trace (step state action) rest

private theorem step_valid (state : Selection) (action : Action) : valid (step state action) := by
  cases action with
  | choose command =>
    simp only [step]
    split
    · rename_i member
      intro selected same
      cases same
      exact member
    · intro selected same
      cases same
  | refresh candidates =>
    intro selected same
    cases same
  | clear =>
    intro selected same
    cases same

/-- 任意选择、刷新与清空轨迹之后,可复制的命令仍来自当前服务端候选。 -/
theorem every_trace_keeps_the_current_candidates (state : Selection) (actions : List Action)
    (initial : valid state) : valid (trace state actions) := by
  induction actions generalizing state with
  | nil => exact initial
  | cons action rest ih => exact ih (step state action) (step_valid state action)

end Wire.ReleaseChoice