nyaKazuha and Claude Fable 5
e9b7ce219f
fix(official-sync): 修正对抗性审查发现的 launcher 链错误码误归类
...
对 d2466d6 做三视角对抗性核查(错误码语义/消费者破坏面/测试与文档),
确认 8 项(去重后 5 类)误归类,全部集中在 official_game_main_config
的 From<String> 兜底面。逐项修正:
- launcher_package_url 改返回 DownloadError:非官方 CDN 根(来自远端
API 响应,安全边界拒绝)→ NON_OFFICIAL_URL;非法包路径(来自远端
manifest 内容)→ LAUNCHER_RESPONSE_INVALID。此前提交说明称其为
"硬编码常量上的内部不变量"不成立——三个生产调用点传入的都是远端
API 下发的 cdn_root。
- select_game_main_config_source / find_resources_assets:目录 source
缺 resources.assets 条目、无可用游戏包路径、包内容缺必需文件均为
远端可触发的内容缺陷 → LAUNCHER_RESPONSE_INVALID(此前落 INTERNAL,
且官方 manifest 布局已演进过一次,是现实的主要失败面)。
- extract_archive 解压失败 → ZIP_STRUCTURE_INVALID:结构校验不覆盖
压缩数据流,数据区损坏(bad CRC)在 unzip 阶段首次暴露,主导成因
是损坏/截断下载,归完整性域;本地原因保留在 stderr 消息中。
- verify_manifest_file_size 三种失败分码:size 字段无效 →
LAUNCHER_RESPONSE_INVALID、本地读文件失败 → INTERNAL、真正不符 →
SIZE_MISMATCH(此前三者统归 SIZE_MISMATCH)。
- 空 --launcher-version(用户 CLI 输入)→ INVALID_ARGUMENT,在发起
任何请求前拒绝(此前落 INTERNAL)。
- 统一 launcher 链内容口径:API 响应、远端 manifest、包内容的解析/
缺失问题全部归 LAUNCHER_RESPONSE_INVALID(600004),
MANIFEST_PARSE_FAILED(600001) 保留给资源侧 manifest/catalog;
fetch_remote_manifest 两处 600001 改 600004,error_code.rs 注释与
USERGUIDE 描述同步。
- download_file_with_fallback:备用 URL 构造失败不再经 `?` 丢弃主地址
失败上下文,错误码与"两次都失败以最终一次为准"策略一致。
新增 7 个错误码断言测试(launcher_package_url 两类拒绝、空版本、
manifest 无条目、fallback 终码保留、fallback 构造失败保留主上下文、
select/verify/extract 各失败面)。全量 fmt / clippy --workspace
--all-targets -D warnings / test --workspace 全绿。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 09:42:17 -07:00
nyaKazuha and Claude Fable 5
d2466d60db
feat(official-sync): 错误码模型铺开到 launcher/metadata 拉取路径
...
此前统一错误码只覆盖资源下载路径,launcher/metadata 链
(fetch_game_config → manifest URL → remote manifest → resources.assets
→ GameMainConfig)整条返回 Result<_, String>,经 anyhow::Error::msg
抹成无类型消息,RPC/任务层只能标为 internal。
本次将该链整体改为 Result<_, DownloadError>:
- core 新增两个错误码:LAUNCHER_API_REJECTED(300031,官方启动器 API
返回非 200 业务码)与 LAUNCHER_RESPONSE_INVALID(600004,响应无法
解析或缺少必需字段),并纳入唯一性测试;
- official_launcher:curl 失败保留准确网络域码(403/404/DNS/超时/TLS/
代理等,final_error_code()),API 非 200 → LAUNCHER_API_REJECTED,
响应解析/缺字段 → LAUNCHER_RESPONSE_INVALID,非官方 manifest URL →
NON_OFFICIAL_URL,manifest 无文件条目 → MANIFEST_PARSE_FAILED,
空版本/路径入参 → INVALID_ARGUMENT;
- official_game_main_config:下载失败带网络域码(主/备 CDN 均失败时
以最终一次为准),ZIP 结构 → ZIP_STRUCTURE_INVALID,manifest 大小
不符 → SIZE_MISMATCH,GameMainConfig 解密/解析 →
GAME_MAIN_CONFIG_FAILED,manifest 缺 source →
LAUNCHER_RESPONSE_INVALID;
- official_update 两处调用改 anyhow::Error::msg → anyhow::Error::new,
保留类型,task worker 现有 downcast 直接接住 launcher 路径错误码;
- USERGUIDE 错误码表补录 300031 与 600004。
内部工具函数(launcher_package_url / launcher_api_url /
launcher_authorization_header)仍返回 String,经 From<String> 归
INTERNAL——这些是硬编码常量上的内部不变量校验,非运行时主要失败面。
验证:新增 4 个单测断言映射(API 403 业务码 → 300031、非法 JSON →
600004、HTTP 404 → 300002、非官方 URL → 300030);全量
fmt / clippy --workspace --all-targets -D warnings / test --workspace
全绿(含 examples 编译)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 08:29:16 -07:00
nyaKazuha and Claude Opus 4.8
d4d6d0a686
fix(curl): 将 ETXTBSY 归为可重试的瞬时启动失败
...
启动 curl 子进程时命中的 ETXTBSY(可执行文件忙)是多线程程序里
fork/exec 与"刚写出的可执行文件"之间的瞬时竞态:另一线程 fork 出的
子进程在 fork 与 execve 之间短暂持有目标文件的可写句柄,导致本次
exec 被内核判为忙。此前它被并入 ProcessFailed 且 retryable=false,
per-URL 层直接放弃。
新增 CurlFailureKind::ProcessBusy(retryable=true),在 process_failed
中按 io::ErrorKind::ExecutableFileBusy 精确识别,并在 busy 重试前做
极短退避让兄弟进程完成 execve。生产中 curl 是固定系统二进制、从不
被并发改写,故此变更对真实下载无影响,仅消除集成测试在高并发下偶发的
"Text file busy" flake(fetch_bootstrap unwrap 失败)。
验证:以 8-10 并发 worker × 8 线程 / 4 核(≈64-80 线程超载)复现,
修复前首轮即挂;修复后 200+ 次超压运行零 ETXTBSY、零失败。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-17 07:30:20 -07:00
nyaKazuha and Claude Fable 5
ab11cc899d
feat(official-sync): 下载失败携带类型化错误码
...
用类型化错误(不做 message 匹配)把资源下载失败归到准确的 BAT-ERR 码:
- curl_transfer:CurlFailureKind::error_code() 映射到网络域码(403→300001、
404→300002、5xx→300005、dns/connect/timeout/tls/interrupted→30001x、
proxy→310001、其余→300015);CurlRetryError::final_error_code() 取末次失败的码。
- official_download:新增 pub DownloadError { code, message },From<String>→internal,
Display/Error;pull_* 的返回类型由 String 改为 DownloadError,内部 String 错误经
From 归 internal,下载失败边界带 pull_one 的 error_code(),非官方 URL 带
non_official_url(300030)。
- official_update:pull 错误改用 anyhow::Error::new 保留 DownloadError 类型。
- 任务 worker:downcast DownloadError 取 code 写入任务记录的 error(失败不再一律
900001),非下载失败仍归 internal。
验证:新增 kind→code 映射单测;pull 404 测试断言 DownloadError.code()==HTTP_NOT_FOUND;
lib/core 全量测试通过,clippy --all-targets 干净。
范围说明:本次覆盖资源下载路径;launcher/metadata 拉取(official_launcher)的网络
失败仍归 internal,可按同一模式后续接入。
对应 issue #1(错误码细分映射,第一批)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 07:01:31 -07:00
nyaKazuha and Claude Fable 5
9a5fef23af
feat(daemon): 补全 task.cancel 与 task.logs
...
完成 task.* 命名空间:
- task.cancel:每个任务带共享的取消标志(Arc<AtomicBool>),worker 的 should_cancel
同时检查它和 daemon 停止标志;请求取消后置标志,worker 在下一个同步检查点中止,
任务转为 cancelled(协作式,不硬杀正在执行的 curl)。已结束任务返回 already-finished,
不存在返回 700004。
- task.logs:worker 把每条 progress 追加到任务的有界日志(上限 200 行),task.logs
返回该历史;不存在返回 700004。TaskRecord 的 cancel/log 字段 serde(skip),不进
task.status 输出。
- 新增 cancelled 任务状态;prune 与已结束判定纳入 cancelled。
- USERGUIDE RPC 方法表更新(cancel/logs 标为已实现)。
验证:新增取消/日志注册表单测(63 bin 测试全过);真机端到端确认触发 resource.sync
后 task.cancel 使任务转为 cancelled、task.logs 返回进度历史。
对应 issue #1(task.* 命名空间补全)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 06:00:26 -07:00
nyaKazuha and Claude Fable 5
d7257db447
docs(userguide): 增加 Daemon RPC 接口章节
...
记录 bat.sock JSON-RPC 2.0 控制面:统一 envelope(ok/status/data/error/request_id)、
方法命名空间与实现状态(daemon.*/resource.*/task.* 已实现,catalog/patch/unityfs
及 task.cancel/logs 返回 700003)、异步任务模型(resource.sync/verify 返回 task_id、
task.status/list 轮询)和调用示例。
对应 issue #1(协议文档)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 05:31:57 -07:00
nyaKazuha and Claude Fable 5
01ea5d8fa5
feat(daemon): 任务执行器 + 异步 resource.sync/verify(阶段 1b)
...
在 daemon 里加入任务模型,让 resource.sync/verify 经 RPC 触发即返回 task_id、
可轮询进度与最终结果:
- 专用任务 worker 线程 + FIFO 队列(mpsc);TaskRegistry 句柄包住内存态注册表
(HashMap,有界保留 64 条已结束任务,运行中/排队中不裁剪),方法访问便于将来
换 Redis 等持久化后端。
- 进程内 sync 锁:watch 循环与 worker 在跑同步前都获取它,互相等待而非撞
.official-sync.lock 文件锁失败;只在实际跑同步的那段持锁,空闲睡眠不持锁。
- resource.sync/resource.verify 入队返回 { task_id, kind }(envelope status=accepted);
worker 复用 run_with_progress_and_cancellation(sync 用 daemon config + force;
verify 用 dry-run+plan+audit),进度写入任务记录,should_cancel 接 daemon 停止标志
(停机中止在途任务)。task.status/task.list 从注册表读真实数据。
验证:新增任务分发/入队/注册表单测(62 bin 测试全过);真机端到端确认经裸 socket
触发 resource.sync 返回 task_id、轮询 task.status 走到最终态(fake curl 失败→
failed 且记录 error)、task.list 可见、resource.verify 亦入队。满足 issue #1 验收
「至少一个同步任务可经 RPC 触发并经 task.status 查询进度和最终结果」。
任务仅存内存(随 daemon 生死);task.cancel/logs、错误码细分映射留待后续。
对应 issue #1(任务模型 + 最小方法集打通)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 05:23:24 -07:00
nyaKazuha and Claude Fable 5
b95a3ac417
feat(daemon): RPC 统一 envelope、命名空间分发与只读方法
...
阶段 1a 的协议地基(承接错误码模型):
- 统一 envelope:所有响应装入 JSON-RPC 2.0 result 的
{ ok, status, data, error, request_id };error 用 bat_core::ApiError
(含 BAT-ERR 码/kind/domain/location/retryable)。传输层解析失败仍走
JSON-RPC 顶层 error。request_id 为 req-<pid>-<seq>。
- 命名空间分发:方法改用国际惯例 <namespace>.<action>;daemon.* 为规范名,
bat.* 保留为兼容别名(canonical_rpc_method 解析)。未知方法 → 700001,
已规划未实现(resource.sync/verify、catalog.*/patch.*/unityfs.* 等)→ 700003。
- 只读方法:daemon.status/logs/stop/reload/refresh(迁移)、resource.state(新增,
返回资源发布根 + 版本状态 + 上次同步结果)、task.status/task.list(任务库暂空,
status → 700004,list → 空列表;执行器留待阶段 1b)。
- 客户端 daemon_rpc_call 解包 envelope(检查 ok、返回 data、把 error 转 Err),
CLI 调用方零改动。
验证:新增分发/别名/envelope 单测(60 bin 测试全过);真机起停 daemon 端到端确认
daemon.status/logs/resource.state/task.list 经 CLI 与裸 socket 均正确返回 envelope,
bat.* 别名生效,未知/未实现返回对应 BAT-ERR 码。
对应 issue #1(协议基础设施 + 最小只读方法集)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 04:19:22 -07:00
nyaKazuha and Claude Fable 5
1a25ea58dd
feat(core): 引入统一错误码模型并新增 USERGUIDE
...
为 issue #1 的公共错误契约建立错误码模型:
- core/src/error_code.rs:ErrorCode(BAT-ERR-<域3位><序号3位>,如 BAT-ERR-300012)
+ 44 个初始码表(覆盖输入/路径安全/网络下载/校验/发布存储/解析/任务RPC/内部
八域,网络域含代理故障 310001)、ErrorDomain、以及进入 RPC envelope / --json /
bat-events.jsonl 的统一 ApiError { code, kind, domain, location, message, retryable }。
location 用稳定的组件·操作标签(不随行号漂移)。
- 新增 USERGUIDE.md:bat 命令、选项(发现/同步/守护/输出)、退出码(含 75=locked)、
运行时默认值,以及从码表同步的错误码参考(含承载结构与域一览)。
命名遵循国际惯例(英文 kind/domain slug)。码表以 error_code.rs 为准,USERGUIDE
错误码表与之逐条一致。后续各链路报错接入该码表在 issue #1 下推进。
对应 issue #1(错误码模型 + 用户指南)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 03:57:17 -07:00
nyaKazuha and Claude Fable 5
17b86ab9fa
docs: 修正文档漂移,与当前实现和 G-018 状态对齐
...
- PROJECT_PLAN:"真实官方网络 smoke 尚未记录/未完成记录" 与 G-018 已关闭矛盾,
改为"命令已固化(G-018 已关闭),真实运行处于长期运行测试阶段、报告待后续提供"。
- PROJECT_PLAN §6 标题"近期 10 个具体任务"实列 8 条,去掉误导性数字。
- official-resource-test-pull.md 重复的 "## 8" 编号(代码入口/验证)修正为 8/9。
- CURRENT_GAPS G-008 "cmd/bat 无 main.go" 已过时(main.go 存在但为 cgo 最小
骨架、非产品入口),更正现象描述。
对应 issue #18 维护清单 4-1、4-2、4-3、4-4。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 10:04:09 -07:00
nyaKazuha and Claude Fable 5
232d74b617
fix(daemon): 串行化 bat-status.json 的读-改-写
...
watch 循环线程(update_daemon_status/update_daemon_progress)与 RPC 处理线程
(update_daemon_state_only)都会对状态文件做“读→改字段→写回”。单次写虽原子,
但整段读-改-写非原子,无互斥时并发线程会 last-writer-wins 丢失对方的字段更新。
新增进程级 DAEMON_STATUS_FILE_LOCK,三处读-改-写函数入口统一获取该锁串行化
(锁中毒时取 into_inner 继续,不 panic)。
对应 issue #18 维护清单 3-4。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 09:38:46 -07:00
nyaKazuha and Claude Fable 5
0656ad05c7
refactor(official-sync): CLI 工程卫生清理
...
- doctor daemon_status 检查(3-3):ok 与 message 原分别取自解析结果和文件存在性,
文件存在但解析失败时会“ok=false 却提示可解析”。改为从同一次解析结果派生两者。
- localize_error_message(3-1a):空壳直通占位函数,删除并在 4 处调用点直接用消息。
- daemon 路径 helper 形参(3-1b):output_root 实际语义是 state_dir,统一改名消除误导。
- stop_daemon 非 RPC 路径(3-1c):删除无意义的 let-else(_pid 读后丢弃、两分支
逐字重复 stop_daemon_inner+print_report),stop_daemon_inner 内已做 PID 校验。
- parse_http_status(3-1d):改为锚定 curl stderr 中 "error" 之后再取三位状态码,
避免误取端口/字节数等无关三位数字;新增锚定测试。
- 非 Unix process_exists(3-1e):补注释说明保守返回 true 的理由(无法探测存活,
避免误回收可能仍在运行的 daemon)。
对应 issue #18 维护清单 3-1、3-3。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 09:35:31 -07:00
nyaKazuha and Claude Fable 5
28e9ce5a6f
refactor(official-sync): 删除误导性的 skipped_this_run 字段并修正措辞
...
quarantine 条目的 skipped_this_run 字段恒写 true、仅测试读取、不参与任何逻辑,
且名称误导——下载失败是 fail-fast 中止整轮,并非“跳过该 URL 继续”。删除该字段,
并把失败消息中的“跳过本轮”改为“中止本轮同步、不发布不完整资源”以消除歧义。
(quarantine 为瞬时状态文件且未启用 deny_unknown_fields,旧文件多出的键会被忽略。)
对应 issue #18 维护清单 3-2。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 09:21:16 -07:00
nyaKazuha and Claude Fable 5
11f4c6c36e
test(adapters): 真实 resources.assets 测试改用环境变量注入
...
reads_text_asset_from_real_resource_file 原硬编码 /home/wanye 绝对路径,文件
不存在时静默 return——在其它机器/CI 上是永远跳过、从不断言的死测试。改为
#[ignore] + BAT_REAL_RESOURCES_ASSETS 环境变量注入(与仓库既有 real_* 测试一致),
并把机器特定的精确字节 golden 断言放宽为结构性断言(name 匹配、bytes 非空),
便于任意真实 resources.assets 显式运行。
对应 issue #18 维护清单 3-5。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 09:16:07 -07:00
nyaKazuha and Claude Fable 5
fd86eafebd
chore(deps): 移除占位 crate 中零引用的依赖
...
bat-patch 的 bsdiff/json-patch、bat-assetbundle 的 byteorder/lz4/lzma-rs 在
源码中完全未使用,占位阶段白增编译负担。移除并留注释说明待对应引擎/解析器真正
实现时再按需引入。
对应 issue #18 维护清单 3-6。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 09:12:40 -07:00
nyaKazuha and Claude Fable 5
48ffc08cdf
fix(cas): exists 返回 Result 以区分不存在与存储故障
...
CasRepository::exists(core trait)与底层 Storage::exists 原返回裸 bool,
FileSystemStorage 用 try_exists(...).unwrap_or(false)、infra 适配层吞掉解析/
初始化错误返回 false,调用方无法区分“对象不存在”和权限/IO/初始化故障。
将整条链改为 Result<bool>:
- storage trait 与 FileSystemStorage:try_exists 的 IO 错误经 ? 传播;
- repository FileSystemCasRepository::exists 及 store/add_reference 内部调用;
- core CasRepository::exists trait;
- infra 适配层:解析失败→InvalidArgument、初始化/引擎错误经 map_error 传播。
Ok(false) 仅表示确实不存在。
新增单测:合法但不存在的对象返回 Ok(false),非法 ObjectId 返回 Err(而非静默
false);同步更新各层 exists 断言。
对应 issue #18 维护清单 2-1。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 08:53:54 -07:00
nyaKazuha and Claude Fable 5
c362fd80f4
fix(import): 导入失败回滚,find_bundle 拒绝同名歧义
...
- 非事务导入:import_manifest_bundles 中途某条目失败(如 AssetBundle 解析失败)
时,之前已写入的 CAS 对象和 ResourceRepository 行不回滚,留下部分导入状态。
改为记录本次写入的 object_id 与资源 id,任一条目失败时 best-effort 回滚
(删除资源行、对 store 增加的引用逐一 remove_reference)。
- find_bundle 跨目录同名:文件名回退无目录约束,jp/data.bundle 与 en/data.bundle
同名时可能静默取错数据。改为返回 Result:精确路径优先,文件名回退仅在唯一匹配
时采用,多个同名 bundle 时显式报错而非猜测。
新增单测:后续条目失败时回滚先前成功条目(资源行清空、CAS 引用回滚为 0)、
同名 bundle 歧义显式报错。
对应 issue #18 维护清单 2-2。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 08:29:27 -07:00
nyaKazuha and Claude Fable 5
b570f37359
fix(official-sync): 区分代理故障并前置校验代理配置
...
- 代理故障分类:curl 因代理 407 认证失败(CONNECT 隧道失败)、无法解析/连接
代理等,原被归为普通可重试网络错误,永不成功也会耗尽 per-URL 重试且无诊断。
新增 CurlFailureKind::Proxy,从 curl stderr 识别代理故障,per-URL 层 fail-fast
不重试(daemon error-retry 循环仍整体重试以覆盖代理短暂抖动),并在失败摘要里
以 kind=proxy 明确标注。
- 前置校验:parse_proxy_config 新增 validate_proxy_url,拒绝拼错的代理 scheme
(如 htp://),只接受 http/https/socks4/socks4a/socks5/socks5h 或无 scheme
的 host:port。
- doctor:proxy 检查不再恒 ok,对解析出的代理 URL(含 auto 从环境变量取得的)
做 scheme 校验,前置暴露配置错误。
新增单测:代理 407/解析失败归为 Proxy 且不重试、源站连接失败仍为 Connect 可重试、
拒绝不支持的 scheme、无 scheme host:port 接受。
对应 issue #18 维护清单 2-5。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 08:18:37 -07:00
nyaKazuha and Claude Fable 5
f0fbe65429
fix(official-sync): 复用 staging 异常时退化为全量重下而非中止
...
recoverable_staging_path 对「staging 存在但不可用」(被外部替换成文件/symlink、
路径组件含 symlink、id 不匹配、路径逃逸等)一律返回 Err,经调用方 ? 中止整轮
同步。失败记录残留时每轮都会撞到同一异常而永久失败、无法自愈。
改为返回 Option<PathBuf>:任何无法安全复用的情况返回 None,走全量重下(始终安全
的 fail-closed 回退,复用文件仍逐一校验,不会发布损坏内容)。新增单测:staging
被替换成普通文件时不复用、返回 None 而非 Err。
对应 issue #18 维护清单 2-6。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 08:08:12 -07:00
nyaKazuha and Claude Fable 5
42d69dd4bd
fix(official-sync): 拒绝携带 query/fragment 的资源 URL
...
destination_for_url 原来对每个路径片段静默剥除 query/fragment,导致仅 query
不同的两个官方 URL 映射到同一目标文件而相互覆盖,并使每轮 hash 复用校验失配、
反复重下。官方资源 URL 本不携带 query(发现 URL 由固定拼接生成),改为直接拒绝,
消除该碰撞路径。新增单测。
对应 issue #18 维护清单 2-3。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 08:03:40 -07:00
nyaKazuha and Claude Fable 5
02d5bc537e
fix(patch): 占位函数返回未实现错误而非空结果
...
apply_patch / apply_json_patch 原返回 Ok(空 Vec/空 String),调用方会把未实现
的占位误当成一次成功的补丁应用。改为返回 PatchError::ApplyFailed,让占位状态
显式可见。新增单测确认返回错误。
对应 issue #18 维护清单 2-4。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 08:00:31 -07:00
nyaKazuha and Claude Fable 5
962261ba12
fix(ffi): 统一 cgo 链接与 release 构建 profile
...
internal/ffi/ffi.go 的 cgo LDFLAGS 硬编码 -L target/debug,而 build-rust 用
--release(产物落 target/release),干净环境下 make build/test-go/ci 必然
报 cannot find -lbat_ffi。
- LDFLAGS 指向 target/release,并加 -Wl,-rpath 让产物运行时无需 LD_LIBRARY_PATH
即可定位 libbat_ffi.so;删除指向不存在目录的无效 CFLAGS -I(C 声明本就内联)。
- 新增 build-ffi target(cargo build --release -p bat-ffi),build-go 与 test-go
依赖它,确保链接前 release FFI 库已存在。
验证:make build-go 成功产出并可运行 bin/bat;make test-go 链接并通过;
go vet(check-go)通过。
对应 issue #18 维护清单 1-6。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 07:46:37 -07:00
nyaKazuha and Claude Fable 5
1c4debbaa7
fix(cas): 消除 store/gc 之间的引用计数竞态
...
store() 原来先 ensure_object(建行 ref_count=0)再 add_reference,两条语句
非事务;即使连接池 max_connections=1,两语句间的 await 也会释放连接,让并发
gc() 在 ref_count=0 窗口删掉刚存的对象文件与元数据(静默丢数据),或使 store
返回 ObjectNotFound。
- 新增 store_reference:单条 UPSERT 原子建行为 ref_count=1 或 +1,对象行不再
出现 ref_count=0 的可见窗口;store() 与 repository add_reference() 均改用它。
- 新增 delete_zero_ref_metadata:gc 先原子执行 DELETE ... WHERE ref_count=0,
仅当 rows_affected>0 才删对象文件;被并发递增抢先时跳过,绝不删除仍被引用对象。
元数据先删、文件后删,最坏只留无元数据的孤儿文件(可覆盖,无数据丢失)。
新增单测:store 后不暴露 ref_count=0(gc_candidates 为空)、候选被重新引用后
gc 跳过、store_reference 原子建行/递增、delete_zero_ref_metadata 守卫。
对应 issue #18 维护清单 1-5。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 07:39:07 -07:00
nyaKazuha and Claude Fable 5
3cb3637749
fix(official-sync): 清理未被引用的孤儿 staging 目录
...
同版本失败 staging 复用已由 060b7d7 处理,但跨版本失败、或被 trim/去重挤出
failed_versions 记录后残留的 .staging/<id> 目录永不被复用也无人清理,长期 daemon
场景下多 GB 孤儿目录会累积耗尽磁盘。
新增 gc_orphan_staging:枚举 .staging 下子目录,只保留 in_progress_version 与
failed_versions 引用的 <id>,删除其余(跳过普通文件与 symlink,staging 根不存在
时无操作)。在同步成功发布后(读取最新版本状态)和 clean-stable(后台已停止)两处
调用;GC 失败仅告警,不影响发布结果。
对应 issue #18 维护清单 1-4。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 07:29:37 -07:00
nyaKazuha and Claude Fable 5
4d818f512c
fix(official-sync): 发布成功后立即提交版本状态事务
...
publish() 切换 current symlink 后,写最终 snapshot 或 complete_version_state
若失败会经 ? 提前返回,此时 VersionStateGuard 尚未 commit,其 Drop 会把这个
磁盘上已发布(current 已指向)的版本记入 failed_versions,造成状态与磁盘不一致。
改为在 publish() 成功后立即取出完成记录并 commit 版本状态事务,随后 snapshot
与 version-state 写入失败降级为可下轮重试的警告(不再 ? 中断、不再误记 failed);
snapshot_written 也改为仅在实际写入成功时置 Some。
对应 issue #18 维护清单 1-3。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 07:17:51 -07:00
nyaKazuha and Claude Fable 5
4c123b9560
docs(official-sync): 推荐环境变量配置代理并同步凭据处理说明
...
- official-resource-test-pull.md §0.1:新增"带凭据代理优先用 HTTPS_PROXY 环境
变量"推荐(含 systemd EnvironmentFile 0600 用法),补充凭据处理说明——日志/
status 脱敏、经 ALL_PROXY 环境变量传 curl、daemon 经环境变量下传、bat-proxy.secret
复用与 clean-stable 清除;修正旧表述"代理参数写入后台子进程启动参数"。
- official-resource-backend.md 第 13 条:把"仅日志脱敏"扩写为全链路凭据不落
世界可读位置。
- CURRENT_STATUS.md 第 7 条:同步上述凭据处理描述。
- deployments/systemd/official-sync.env.example:新增注释版 HTTPS_PROXY/NO_PROXY
示例,并提示含凭据时按 0600 安装。
- CHANGELOG:新增"修复"(Unity 版本数值比较)与"安全"(代理凭据不落世界可读
位置)条目。
对应 issue #18 维护清单 1-1 / 1-2。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 06:58:11 -07:00
nyaKazuha and Claude Fable 5
565fd317de
fix(official-sync): curl 代理改由环境变量传入,堵住 argv 泄漏
...
apply_curl_proxy 原来对 URL 型代理执行 command.arg("--proxy").arg(url),
把可能含凭据的代理 URL 放进 curl 子进程 argv,会出现在 curl 进程的
/proc/<pid>/cmdline(0444,世界可读,每次下载存活期间可被本地任意用户读到)。
改为先 remove_proxy_env 清除所有继承的代理变量,再通过 ALL_PROXY/all_proxy
环境变量把代理传给 curl(大小写两种写法都设,避免 curl 只读其一)。凭据从
世界可读的 cmdline 转移到仅属主可读的 /proc/<pid>/environ(0400)。no_proxy
列表不含凭据,仍以 --noproxy 参数传入;disabled 模式保持 --noproxy * 直连。
至此代理凭据泄漏面全部堵住:daemon 子进程 argv、0600 状态文件(55b9bab),
以及本次的 curl 孙进程 argv。
验证:
- 新增单测用 Command::get_args/get_envs 断言 URL 只进 ALL_PROXY 环境变量、
不进 argv,且 scheme 专用变量被清除;disabled 模式强制直连。
- 真机经本地混合代理 127.0.0.1:7897 端到端验证:curl shim 记录 11 次调用,
凭据 0 次进 argv、0 个 --proxy 参数,代理仅在 ALL_PROXY 环境变量中;curl
确实经该代理到达官方 launcher/CDN/resources.assets 端点,功能未回归。
- 对抗性审查确认 auto/disabled/no_proxy 语义与旧 --proxy 等价,env 先删后设
最终为 set,无其它遗漏的凭据落 argv/日志/状态文件路径。
对应 issue #18 维护清单 1-2 残留项(curl 子进程)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 06:44:03 -07:00
nyaKazuha and Claude Fable 5
55b9babb66
fix(official-sync): 代理凭据改由环境变量下传子进程
...
彻底收敛 1-2 的两处残留凭据暴露:
- 子进程 argv:daemon_child_args 不再把 --proxy <url> 写入子进程参数,改为
只放不含凭据的内部 flag --proxy-from-env,真实 URL 经 BAT_OFFICIAL_SYNC_PROXY_URL
环境变量下传。凭据从世界可读的 /proc/<pid>/cmdline(0444)转移到仅属主可读的
/proc/<pid>/environ(0400);子进程解析后立即 env::remove_var,避免被 curl 等
孙进程继承。
- 状态文件 at-rest:0600 状态文件的 command 字段不再含凭据。restart/reload 复用
所需的 URL 改存专用 0600 文件 bat-proxy.secret,该文件永不进入状态输出或 --json;
clean-stable 会在后台停止后清除它。
复用型 restart/reload 从 bat-proxy.secret 还原代理;凭据文件缺失时(如 clean-stable
后)明确报错要求重新传入 --proxy,而非静默丢弃代理。
验证:新增 curl_proxy_url、secret 文件 0600 往返、--proxy-from-env 读取并清除
环境变量的单测;真机起停 daemon 确认凭据不在 cmdline/状态文件/status --json,
仅在 0600 secret 文件与 owner-only environ;复用 restart 成功还原、clean-stable
后复用 restart 明确报错。
对应 issue #18 维护清单 1-2 残留项。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 05:20:22 -07:00
nyaKazuha and Claude Fable 5
810b39c2cd
fix(official-sync): 修复阻塞 clippy 门禁的两处告警
...
cargo clippy --workspace -- -D warnings 在 HEAD 上失败,阻塞项目验证门禁:
- resolve_bootstrap 因 c123f6c 新增 curl_proxy 参数达到 8 个,触发
too_many_arguments。将 curl_command/curl_proxy/unzip_command 收拢为
BootstrapTools 结构体,降到 6 个参数。
- visible_historical_failed_versions(169822a 引入)的显式生命周期可省略,
触发 needless_lifetimes。按 clippy 建议省略。
对应 issue #18 维护清单 1-7。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 04:40:35 -07:00
nyaKazuha and Claude Fable 5
eef8c52497
fix(official-sync): 脱敏代理凭据避免泄漏到日志与状态输出
...
两处代理凭据泄漏:
- redact_proxy_url 对无 scheme 的代理串(user:secret@host:port,curl 默认按
http 处理)完全不脱敏,明文凭据会进入 progress 事件、daemon 日志和
bat-events.jsonl。现对无 scheme 但含 userinfo 的情况一并脱敏。
- daemon 保存的 command 含原始代理 URL,经 RPC status 和 bat status --json
回显到 stdout(会被监控采集)。新增 redact_command_proxy_credentials,在
build_daemon_status_report 的对外拷贝里脱敏 --proxy 值;磁盘状态文件
(0600)仍保留原始 command 供 restart/reload 复用。
残留:子进程 argv 仍可经 /proc/<pid>/cmdline 读到代理凭据,以及 0600 状态
文件内的 at-rest 凭据,二者受进程属主与文件权限约束,后续可改由环境变量下
传子进程进一步收敛。
对应 issue #18 维护清单 1-2。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-16 04:31:10 -07:00
nyaKazuha and Claude Fable 5
7c2f6824a6
fix(adapters): 按数值比较 Unity 版本范围
...
VersionRange::contains 原为字符串字典序比较,2021.3.9f1 等带发布后缀的
正式版本会被 can_handle/parse 误拒,多位补丁号排序也不正确。改为解析
(major, minor, patch) 数值元组比较,补丁号剥离发布后缀,无法解析的版本
一律视为不在范围内,并补充多位补丁号、后缀版本和畸形版本的测试。
对应 issue #18 维护清单 1-1。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-15 10:27:28 -07:00
nyaKazuha
060b7d73e5
fix(official-sync): 复用失败 staging 避免重复全量下载
2026-07-16 00:35:24 +08:00
nyaKazuha
c123f6c0dc
feat(official-sync): 支持本地代理下载官方资源
2026-07-16 00:12:27 +08:00
nyaKazuha
169822abaf
fix(daemon): 区分当前下载与历史失败状态
2026-07-15 23:22:30 +08:00
nyaKazuha
5b31112e91
fix(daemon): 使用人类格式输出 RPC 下载进度
2026-07-15 23:05:28 +08:00
nyaKazuha
7890b667d7
fix(daemon): 去重失败版本并优化状态输出
2026-07-15 22:32:27 +08:00
nyaKazuha
60b8339ecb
fix(official): 修正官方 hash 校验算法
2026-07-15 22:30:33 +08:00
nyaKazuha and Claude Fable 5
9e83bbea11
docs(docs): 按 issue 状态同步当前状态与缺口文档
...
G-018 已关闭并进入长期运行测试阶段,运行报告后续提供;阻塞项和下一步按
open issue #1/#2/#3 重排,明确 daemon JSON-RPC 扩展为 Rust Resource
Backend API 的优先级和最小方法集。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-15 06:51:46 -07:00
nyaKazuha
0d07b9f4ce
docs(docs): 记录提交信息 scope 规则
...
要求提交标题统一使用 type(scope): 中文说明,并在开发指南和贡献指南中补充示例。
2026-07-15 21:28:22 +08:00
nyaKazuha
b4b4f25cb3
refactor(ffi): 降级 FFI 为可选兼容层并整理文档
...
将 bat-ffi 明确收敛为无状态 C ABI 兼容层,默认集成路径改为 bat --json 进程边界或未来稳定 SDK。
同步 README、当前状态、项目计划、架构文档、开发指南和缺口清单,移除 FFI 作为主集成边界的表述。
新增 AGENTS.md 和 CONTRIBUTING.md,压缩 CLAUDE.md 为兼容入口,并归档阶段性报告、同步 .gitignore 规则。
2026-07-15 21:12:17 +08:00
nyaKazuha
90307a3243
feat: track official versions and import resources
...
Persist official version-state, extend CAS/ResourceRepository import classification, and add offline catalog and failure regression fixtures.
Fixes #13
Fixes #12
Fixes #8
2026-07-15 19:53:10 +08:00
nyaKazuha
4192d7ee4c
fix: classify official download failures
...
Distinguish terminal HTTP errors from retryable CDN/network failures, record quarantined resources, and report failed download progress.
Fixes #7
2026-07-14 01:30:12 +08:00
nyaKazuha
25c2c4d40f
feat: add official full pull smoke
...
Emit runtime download progress and validation summaries for official sync.
Add repeatable real-network full pull smoke runbook and script.
Fixes #4
Fixes #6
2026-07-14 00:48:59 +08:00
nyaKazuha
2ff99ae9e3
feat: publish official resources atomically
...
Fixes #9
Fixes #11
2026-07-14 00:10:39 +08:00
nyaKazuha
45aba2fb2b
fix: harden official sync filesystem boundaries
...
Fixes #14
2026-07-13 23:17:52 +08:00
nyaKazuha
1bdbb47b52
docs: define production sync deployment
...
Fixes #15
2026-07-13 22:22:20 +08:00
nyaKazuha
599ead8391
fix: serialize daemon control commands
...
Fixes #10
2026-07-13 22:02:11 +08:00
nyaKazuha
1bcb9c828a
feat: summarize official validation results
...
Fixes #5
2026-07-13 01:06:37 +08:00
nyaKazuha
e5fcf26e19
feat: validate official zip structure
2026-07-12 23:37:47 +08:00
nyaKazuha
559206962c
chore: update license holder
2026-07-12 23:04:27 +08:00