# Rust Resource Backend RPC API 本文档冻结本机 Rust Resource Backend API 的稳定调用边界。Go 项目 `bat-api`、Go 服务层、运维脚本和 `bat` CLI 都应以这里的 JSON-RPC contract 为准,不应绕过 daemon 状态文件或扩展 `bat-ffi` 作为主路径。 ## 传输 - 传输:Unix domain socket。 - 默认 socket:`/tmp/bat-pid/bat.sock`。 - 协议:JSON-RPC 2.0,每行一个 request,每行一个 response。 - 编码:UTF-8 JSON。 - 访问控制:依赖本机文件权限和状态目录权限;不要把 socket 暴露到公网。 请求: ```json {"jsonrpc":"2.0","id":1,"method":"resource.repair","params":null} ``` 成功响应的 JSON-RPC 顶层 `result` 一律是应用层 envelope: ```json { "jsonrpc": "2.0", "id": 1, "result": { "ok": true, "status": "accepted", "data": {"task_id": "task-1234-1", "kind": "resource.repair"}, "request_id": "req-1234-1" } } ``` 应用层失败也放在 `result` 的 envelope 中: ```json { "ok": false, "status": "error", "error": { "code": "BAT-ERR-700003", "kind": "not_implemented", "domain": "rpc", "location": "rpc.dispatch", "message": "方法尚未实现:daemon.clean-stable", "retryable": false }, "request_id": "req-1234-2" } ``` 只有 JSON 解析失败等传输层错误使用 JSON-RPC 顶层 `error`。 ## Envelope | 字段 | 类型 | 说明 | |---|---|---| | `ok` | bool | 应用层是否成功。 | | `status` | string | `ok`、`accepted` 或 `error`。 | | `data` | object/null | 成功结果。失败时省略。 | | `error` | object/null | `ApiError`。成功时省略。 | | `request_id` | string | daemon 进程内请求 ID,用于日志关联。 | `ApiError` 结构以 `core/src/error_code.rs` 码表为准: | 字段 | 类型 | 说明 | |---|---|---| | `code` | string | `BAT-ERR-<6位>`。 | | `kind` | string | 错误类别。 | | `domain` | string | 错误域。 | | `location` | string | Rust 侧出错位置。 | | `message` | string | 可诊断错误信息。 | | `retryable` | bool | 调用方是否可以按策略重试。 | ## 方法 ### daemon | 方法 | 状态 | params | data | |---|---|---|---| | `daemon.status` | 已实现 | `null` | 后台状态报告。 | | `daemon.logs` | 已实现 | `{ "tail": 200 }` | 日志尾部报告。 | | `daemon.stop` | 已实现 | `null` | accepted ack。 | | `daemon.restart` | 已实现 | `null` | accepted ack;启动 Rust lifecycle controller,并在响应后停止当前 daemon。 | | `daemon.reload` | 已实现 | `null` | accepted ack。 | | `daemon.refresh` | 已实现 | `{ "force": false }` | accepted ack。 | | `daemon.doctor` | 已实现 | `null` | 只读诊断报告。 | | `daemon.clean-stable` | 保留 | `null` | live RPC 不执行;由 CLI 离线清理入口处理。 | `daemon.restart` 不在 daemon 线程内手写第二套启动流程;它启动本机 Rust `bat restart --state-dir ...` lifecycle controller,由既有 CLI restart 路径复用 保存的启动参数、代理凭据、PID/socket 替换和控制锁。 `bat.status`、`bat.stop`、`bat.restart`、`bat.reload`、`bat.refresh`、`bat.logs`、 `bat.doctor`、`bat.clean-stable` 是兼容别名;新代码应使用 `daemon.*`。 ### resource | 方法 | 状态 | params | data | |---|---|---|---| | `resource.state` | 已实现 | `null` | 资源发布根、版本状态、上次同步结果。 | | `resource.sync` | 已实现 | `{ "force": false }` | `{ "task_id": "...", "kind": "resource.sync" }`。 | | `resource.verify` | 已实现 | `null` | `{ "task_id": "...", "kind": "resource.verify" }`。 | | `resource.repair` | 已实现 | `null` | `{ "task_id": "...", "kind": "resource.repair" }`。 | | `resource.manifest` | 已实现 | `{ "release_id": "...", "expected_publication_identity": "...", "expected_manifest_identity": "...", "expected_verification_generation": 7, "offset": 0, "limit": 100 }` | 绑定一个 Rust attested official generation 的 download manifest 分页;generation 为必需绑定条件,`0` 也不能省略或忽略。 | | `resource.list` | 已实现 | 同 `resource.manifest` | `resource.manifest` 的兼容别名。 | | `resource.index` | 已实现 | `{ "offset": 0, "limit": 100, "type": "asset_bundle", "hash": "...", "path_pattern": "*", "release_id": "...", "platform": "windows", "destination": "...", "archive_entry": "...", "parse_status": "parsed", "format": "json" }` | 当前 `ResourceRepository` 分页/过滤查询。 | `resource.repair` 会开启本地 manifest audit + repair,不继承 `force`。 `resource.manifest` / `resource.list` 查询当前已发布 release 的 `official-download-manifest.json`;`resource.index` 查询可选导入产生的 SQLite `ResourceRepository`,索引不存在时返回 `ok=true` 且 `data.available=false`,不会隐式创建数据库。`resource.index` 可按 `resource_type`/`type`、`hash`、`path_pattern`、`official_release_id`/`release_id`、 `platform`、`destination`、`bundle_path`、`archive_entry`、`parse_status` 和 `text_unit_format`/`format` 过滤;`path_id`、`class_id` 和 `field_path` 属于 `parse.text_units` / `parse.errors` 的对象级查询。`limit` 范围是 `1..=1000`,非法参数返回 `BAT-ERR-700002`。 `resource.manifest` 的请求必须携带由 `release.attestation` 返回的 `release_id`、`expected_publication_identity`、`expected_manifest_identity` 和 `expected_verification_generation`。 每一页返回 `release_id`、`resource_root`、`manifest_version`、 `publication_identity`、`mapping_identity`、`manifest_identity`、`generation`、 `total_entries`、`offset`、`limit` 和 `entries`。Rust 在当前 release 切换或 identity 不匹配、attestation 不可用或 generation 改变时拒绝请求;Go 会逐页验证 channel、 这些 identity、generation、manifest version、页 offset/limit、total 和最终 entry count,任何一页不一致都会丢弃整个候选快照。 `resource.index` 的 `entries[]` 是 `Resource` JSON,除 `id`、`local_path`、 `entry` 外会包含 `metadata`:`official_release_id`、`platform`、 `bundle_path`、`archive_entries`、`parse_statuses`、`unity_versions`、 `text_assets`、`text_unit_count`、`text_unit_formats` 和 `text_unit_error_count` 等字段。`entry` 还会保留 Addressables 的 `provider_id`、`bundle_name`、`hash`、`size`、`crc` 和 `dependencies`。 旧索引库会通过 `metadata_json` 以及资源字段兼容迁移得到默认空值。 `resource.state`、`catalog.status`、`parse.status` 和 `localized.status` 都会返回当前观察面的短状态 `status` 与稳定状态码 `status_code`。`status_code` 使用命名空间格式,例如 `official.up_to_date`、`official.published`、 `parse.completed`、`translation.queued_offline`、`localized.published` 和 `distribution.ready`。这些状态码描述资源/解析/翻译 handoff/汉化/分发生命周期; 失败原因仍使用 `BAT-ERR-*` 错误码,二者不混用。响应还会包含 `status_phase`、`status_terminal` 和 `status_retryable`,供 `bat-api` 等读侧 决定展示、重试或 readiness。 官方资源完整新版本发布后,Rust 侧会先比较上一完整 release 与当前 release 的 download manifest,并在当前 release 根目录写出: - `official-resource-changes.json`:记录 added / modified / removed 资源。 同一 destination 只有 size 或 BLAKE3 变化才算 modified;URL 或 CDN root 变化但内容一致时不进入解析/翻译候选。 - `crowdin-translation-handoff.json`:只包含 added + modified 资源,作为后续 Crowdin worker 的稳定本地队列输入;当前 RPC 不直接调用 Crowdin API。 - `official-parse-cache.json`:解析缓存。up-to-date 轮询发现本地文件未变且缓存 有效时只读取摘要,不重复解析。 - `official-textunit-index.json`:TextUnit 明细和解析错误索引。up-to-date 轮询发现 本地文件未变且索引有效时复用,不重复解析。 - `official-textunit-tasks.json`:只由 added + modified 资源、parse cache 和 TextUnit 明细索引派生,记录 TextUnit 任务、跳过原因和解析诊断。 - `crowdin-textunit-queue.json`:只包含已产生 TextUnit 的离线任务;官方同步阶段 不发出 provider 网络请求。 - `translation-tasks.sqlite`:当前 release 的可变 worker 状态库,记录 queued / running / failed / completed / skipped、attempt count、provider run ID、provider、TextUnit 级译文结果、lease、失败分类、可重试标记和 next attempt;当前 schema version 为 V2,schema 由 `schema_migrations` 版本表 管理,并通过只读 fingerprint、`BEGIN IMMEDIATE` 和显式 V1 → V2 migration 保证 future/未知 schema fail closed。 - `translation-handoff.json`:当前 release 的版本化 job/unit/provider run 交接 快照;worker 更新后的实时状态仍以 `translation-tasks.sqlite` 为准。 - `translation-memory.sqlite`:跨 release 的项目级 Translation Memory,不位于 `versions/`,也不与 `translation-tasks.sqlite` 共用;记录 raw source/hash、完整 TextUnit context、candidate/trusted、translation 和 release/TextUnit/provider/run provenance;当前 schema version 为 V1,打开时先进行只读 fingerprint preflight, 再在 writer transaction 内补齐 `schema_migrations` 版本记录。默认路径为 `/translation-memory.sqlite`,可由 `BAT_TRANSLATION_MEMORY_PATH`、`[translation.worker].translation_memory_path` 或 CLI 覆盖。 - `glossary.sqlite`:跨 release 的项目级 Glossary,不位于 `versions/`,也不与 `translation-tasks.sqlite` 或 TM 共用;记录 term、alias、推荐/允许译法、scope、 priority、review 状态、source provenance、完整 source/review history 和 deletion audit;当前 schema version 为 V2。V2 正式吸收历史上未升版本的 `glossary_term_deletions` drift,打开时通过 fingerprint 和 writer transaction 区分 V1-A/V1-B 并 fail closed;正式 schema evolution 不再通过 `ensure_column` 隐式修复。 默认路径为 `/glossary.sqlite`,可由 `BAT_GLOSSARY_PATH`、`[translation.worker].glossary_path` 或 CLI 覆盖。 删除资源只进入 `official-resource-changes.json`,不进入 Crowdin handoff。 ### release | 方法 | 状态 | params | data | |---|---|---|---| | `release.attestation` | 已实现 | `null` | 当前 official 的轻量 health/publication proof:`available`、`ready`、`channel`、`release_id`、`resource_root`、`publication_identity`、`mapping_identity`、`manifest_identity`、`entry_count`、`integrity_status`、`status`、`status_code`、`verification_generation`、`verified_at`、`max_age_seconds` 和 diagnostics。只读取 current、publication anchor、manifest 元数据与 freshness,不扫描历史 release 或计算资源文件 BLAKE3。 | | `release.status` | 已实现 | `null` | official/localized current、source relation、match、历史 release 和 manifest/artifact/distribution integrity 的重型管理诊断,仍返回管理侧 `official_distribution_ready`;普通 current bat-api readiness 使用 `release.attestation`。 | | `release.list` | 已实现 | `{ "channel": "official" }` 或 `{ "channel": "localized" }`,可省略 | 对应 namespace 的历史 release 摘要,包含 stable ID、created/published、current pointer、`rollback_available`、lifecycle、`stale`/`damaged`/`referenced`/`unknown`、legacy 和诊断。 | | `release.distribution` | 已实现 | `{ "channel": "official", "release_id": "...", "destination": "...", "offset": 0, "limit": 1000 }`,均可省略 | Rust 只选择具有独立 `official-distribution-publication.json` 且 identity 与当前 manifest 一致的 verified `resource_root`;有 `destination` 时是 single-entry lookup,响应固定 `total=1, offset=0, limit=1, entries.length=1`,使用 published mapping identity/destination index,只校验该实际文件的 bytes/BLAKE3,不重新执行全量映射或资源 audit;无 `destination` 时保留管理查询分页语义。localized 还必须匹配 source official 的 published identity,并使用发布时生成的实际字节 metadata,不复用 official size/hash;默认 channel 为 official,选择失败返回 `available=false`,不跨 channel fallback。 | | `release.cleanup` | 已实现 | dry-run `{ "execute": false }`;执行 `{ "execute": true, "plan_id": "..." }` | cleanup plan、candidate/retain reasons、blocking references 和 removed paths;执行前会重新生成并比对 `plan_id`。 | `release.status`、`release.list` 和 `release.distribution` 只读现有 official/localized state、current、manifest、文件系统和 CAS/reference 元数据,不创建第二套 release 状态。 分发选择使用发布后的轻量 manifest 和文件 size/单文件 BLAKE3 校验,不在 HTTP 热路径 重新执行完整 release audit;localized 还要求 distribution manifest 的 destination/URL 集合与 source official manifest 一致,并使用发布时记录的实际 localized bytes/hash。 publication 文件缺失、manifest content identity 变化或 source mapping identity 不一致时, 即使单个目标文件本身完整,也返回 `available=false`;旧 release 可被列出并标记 `legacy`,但不会被 distribution 读侧自动重建 publication metadata。默认官方分发行为不变。 `release.cleanup` 只删除 Rust 能证明是普通目录且未被 current、rollback、staging、 source、state、manifest、CAS 或未知 ownership 引用的历史项,不修改 current,也不承担 rollback 或 repair。 ### schedule 调度计划由 Rust `bat` 持有,状态文件为 daemon `state_dir` 下的 `bat-schedules.json`。CLI、RPC 和 `bat-api` dashboard 都调用同一组原子 读改写逻辑,不在 Go 侧复制计划状态。 | 方法 | 状态 | params | data | |---|---|---|---| | `schedule.list` | 已实现 | `null` 或 `{ "id": "...", "group": "res", "enabled": true }` | `{ "command": "schedule-list", "query": {...}, "schedules": [...] }`。 | | `schedule.add` | 已实现 | 调度 mutation | 新建 schedule report。 | | `schedule.update` | 已实现 | 调度 mutation,必须有 `id` | 更新后的 schedule report。 | | `schedule.remove` | 已实现 | `{ "id": "daily-pull" }` | 删除报告。 | | `schedule.run` | 已实现 | `{ "id": "daily-pull", "group": "res", "force": true, "max_runs": 1 }`,字段可省略 | 到期或强制执行报告;省略 `id` 执行指定 group 的到期计划。 | 调度 mutation 字段如下: | 字段 | 类型 | 说明 | |---|---|---| | `id` | string | 计划 ID;add 必填,update/remove 用于定位。 | | `group` | string | `res`、`parse` 或 `i18n`;对应一级工作流。 | | `action` | string | `res` 的 `pull/refresh/verify/repair`、`parse` 的 `run/repack/clear-cache`、`i18n` 的 `run/export/validate/publish`。 | | `args` | string[] | 目标工作流的 CLI 参数。 | | `next_run_unix_seconds` | uint64 | 指定下一次执行时间;不能和 `delay_seconds` 同时使用。 | | `delay_seconds` | uint64 | 从当前时间计算下一次执行时间。 | | `every_seconds` | uint64 | 周期秒数;必须大于 0。 | | `count` | uint64 | 最大执行次数;省略周期无限执行,非周期计划默认执行一次。 | | `clear_args` | bool | update 时清空工作流参数。 | | `clear_every` | bool | update 时清除周期并转为单次计划。 | | `enabled` | bool | 启用或停用计划。 | `schedule.run.max_runs` 必须大于 0,用于限制一次轮询最多领取的到期计划数。 `count > 1` 必须和周期同时存在;`schedule.run` 的 `force=true` 只忽略 到期时间,不会绕过 `enabled=false`。每次执行前先持久化下一次状态,执行后 再持久化成功/失败和错误信息,避免进程中断后重复领取同一计划。 ### parse | 方法 | 状态 | params | data | |---|---|---|---| | `parse.status` | 已实现 | `null` | 当前官方 release 的解析缓存状态。 | | `parse.text_units` | 已实现 | `{ "offset": 0, "limit": 100, "destination": "*Table*", "archive_entry": "*.bytes", "path_id": 1, "class_id": 114, "field_path": "*Text*", "format": "json" }` | 当前官方 release 的 TextUnit 明细分页。 | | `parse.errors` | 已实现 | `{ "offset": 0, "limit": 100, "destination": "*Table*", "archive_entry": "*.bytes", "path_id": 1, "class_id": 114, "field_path": "*Text*", "format": "json" }` | 当前官方 release 的解析错误分页。 | | `translation.tasks` | 已实现 | `{ "offset": 0, "limit": 100, "task_id": "...", "release_id": "...", "destination": "...", "archive_entry": "...", "status": "skipped_parse_failed", "parse_status": "failed", "format": "json", "has_reason": true }` | 当前官方 release 的离线 TextUnit 翻译任务状态分页。 | | `translation.handoff` | 已实现 | `null` | 当前官方 release 的 job、unit、provider run 交接视图;动态合并队列和 SQLite worker 状态。 | | `translation.task.update` | 已实现 | `{ "task_id": "...", "status": "failed", "failure_reason": "...", "provider_run_id": "..." }` | 写入当前 release 的 provider worker 状态,返回可回查任务记录。 | | `translation.worker.run` | 已实现 | provider worker 参数 | 异步触发 Rust provider worker,返回 `{ "task_id": "...", "kind": "translation.worker.run", "worker": {...} }`。 | | `translation.proofread` | 已实现 | `null` | 将当前汉化 workflow 标记为人工校对中,返回工作流状态报告。 | | `translation.memory.summary` | 已实现 | 可选 `{ "translation_memory_path": "..." }` | 返回 TM persistence schema 版本、总记录数、candidate/trusted/rejected/superseded 状态计数和 trusted 冲突组计数。 | | `translation.memory.query` | 已实现 | `{ "source_text": "...", "source_context": {...}, "limit": 100 }` | 按 raw source 查询记录,返回 match kind、trust、translation 和 provenance;conflict 结果不可自动复用。 | | `translation.memory.confirm` | 已实现 | `{ "record_id": "...", "reviewer": "...", "reason": "...", "supersede_record_id": "..." }` | 显式确认 candidate 为 trusted;已有不同 current Trusted 时必须显式 supersede,worker 之后才可自动复用。 | | `translation.memory.conflicts` | 已实现 | 可选 `{ "translation_memory_path": "...", "limit": 100 }` | 只读列出 exact source/context 下存在多个 current Trusted 的冲突组。 | | `translation.memory.resolve_conflict` | 已实现 | `{ "winner_record_id": "...", "expected_trusted_record_ids": ["..."], "reviewer": "...", "reason": "..." }` | 使用稳定 record ID 原子解决历史 Trusted 冲突,保留 supersede 历史并写入 audit event。 | | `translation.glossary.summary` | 已实现 | 可选 `{ "glossary_path": "..." }` | 返回 Glossary schema 版本和 draft/approved/deprecated/rejected 计数;缺库只返回 `available=false`,不会创建空库。 | | `translation.glossary.query` | 已实现 | `{ "source_text": "...", "category": "...", "review_status": "approved", "limit": 100 }` | 查询 term、alias、scope、source provenance 和完整 source/review history。 | | `translation.glossary.diagnose` | 已实现 | `{ "source_text": "...", "context": {...} }` | 只对 approved term 生成 provider-neutral constraints,并返回冲突/覆盖诊断和 blocked 决策。 | | `translation.glossary.add` | 已实现 | Glossary term draft,包含 `term_id`、`source_term`、`recommended_translation`、`source` 等 | Rust 创建 draft/import term 并记录 source history。 | | `translation.glossary.update` | 已实现 | term draft + `reviewer`,可选 `reason` | Rust 替换 term definition,并记录 source/review history。 | | `translation.glossary.approve` | 已实现 | `{ "term_id": "...", "reviewer": "...", "reason": "..." }` | 将 term 明确置为 approved;只有 approved term 进入 worker/TM 自动流程。 | | `translation.glossary.deprecate` | 已实现 | `{ "term_id": "...", "reviewer": "...", "reason": "..." }` | 保留历史但停止自动应用。 | | `translation.glossary.delete` | 已实现 | `{ "term_id": "...", "reviewer": "...", "reason": "..." }` | 显式删除当前 term;需要 reviewer/reason,Rust 另保留删除审计快照,返回删除前快照。 | TM 的自动复用规则是 raw source 完全相同、完整 context 完全相同且状态为 `trusted`; context 缺失/不一致、normalized source 仅辅助查询、candidate 或 provider 成功都不会 自动复用或自动变成 trusted。TM 查询、confirm 和诊断由 Rust `bat` 持有,Go `bat-api` 不维护第二份 TM 状态。 `parse.status` 是只读查询;没有当前 release 或没有解析缓存时返回 `ok=true` 且 `data.available=false`。解析缓存来自官方原版资源目录,不读取 汉化输出目录。存在 `official-textunit-index.json` 时,响应会包含 `textunit_index_available=true`、`textunit_index_path` 和 `textunit_index_summary`;存在 `official-textunit-tasks.json` 时,响应会包含 `textunit_queue_available=true`、`textunit_task_queue_path` 和 `textunit_task_summary`。当 TextUnit 队列存在且有离线任务时, `translation_status_code=translation.queued_offline`;provider worker 完成任务后, 同一查询面会返回已落库的 worker 状态和 TextUnit 级译文结果。 `parse.text_units` / `parse.errors` 是只读查询;没有当前 release 或没有 `official-textunit-index.json` 时返回 `ok=true` 且 `data.available=false`。 分页参数 `offset` 默认 0,`limit` 默认 100,范围是 `1..=1000`。过滤参数: | 字段 | 类型 | 说明 | |---|---|---| | `destination` | string | official download manifest destination,支持 `*` 通配。 | | `archive_entry` | string | zip 内条目,支持 `*` 通配;直接 bundle 通常为 `null`。 | | `path_id` | integer | Unity object path id。 | | `class_id` | integer | Unity class id。 | | `field_path` | string | TypeTree/TextAsset 字段路径,支持 `*` 通配。 | | `format` | string | TextUnit 格式,例如 `json`、`csv`、`tsv`、`plain` 或 `typetree_string`。 | `parse.text_units` 的 `entries[]` 会包含 source text、source URL、 destination、archive entry、source kind、Unity version、serialized file、 path id、class id、field path、字段 offset/byte size、format、asset name 和 context。`parse.errors` 的 `entries[]` 会包含 source URL、destination、 archive entry、status、serialized file、path id、class id、field path、 offset 和 error。TypeTree-covered managed reference 字段会进入结构化字段遍历; 完整 managed reference registry 等暂不支持结构会进入解析错误,而不是静默降级为 低保真文本。 `translation.tasks` 优先查询当前 release 的 `translation-tasks.sqlite`,旧 release 没有该文件时回退到 `official-textunit-tasks.json`;用于查看离线 TextUnit 翻译任务候选和 provider worker 状态。没有当前 release 或没有任务队列时返回 `ok=true` 且 `data.available=false`。过滤参数包括 `task_id`、 `official_release_id`/`release_id`、`destination`、`path_pattern`、 `archive_entry`、`status`/`task_status`、`worker_status`、`parse_status`、 `text_unit_format`/`format`、`has_reason` 和 `has_failure_reason`。 `entries[]` 会包含 `official_release_id`、`destination`、`archive_entry`、 `parse_status`、队列 `status`、`task_status`、`failure_reason`、`attempt_count`、 `provider_run_id`、TextAsset/TextUnit 摘要和校验指纹。 `translation.task.update` 只更新当前 release 的 SQLite 状态库,不改写 immutable 队列文件,也不主动访问 Crowdin。`status` 支持 `queued`、`running`、`failed`、 `completed` 和 `skipped`;进入 `running` 会增加 attempt count,`completed` 会 记录完成时间,`failed` 可写入 `failure_reason`。人工校对流程可以在 `status=completed` 时额外提交 `provider`、`provider_run_id` 和 `translation_results[]`,每个结果必须包含 `unit_id`、`source_text` 和 `translated_text`;结果也可以提交完整的 `glossary_override`(`reviewer`、 `reason`、`provenance`、`confirmed_unix_seconds` 和当前 blocking QA 的 `qa_identity`),用于人工确认 Glossary blocking deviation。`qa_identity` 必须与 Rust 重新计算的当前 QA 完全相等;缺失或过期的 override 不授权。Rust 会用当前 `official-textunit-index.json` 校验 unit、 source text、destination 和 archive entry 后再落库。因此 worker 或人工校对流程 消费 handoff 后,bat-api 可通过 `translation.tasks` 查询单项任务,也可通过 `translation.handoff` 获取完整 job/unit/provider run 状态。`translation.handoff` 不会触发下载或 provider 网络请求;没有当前 release 或任务队列时返回 `data.available=false`。 `translation.worker.run` 通过 daemon 任务队列异步启动 Rust provider worker。 provider worker 会先同步当前 release 的 TextUnit 队列到 `translation-tasks.sqlite`,回收过期 lease,然后由 `concurrency` 个独立 worker 循环 claim 下一项任务;任一 worker 完成当前任务后会立即领取下一项,不等待 其他 worker 完成本轮批次。默认并发为 8,范围 `1..=256`。 provider worker 参数: | 字段 | 类型 | 默认 | 说明 | |---|---|---|---| | `provider` | string | `mock` | `mock` 或 `crowdin`。 | | `fixture_path` | string/null | `null` | mock provider fixture;别名为 `translation_fixture`、`provider_fixture`、`mock_fixture`、`fixture`。 | | `concurrency` | uint | `8` | 独立 worker 数,范围 `1..=256`;别名为 `worker_concurrency`、`translation_concurrency`。 | | `max_attempts` | uint | `3` | 单个任务最大 claim 次数,必须大于 0。 | | `lease_seconds` | uint | `300` | claim lease 秒数,必须大于 0。 | | `retry_backoff_seconds` | uint | `5` | 可重试 provider 失败的 next attempt 间隔,可为 0。 | | `max_tasks` | uint/null | `null` | 本轮最多 claim 的任务数,设置时必须大于 0。 | | `worker_id` | string | `bat-rpc-worker` | lease 诊断用 worker ID 前缀。 | | `translation_memory_path` | string/null | 按配置推导 | 覆盖 Rust worker 使用的项目级 TM 数据库路径;未指定时使用 worker 配置或 `/translation-memory.sqlite`。 | | `glossary_path` | string/null | 按配置推导 | 覆盖 Rust worker 使用的项目级 Glossary 数据库路径;未指定时使用 worker 配置或 `/glossary.sqlite`。存在 Glossary 但无法打开时 worker fail-closed,不自动绕过 QA。 | 数字字段必须是 JSON number;字符串数字、负数和越界值会返回 `BAT-ERR-700002`。`mock` provider 在没有 fixture 时把 source text 写成可诊断的 mock 译文;`crowdin` provider 从 `CROWDIN_PROJECT_ID`、`CROWDIN_LANGUAGE_ID`、 `CROWDIN_API_TOKEN` 读取配置,可选 `CROWDIN_API_BASE_URL` 和 `BAT_CURL`。 token 不会进入报告、任务记录或调试输出。 Glossary 只把 `approved` term 发送为 provider constraints。worker 会在 trusted TM 复用前、provider 返回后、人工 `translation.task.update` 和 workbench publish 前执行 同一套确定性 QA;冲突或未使用推荐/允许译法的结果不会自动完成或发布。允许但非推荐译法 产生 warning;blocking deviation 必须在对应结果中提交 `glossary_override`,并包含 `qa_identity`、`reviewer`、`reason`、`provenance` 和确认时间。Glossary 定义变化会 只使受影响 QA 的旧 override 失效;无关术语变化不会改变该 QA identity。系统不会在 译文生成后做静默字符串替换。 ### localized | 方法 | 状态 | params | data | |---|---|---|---| | `localized.status` | 已实现 | `null` | 汉化发布状态、当前官方 release 匹配关系和汉化输出目录。 | | `localized.publish` | 已实现 | `{ "translation_file": "...", "localized_release_id": "...", "force": false }`、`{ "from_worker": true, "localized_release_id": "...", "force": false }` 或 `{ "patch_manifest": "...", "localized_release_id": "...", "force": false }`;三者只能选一个 | 已校验并发布的汉化 release、generic/localized manifest 和完整性报告。 | | `localized.rollback` | 已实现 | `{ "localized_release_id": "..." }`,可省略 | 删除当前 release、恢复 manifest 记录的上一 release 和新状态。 | `localized.status` 严格按 daemon / `config.toml` 或环境变量中的 `BAT_LOCALIZED_OUTPUT` 或 `--localized-output` 查询汉化产物目录,不把 `./bat-resources` 与 `./bat-localized` 混用。当前支持未汉化发布状态和已汉化发布状态的只读报告。 `status` / `status_code` 使用生命周期短状态和稳定状态码,例如 `pending` / `localized.pending`、`stale` / `localized.stale`、`published` / `localized.published`、`localized.degraded`;旧的 `localized` / `not_localized` 业务标签放在 `localized_release_status`。`translation_workflow_status` / `translation_workflow_status_code` 用于表示汉化工作流的人工校对状态,例如 `manual_proofreading` / `translation.manual_proofreading`。返回 `localized_release_status=localized` 的条件是: `localized-version-state.json` 的官方 release ID 匹配当前官方 release, `current` symlink 指向汉化发布根下对应的 `versions/`,并且该版本目录中的 `localized-patch-manifest.json` 存在且 release ID 匹配。响应会返回 `patch_manifest_path`、`patch_manifest_available`、 `patch_manifest_matches_release`、`patch_manifest_contract_status`、 `patch_manifest_integrity_status`(兼容别名)、`artifact_integrity_status`、 `artifact_integrity_verified`、`artifact_integrity_error` 和 `artifact_integrity_diagnostics`、 `patch_manifest_source_version`、`patch_manifest_target_version`、 `patch_file_count`、`patch_operation_count`、`patch_kind_counts`、 `patch_text_asset_operation_count` 和 `rollback_previous_current_target`。 每个 localized patch operation 的 manifest metadata 记录发布时重新计算的 `glossary_qa`(包括 `qa_identity`)及对应 `glossary_override`,不会复用 workbench 中已经过期的 QA 快照。 `localized.publish` 也可直接接收由 Rust `bat-patch` 构建的 generic manifest。 Rust 会把其 source version 绑定当前官方 release,在独立 staging 中按 manifest 顺序执行 Binary、JSON、UTF-8 Text 和当前支持的 UnityFS TextAsset/TypeTree 字段 操作,并保留实际操作载荷、hash/size、定位信息和 TextUnit/TM/Glossary/review provenance。Go 只做鉴权、typed 参数校验和 RPC 转发。 ### catalog | 方法 | 状态 | params | data | |---|---|---|---| | `catalog.status` | 已实现 | `null` | 当前已发布 catalog 概览。 | | `catalog.versions` | 已实现 | `null` | current / in_progress / previous / failed。 | | `catalog.diff` | 已实现 | `null` | 当前 snapshot 相对上一可用版本的差异。 | | `catalog.refresh` | 已实现 | `{ "force": false }` | `{ "task_id": "...", "kind": "catalog.refresh" }`。 | 只读查询在没有可用版本时返回 `ok=true` 且 `data.available=false`。 `catalog.status` 可用时会返回 `status_code=official.published`,并用 `distribution_status_code=distribution.ready` 表示该官方 release 可被读侧分发; 不可用时对应 `official.unavailable` / `distribution.blocked`。 ### task | 方法 | 状态 | params | data | |---|---|---|---| | `task.status` | 已实现 | `{ "task_id": "..." }` | 单个任务记录。 | | `task.list` | 已实现 | `null` | `{ "tasks": [...] }`。 | | `task.cancel` | 已实现 | `{ "task_id": "..." }` | cancel ack。 | | `task.logs` | 已实现 | `{ "task_id": "..." }` | `{ "task_id": "...", "lines": [...] }`。 | | `task.create` | 保留 | object | 不开放通用任务入口;由语义方法创建任务。 | 任务记录: ```json { "id": "task-1234-1", "kind": "resource.repair", "status": "queued", "stage": null, "message": null, "created_at": 1780000000, "updated_at": 1780000000, "started_at": null, "finished_at": null, "error": null, "result": null } ``` `status` 取值:`queued`、`running`、`succeeded`、`failed`、`cancelled`。 daemon 重启后仍处于 `queued` 或 `running` 的历史任务会被标记为 `failed`,错误码为 `BAT-ERR-700005`。 ### patch / unityfs 已开放的文件级写入方法: - `patch.apply`:对显式 `source_path`、`patch_path`、`target_path` 执行 Binary/JSON/Text patch apply,`kind` 取值为 `binary`、`json` 或 `text`。 - `unityfs.patch_text_asset`:对显式 UnityFS `bundle_path` 中的 `serialized_file_path` / `path_id` TextAsset 应用 `replacement_path`,写入 `target_path`,可选 `expected_name`。 - `unityfs.patch_string_field`:对显式 UnityFS `bundle_path` 中的 `serialized_file_path` / `path_id` / `field_path` TypeTree string 字段应用 `replacement_text` 或 UTF-8 `replacement_path`,写入 `target_path`,可选 `expected_value`。 - `unityfs.patch_field`:对显式 UnityFS `bundle_path` 中的 `serialized_file_path` / `path_id` / `field_path` TypeTree 字段应用语义 `replacement` JSON,写入 `target_path`,可选 `expected_value`。`replacement` 使用 `{"kind":"signed","value":42}` 这类 tagged JSON;支持 `bool`、`signed`、`unsigned`、`float32`、`float64`、`string`、`bytes`、 `enum`、`bit_field`、`p_ptr`、固定 Unity 叶子结构、object 字段组合和 TypeTree schema 支撑的 array/map 整体替换。enum 形如 `{"kind":"enum","value":{"type_name":"ScenarioDifficulty","storage_type":"int","value":3}}`; `type_name` 是 TypeTree enum 类型名,`storage_type` 是 backing integer 类型。`LayerMask` / `BitField` 形如 `{"kind":"bit_field","value":{"type_name":"LayerMask","storage_type":"UInt32","bits":9}}`。 array 形如 `{"kind":"array","value":[{"kind":"string","value":"你好"}]}`;map entry 用 object 表达,例如 `{"kind":"object","value":[{"name":"first","value":{"kind":"string","value":"jp"}}]}`。 扩容时复用当前首个元素或 TypeTree data node 的编码 schema;map entry schema 变化、unknown 字段和未覆盖的 managed reference registry 变体仍会返回明确错误。 固定 Unity 叶子结构使用 raw bits/bytes 表达,例如 `{"kind":"float32_struct","value":{"type_name":"Vector3f","values":[1065353216,1073741824,1077936128]}}` 或 `{"kind":"fixed_bytes","value":{"type_name":"GUID","bytes":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]}}`。 这些方法同步执行,不进入 `task.*` 队列;输出文件使用临时文件原子写入,响应 `data` 会返回 source / patch 或 replacement / target 的 size 与 BLAKE3。`target_path` 不能与输入文件相同。 `localized.publish` 从当前官方 TextUnit/工作台生成受支持的 UnityFS patch operation;当 TextUnit 带有 `archive_entry` 时,发布 manifest 的 operation 会记录该可选字段,Rust 发布器会在独立 staging 中校验、重建内层 UnityFS 并 重写外层 ZIP。ZIP 路径、内层解析或重打包校验失败时整个发布失败,不会只发布 部分结果。 仍关闭的范围:通用 manifest 驱动的发布级 `patch build` / `patch rollback`、复杂 UnityFS 语义编辑、 `unityfs.inspect`、通用 manifest 驱动 release 切换。调用这些规划方法仍返回 `BAT-ERR-700003`。 CLI 对应关系: | CLI | RPC | |---|---| | `bat patch-apply` | `patch.apply` | | `bat unityfs-patch-text-asset` | `unityfs.patch_text_asset` | | `bat unityfs-patch-string-field` | `unityfs.patch_string_field` | | `bat unityfs-patch-field` | `unityfs.patch_field` | ## Go 调用边界 `bat-api` 应直接调用本 RPC contract,不通过 `exec` 调用 `bat` binary。 `bat` binary 是人类 CLI 和进程生命周期工具;默认 `refresh` / `repair` 在 daemon 可用时也会作为 RPC client 调用同一个 socket。`daemon.restart` 会启动 Rust lifecycle controller 复用同一套 CLI restart 路径,Go 层仍不直接 `exec` 或解析 `bat` stdout。 人类 CLI 的只读查询命令与 RPC 对应关系如下: | CLI | RPC | |---|---| | `bat parse-status` | `parse.status` | | `bat parse-text-units` | `parse.text_units` | | `bat parse-errors` | `parse.errors` | | `bat translation-tasks` | `translation.tasks` | | `bat translation-handoff` | `translation.handoff` | | `bat i18n task list` / `bat i18n task status` | `translation.tasks` | | `bat i18n task update` | `translation.task.update` | | `bat i18n worker run` | `translation.worker.run` | | `bat i18n proofread` | `translation.proofread` | | `bat i18n memory summary` / `bat i18n memory query` | `translation.memory.summary` / `translation.memory.query` | | `bat i18n memory confirm` / `bat i18n memory conflicts` | `translation.memory.confirm` / `translation.memory.conflicts` | | `bat i18n memory resolve-conflict` | `translation.memory.resolve_conflict` | | `bat i18n glossary summary` / `bat i18n glossary query` | `translation.glossary.summary` / `translation.glossary.query` | | `bat i18n glossary diagnose` | `translation.glossary.diagnose` | | `bat i18n glossary add/update` | `translation.glossary.add` / `translation.glossary.update` | | `bat i18n glossary approve/deprecate` | `translation.glossary.approve` / `translation.glossary.deprecate` | | `bat i18n glossary delete` | `translation.glossary.delete` | | `bat localized-status` | `localized.status` | | `bat resource-index` | `resource.index` | `bat translation-tasks` / `bat i18n tasks`、`bat translation-handoff` / `bat i18n handoff`、 `bat localized-status` / `bat i18n status` 都对应同一 RPC;这里列出的是推荐命令形态。 `bat resource-index` 支持 `--offset`、`--limit`、`--resource-type`、`--hash`、 `--path-pattern`、`--release-id`、`--platform`、`--destination`、 `--bundle-path`、`--archive-entry`、`--parse-status` 和 `--format`; 这些常用 metadata 过滤在 SQLite `ResourceRepository` 中下推执行。`bat doctor cas` 是本地只读 CLI 诊断入口,不对应 live RPC 方法;它读取 CLI 指定的 CAS 根目录和 元数据库路径,报告缺失或对象文件异常,且不会创建空库。 `bat parse-text-units` / `bat parse-errors` 支持 `--offset`、`--limit`、 `--destination`、`--path-pattern`、`--archive-entry`、`--path-id`、 `--class-id`、`--field-path` 和 `--format`;`bat translation-tasks` 支持 `--offset`、`--limit`、`--task-id`、`--release-id`、`--destination`、 `--path-pattern`、`--archive-entry`、`--task-status`、`--worker-status`、 `--parse-status`、`--format`、`--has-reason` 和 `--has-failure-reason`。这些过滤参数不适用于 `parse-status`、`translation-handoff` 或 `localized-status`。 ### Go 客户端表面 `internal/backendrpc.Client` 是 Unix socket JSON-RPC 传输客户端: - `Call` 可发送本文档中的任意已记录方法,并负责 JSON-RPC transport、 envelope 和 `ApiError` 解码;它不是 bat-api 的 HTTP 任意 RPC proxy。 - typed helper 已覆盖 daemon 已实现方法(`status/logs/stop/restart/reload/refresh/doctor`)、 `resource.state/sync/verify/repair/manifest/list`、`schedule.list/add/update/remove/run`、 `catalog.*`、`parse.*`、`release.status/list/distribution/cleanup`、 `localized.status`、`localized.publish`、`localized.rollback`、 `translation.tasks`、`translation.handoff`、`translation.task.update`、 `translation.worker.run`、`translation.proofread`、`translation.memory.summary`、 `translation.memory.query`、`translation.memory.confirm`、`translation.memory.conflicts`、 `translation.memory.resolve_conflict`、`translation.glossary.summary`、 `translation.glossary.query`、`translation.glossary.diagnose`、`translation.glossary.add`、 `translation.glossary.update`、`translation.glossary.approve`、`translation.glossary.deprecate`、 `translation.glossary.delete`、 `task.*` 和三个 `unityfs.patch_*` 方法。 - `resource.index` 和 `patch.apply` 当前没有专用 typed helper;需要直接使用 `Call`,并仍须遵守 本契约的参数和响应定义。 `internal/api` 对 bat-api 生产路径进一步收窄接口: | Go 接口 | 允许调用的 RPC | 用途 | |---|---|---| | `Backend` | `daemon.status`、`daemon.doctor`、`resource.state`、`catalog.status`、`release.attestation`、绑定后的 `resource.manifest` | 启动发现、周期刷新和资源分发基础数据 | | `AttestationBackend` | `release.attestation` | current official 轻量 health/publication proof;不触发历史 release 扫描 | | `ReleaseStatusBackend` | `release.status` | 鉴权管理面的 official/localized 重型 release 诊断;Go 不重新实现 verifier | | `ControlBackend` | `daemon.restart`、`daemon.reload`、`daemon.refresh`、`resource.sync`、`resource.verify`、`resource.repair`、`catalog.refresh` | 鉴权后的管理控制白名单 | | `ScheduleBackend` | `schedule.list`、`schedule.add`、`schedule.update`、`schedule.remove`、`schedule.run` | 鉴权后的 dashboard 调度计划控制 | | `DaemonLogsBackend` | `daemon.logs` | 鉴权后的 daemon 日志尾部查询 | | `TaskBackend` | `task.list`、`task.status`、`task.logs`、`task.cancel` | 鉴权后的 daemon 任务查询和取消 | | `ParseBackend` | `parse.status`、`parse.text_units`、`parse.errors` | 鉴权后的当前 release 解析状态、TextUnit 和解析错误只读查询 | | `TranslationBackend` | `translation.tasks`、`translation.handoff`、`translation.task.update`、`translation.worker.run`、`translation.proofread` | 鉴权后的 dashboard 翻译任务查询、交接视图、状态回写、provider worker 触发与人工校对标记 | | `TranslationMemoryBackend` | `translation.memory.summary`、`translation.memory.query`、`translation.memory.confirm`、`translation.memory.conflicts`、`translation.memory.resolve_conflict` | 鉴权后的 TM 摘要、source/context 查询和 Trusted 冲突治理;Go 只转发,不持有 TM 状态 | | `GlossaryBackend` | `translation.glossary.summary/query/diagnose/add/update/approve/deprecate/delete` | 鉴权后的 Glossary 摘要、term/history 查询、确定性诊断和审核/删除 mutation;Go 只转发,不持有 Glossary 状态 | | `LocalizedBackend` | `localized.status`、`localized.publish`、`localized.rollback` | 鉴权后的汉化 release 状态、发布与显式回滚 | | `ReleaseBackend` | `release.status`、`release.list`、`release.distribution`、`release.cleanup` | 鉴权后的双 release 查询、验证分发选择和 dry-run/execute cleanup;Go 不持有 release 状态 | `daemon.stop`、`daemon.clean-stable` 和任意通用 RPC 不属于 bat-api 管理控制面。 Rust dispatch、Go transport 和 bat-api 接口的权威实现位置分别是 `infrastructure/src/bin/bat/app.rs`、`internal/backendrpc/client.go` 和 `internal/api/rpc_release.go`;修改方法、字段或 allowlist 时必须同步更新本文档。 Go mirror contract fixture 固化在 `internal/api/testdata/contract/`,覆盖 `catalog.status` available/unavailable、`resource.manifest` page0、对应 `official-sync-snapshot.json`、Translation Memory query/缺库 mirror 和 Glossary query/source-history mirror。 这些 fixture/mirror 由 Rust 输出形状归一化而来,只用于 schema / mirror 回归;live daemon socket 和完整 fixture release 切换由 `make bat-api-local-live-smoke` 在同机 `/tmp` 隔离环境中验证。该 smoke 不替代 `make official-smoke` 的官方网络全量下载验证。 禁止事项: - Go 服务层不直接读写 `bat-status.json`、`bat-tasks.json` 等 daemon 内部状态文件。 - Go 服务层不扩展 `bat-ffi` 为主控制面。 - Go 服务层不通过 stdout 解析 `bat status --json` 作为常规调用路径。