# 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` | 已实现 | `{ "offset": 0, "limit": 100 }` | 当前 download manifest 分页。 | | `resource.list` | 已实现 | `{ "offset": 0, "limit": 100 }` | `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.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 由 `schema_migrations` 版本表管理。 - `translation-handoff.json`:当前 release 的版本化 job/unit/provider run 交接 快照;worker 更新后的实时状态仍以 `translation-tasks.sqlite` 为准。 删除资源只进入 `official-resource-changes.json`,不进入 Crowdin handoff。 ### 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 标记为人工校对中,返回工作流状态报告。 | `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`;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 前缀。 | 数字字段必须是 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 不会进入报告、任务记录或调试输出。 ### localized | 方法 | 状态 | params | data | |---|---|---|---| | `localized.status` | 已实现 | `null` | 汉化发布状态、当前官方 release 匹配关系和汉化输出目录。 | | `localized.publish` | 已实现 | `{ "translation_file": "...", "localized_release_id": "...", "force": false }` 或 `{ "from_worker": true, "localized_release_id": "...", "force": false }` | 已校验并发布的汉化 release、manifest 和完整性报告。 | | `localized.rollback` | 已实现 | `{ "localized_release_id": "..." }`,可省略 | 删除当前 release、恢复 manifest 记录的上一 release 和新状态。 | `localized.status` 严格按 daemon / `.env` 中的 `BAT_LOCALIZED_OUTPUT` 或 `--localized-output` 查询汉化产物目录,不把 `./bat-resources` 与 `./bat-localized` 混用。当前支持未汉化发布状态和已汉化发布状态的只读报告。 `status` / `status_code` 使用生命周期短状态和稳定状态码,例如 `pending` / `localized.pending`、`stale` / `localized.stale`、`published` / `localized.published`;旧的 `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_file_count`、 `patch_text_asset_operation_count` 和 `rollback_previous_current_target`。 ### 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` 不能与输入文件相同。 仍关闭的范围:通用 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 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.*`、 `localized.status`、`localized.publish`、`localized.rollback`、 `translation.tasks`、`translation.handoff`、`translation.task.update`、 `translation.worker.run`、`translation.proofread`、 `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`、`resource.manifest` | 启动发现、周期刷新和资源分发 | | `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 触发与人工校对标记 | | `LocalizedBackend` | `localized.status`、`localized.publish`、`localized.rollback` | 鉴权后的汉化 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`。这些 fixture 由 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` 作为常规调用路径。