feat(release):完成双 release 运维闭环
bat-rust / Build and test Rust (push) Canceled after 0s
bat-rust / Build and test Go API (push) Canceled after 0s

This commit is contained in:
2026-09-12 11:08:04 +08:00
parent 8a77502272
commit 8d57a63697
27 changed files with 3635 additions and 222 deletions
+2 -2
View File
@@ -156,7 +156,7 @@ catalog 仍按“明确不支持”处理,不把低保真路径伪装成完整
1. 官方同步完成后可配置触发导入 CAS + ResourceRepository(已具备 `--import-repository` / `BAT_IMPORT_REPOSITORY=1`)。
2. ResourceRepository 已保存官方 manifest 资源的类型、路径、hash、size 和 metadatametadata 包含 release、平台、bundle path、parse status、TextAsset 名称、TextUnit 数量/格式。
3. 支持 RPC/CLI 查询资源、bundle、TextAsset、解析错误和缓存状态;当前 `resource.index` 会返回资源 metadata`parse-status` 会返回 TextUnit 索引和队列摘要,`parse-text-units` / `parse-errors` 会按当前 release 查询明细,`localized-status`校验 patch manifest。
3. 支持 RPC/CLI 查询资源、bundle、TextAsset、解析错误和缓存状态;当前 `resource.index` 会返回资源 metadata`parse-status` 会返回 TextUnit 索引和队列摘要,`parse-text-units` / `parse-errors` 会按当前 release 查询明细,`localized-status`区分 patch manifest contract 与 artifact integrity`release.status/list/distribution/cleanup` 提供 Rust-owned 双 release 视图和安全运维操作
4. schema 迁移可重复执行;当前 SQLite 已有 `crc``metadata_json` 兼容迁移。
验收:
@@ -175,7 +175,7 @@ catalog 仍按“明确不支持”处理,不把低保真路径伪装成完整
2. 已支持 UnityFS TextAsset、TypeTree string field 和 managed-reference string field 的 localized patch 操作;普通 ZIP 条目在 `archive_entry` 可验证、内层可重解析时会解包、重建并重写外层 ZIP,路径穿越、symlink、混合直接/ZIP patch 和无效内层 bundle 明确失败。
3. MonoBehaviour/ScriptableObject 字段替换必须依赖 P2 字段级解析结果;generic manifest 不把 UnityFS 定位信息扁平化。
4. Patch 产物写入配置化汉化发布根下的 `.staging/<id>`,校验通过后发布到 `versions/<id>` 并切换 `current`rollback 按 manifest 恢复上一 release。
5. 成功后发布状态从 `not_localized` 切到 `localized``localized.status` 要求 state、current symlink 和 patch manifest 同时匹配当前官方 releaseZIP 外层文件和内层 UnityFS 也必须通过发布后重解析校验
5. 成功后发布状态从 `not_localized` 切到 `localized``localized.status` 要求 state、current symlink 和 patch manifest 同时匹配当前官方 release并分别报告 schema/contract 与 artifact integrityZIP 外层文件和内层 UnityFS 也必须通过发布后重解析校验;current 仍存在但产物损坏时返回 `localized.degraded`,不自动修复
验收:
+10 -4
View File
@@ -244,7 +244,7 @@ trusted 和 release/TextUnit/provider/run provenance`translation.tasks` 优
13. 发布完成后先对比上一完整 release 和当前 release 的 `official-download-manifest.json`,写出 `official-resource-changes.json``crowdin-translation-handoff.json`。同一 destination 只有 size 或 BLAKE3 变化才算 modified;新增+变更资源进入解析/翻译 handoff,删除资源只进入差异记录。当前只预留 Crowdin 本地 handoff,不发外部 API 请求。
14. 随后刷新 active release 下的 `official-parse-cache.json``official-textunit-index.json`,并从 Added/Modified 资源、parse cache 与 TextUnit 明细索引派生 `official-textunit-tasks.json``crowdin-textunit-queue.json` 和版本化的 `translation-tasks.sqlite`up-to-date 轮询在已有有效解析缓存、TextUnit 明细索引和 TextUnit 队列时只读取摘要,不重复解析,重新同步队列时保留已有 worker 状态。
15. 若启用 `--import-repository`,已校验 release 会被导入 CAS + `ResourceRepository`,并可经 `resource.index` 查询。历史 release 候选失效时,已有 CAS 对象会先经过完整性和元数据校验,再增加 release 引用并原子物化;当前 release 在 `official-cas-reuse-references.json` 中记录引用,staging/release 清理时递减,失败则回退网络并保留诊断。
16. 官方同步报告默认给出 `localized_release_status=not_localized`,表示原版资源已发布、汉化资源未发布;generic manifest 驱动的 Binary/JSON/Text 以及当前支持的 UnityFS TextAsset、TypeTree string field 和 managed-reference string field patch 发布成功并通过 `localized-patch-manifest.json`、current symlink、release ID 及 ZIP 内层最终重解析校验后,`localized.status` 才返回 `localized`,表示原版和汉化两套资源都已发布。`translation.proofread` 只会把 workflow 标记成 `manual_proofreading` / `translation.manual_proofreading`,不会回退已发布汉化 release 的发布状态。
16. 官方同步报告默认给出 `localized_release_status=not_localized`,表示原版资源已发布、汉化资源未发布;generic manifest 驱动的 Binary/JSON/Text 以及当前支持的 UnityFS TextAsset、TypeTree string field 和 managed-reference string field patch 发布成功并通过 `localized-patch-manifest.json`、current symlink、release ID 及 ZIP 内层最终重解析校验后,`localized.status` 才返回 `localized`,表示原版和汉化两套资源都已发布。`localized.status` 分开返回 `patch_manifest_contract_status``artifact_integrity_status`state/current/identity 存在但文件被截断或手工修改时返回 `localized.degraded`,只读检查不回滚、不删除、不修复。`translation.proofread` 只会把 workflow 标记成 `manual_proofreading` / `translation.manual_proofreading`,不会回退已发布汉化 release 的发布状态。
维护期特殊分支:如果官方 launcher/server-info 已经指向新资源根,但 client-patch seed marker 或必需 seed catalog 仍返回 403/404 等未开放状态,`bat` 返回 `waiting_for_official_resources`,保留现有 `current`,不创建失败 staging;若本轮启用 `--auto-discover`,会在 `<output>/official-launcher-bootstrap.pending.json` 写入待处理 launcher bootstrap 证据,供后续排障和自研客户端开发使用。
@@ -345,8 +345,9 @@ JSON-RPC 2.0 服务,是面向上层服务(Go 层)的**主要跨语言边
- 方法命名空间与实现状态、请求/响应示例见
`docs/reference/rpc-backend-api.md``daemon.status/logs/stop/restart/reload/refresh/doctor`
`resource.state/sync/verify/repair/manifest/list/index``parse.status/text_units/errors`
`translation.tasks/handoff/task.update/proofread``localized.status``catalog.*`
`task.status/list/cancel/logs` 已实现;文件级 `patch.apply` / `unityfs.patch_*`
`translation.tasks/handoff/task.update/proofread``localized.status`
`release.status/list/distribution/cleanup``catalog.*` `task.status/list/cancel/logs`
已实现;文件级 `patch.apply` / `unityfs.patch_*`
和受支持 localized publish/rollback 已实现,`archive_entry` 可验证时会重写
外层 ZIP;通用发布级 patch 与复杂 UnityFS 语义编辑仍待后续;
`task.create` 按设计暂不开放通用任务入口;
@@ -357,7 +358,7 @@ JSON-RPC 2.0 服务,是面向上层服务(Go 层)的**主要跨语言边
- Rust `bat` / daemon 是资源生产者和状态拥有者;Go `bat-api` 是资源读侧、
bootstrap 和 HTTP 分发入口。二者之间的稳定边界是 `bat.sock` RPC 和
`resource_root` 中已发布的只读文件。
Rust 选择后返回的 `resource_root` 中已发布的只读文件。
- Go 层负责:资源 bootstrap、资源内容分发(`cmd/bat-api`)、HTTP API 进程配置、
以及通过 `internal/backendrpc` 作为 RPC client 调用本机 daemon(连接
`bat.sock`,每行一个 JSON-RPC 请求/响应)。`cmd/bat` 仍是试验骨架,不是产品级用户 CLI。
@@ -371,6 +372,11 @@ JSON-RPC 2.0 服务,是面向上层服务(Go 层)的**主要跨语言边
manifest 中的 BLAKE3,响应包含 Last-Modified、Accept-Ranges 和长期缓存头。
- 版本/清单发现优先走 RPC:先 `daemon.status`,再 `daemon.doctor`,再
`catalog.status` / `resource.manifest`(可用 `--socket` 指定 socket 文件)。
- `/v1/releases``/v1/distribution` 和受保护的 `/admin/releases/status`
`/admin/releases` 只转发 `release.status/list/distribution` 的 Rust typed
结果;localized 或历史分发不会绕过 Rust 完整性判断。
- 受保护的 `/admin/control/release-cleanup` 只转发 Rust `release.cleanup`
先 dry-run 获取 `plan_id`,执行时由 Rust 重验证引用、路径和 current 保护。
- 支持 `.env` / 环境变量配置监听端口、public base URL、RPC socket 和 RPC
刷新周期,并预留 database/redis 键供后续 API 持久化;**不**负责资源自动拉取。
- 可选改写 server-info 中的 `AddressablesCatalogUrlRoot` 指向自身;不伪装
+29 -4
View File
@@ -8,6 +8,7 @@
- inventory 抽取:`adapters/src/official/inventory.rs`
- 落盘与 manifest`infrastructure/src/official_download.rs``destination_for_url`
- 发布布局:`infrastructure/src/official_update.rs`
- 双 release 视图、分发选择与清理:`infrastructure/src/release_ops.rs`
- 分发:`cmd/bat-api` + `internal/api`(见 `docs/reports/GO_STATUS.md`
---
@@ -17,7 +18,7 @@
| 角色 | 组件 | 职责 |
|---|---|---|
| 同步 / 运维(近乎全自动) | Rust `bat` | auto-discover、拉取、校验、发布、watch/daemon、RPC 后端 |
| 资源 bootstrap / 只读分发 | Go `bat-api` | 同环境经 `bat.sock` 发现已发布版本和 `resource_root`,提供 `/v1/bootstrap`、server-info 改写官方 CDN path 字节 |
| 资源 bootstrap / 只读分发 | Go `bat-api` | 同环境经 `bat.sock` 读取 Rust 选择的已验证版本和 `resource_root`,提供 `/v1/bootstrap`、server-info 改写官方/localized CDN path 字节和 release 管理转发 |
| 试验 CLI | Go `cmd/bat``bin/bat-go` | 非产品;禁止与 Rust `bat` 重名 |
**禁止**:把已安装客户端目录或 `/home/wanye/D/BlueArchive` 当作生产输入;真实全量样本优先服务器 release 或 `/tmp` 隔离目录。
@@ -85,13 +86,34 @@
- `not_localized`:官方原版资源已经完成下载、校验和发布,汉化资源尚未发布;这是官方同步完成后的默认状态。
- `localized`:同一官方版本的原版资源和汉化资源都已发布,生产侧可以同时提供两套资源。
### 2.1 读侧 vs 写侧
### 2.1 双 release 读写边界
Rust `bat``release.status` 是 official/localized 的统一只读视图,基于既有
version state、current symlink、release manifest、文件系统和必要的 CAS/reference
元数据计算,不建立第二个 release 数据库。`release.list` 返回两个 namespace 的当前
与历史 release,包含稳定 ID、created/published、source official relation、生命周期、
`rollback_available`、manifest contract、artifact/distribution integrity、
`stale`/`damaged`/`referenced`/`unknown`、rollback previous 和诊断;缺少 generic manifest 的
旧 localized release 保留为 `legacy`/`unknown`,不自动改写。
`release.distribution` 的默认 channel 是 `official`。只有当前或显式历史、路径归属安全、
source relation 正确且 manifest/artifact integrity 通过的 release 才能被选择;staging、
损坏、缺失、symlink/path escape 或未验证历史项不会回退到另一 channel。返回的
`resource_root` 和 manifest entry 由 Rust 决定,Go 只做 typed forwarding。
`release.cleanup` 先生成 dry-run 计划和 `plan_id`,执行时重新计算并比对计划。current、
rollback previous、active/in-progress、localized source official、state/manifest/CAS
reference、无法确认 ownership 的对象均保留;只删除重新验证后仍为普通目录且确定无引用的
历史 release。它不改变 current,不执行 rollback,也不负责自动 repairstaging 默认保留
以避免删除未持久化任务。
### 2.2 读侧 vs 写侧
| 阶段 | 根目录 |
|---|---|
| 下载写入 | `<output>/.staging/<id>` |
| 发布完成 | rename 到 `versions/<id>`,再切换 `current` |
| 生产读取 / bat-api | RPC 给出的 `version.resource_root`通常等价于 `current` 解析后的 versioned 目录 |
| 生产读取 / bat-api | RPC 给出的已验证 `resource_root`默认等价于 official `current` 解析后的 versioned 目录localized 必须显式选择 |
每个 release 的 `official-download-manifest.json` 是历史复用的索引。新 staging
按规范化 destination 查找候选,并重新验证 manifest 中的 size、BLAKE3 和 ZIP
@@ -138,7 +160,10 @@ GET {public-base-url}/prod-clientpatch.bluearchiveyostar.com/<root_token>/...
≡ 磁盘 <resource_root>/prod-clientpatch.bluearchiveyostar.com/<root_token>/...
```
默认仅服务 **download manifest 索引内且 Present + size 匹配** 的文件。
默认仅服务 **official download manifest 索引内且 Present + size 匹配** 的文件。需要
localized 或历史 release 时,调用 `release.distribution` 选择 Rust 已验证的
`resource_root`,再由 `/v1/distribution` 或带 `channel`/`release_id` 的 CDN path
转发;Go 不在本地判断健康度,也不回退到 official。
### 3.3 launcher 资源引导兼容