构建 1.0.366(code 366)· 2026-10-02 12:15:24 · sha256 a165f2058217e7d0…
开发日志(本轮摘要)
# 贵霜帝国 · 内网开发版 · 本轮开发记录
生成时间:2026-10-02 12:10:39 | 本包:kushan-1.0.366.apk(1.0.366 / code 366,sha256 a165f2058217e7d0…)
## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
### TASK-BATTLE-DEVICE (2026-10-02 12:02:25)
# TASK-BATTLE-DEVICE — 战斗系统真机全链取证(2026-10-02)
**设备/包**:三星 `R3CR704Q72V` · 1.0.365 · cfg `BATTLE_AUTOPLAY=1`(驱动 `scripts/battle_autoplay.gd`)
走**真实玩家路径**:进世界 → 找本屋可交手的人 → `_open_battle_view` 开战 → 推回合。
## 一、结论:战斗可打,服务端裁决到结算全链通 ✅
**附身钱包** `KS194fb06ed5f92ddeaf0bf33f7989356771ba4cae`(`character_panel` 里唯一附身关系:→ 人物 19):
```
KUSHAN_BATTLE_QA begin
KUSHAN_BATTLE_QA target id=17 name=丫鬟阿娜
KUSHAN_BATTLE_QA battle_open
KUSHAN_BATTLE_QA debug_begin ok=true ← 开战成立(服务端建 encounter)
KUSHAN_BATTLE_QA round=1 ok=true status=active cmd_count=2
KUSHAN_BATTLE_QA round=2 ok=true status=active cmd_count=2
KUSHAN_BATTLE_QA round=3 ok=true status=active cmd_count=4
KUSHAN_BATTLE_QA round=4 ok=true status=win cmd_count=3 ← 打赢、服务端结算
KUSHAN_BATTLE_QA DONE rounds=4
```
面板自报(`MENU_DUMP=1`):`攻 击/防 御/逃 走/收 手`+提示「选一个动作,开打。」
截图 OCR(`tools/qa_shot_ocr.py`):结算横幅「**你击败了丫鬟阿娜**」+「收 手」。
⇒ B-013「战斗可打」有真机硬证(本轮)。
## 二、开战的前提:钱包必须**附身**某个人物(领域模型)
同一驱动、同一台机,换**未附身**钱包(`local_trade_qa`/`KSbda5…`)时:
```
KUSHAN_BATTLE_QA debug_begin ok=false
KUSHAN_BATTLE_QA round=1 ok=false status= cmd_count=0
KUSHAN_BATTLE_QA DONE rounds=1
```
服务端原话(直打 `POST /api/combat/start`):
```
{"success":false,"error":"该钱包没有附身任何 NPC,无法战斗"}
```
**根因**:`gateway.py::combat_start` 用 `SELECT cp.character_id FROM character_panel cp WHERE cp.wallet_player=%s` 取 attacker,
未命中即拒。**库内实测只有 1 条附身关系**(`character_panel` id=1:character 19 / `wallet_player=KS194fb06…` / `wallet_npc=KB19xxd_npc`)。
**不是缺陷** —— 是领域模型「玩家一律附身 NPC」的直接体现;但**驱动侧原来只打 `ok=false` 不打原因**,会让排查白跑(本轮已补,见下)。
## 三、顺手补的诊断(本轮改码)
`scripts/battle_autoplay.gd`:`debug_begin`/`round` 两行**都加上 `error=`**。
改前只有 `ok=false`,无从区分「没网关卡 / 服务端拒绝」,实测为此多查了一轮(先怀疑驱动、再怀疑网关、最后才直打端点拿到原话)。
### TASK-B010-SETTINGS (2026-10-02 11:51:06)
# TASK-B010-SETTINGS — 设置页四项「改 → 冷启 → 仍生效」真机验收(2026-10-02)
**口径**:41 号 2.4「字号/皮肤/音量/清缓存+语音助手开关,重启仍生效」。
**驱动**:`scripts/settings_qa.gd`(调设置页自己的 handler,零新逻辑;`SETTINGS_QA=run` 改、`=verify` 冷启回读)。
**设备/包**:三星 `R3CR704Q72V` · 1.0.365 · `AUTO_ENTER=59`。
## ① run(改一遍)
```
KUSHAN_SETTINGS_QA 字号 [run] 期望=1.2 实得=1.2 PASS
KUSHAN_SETTINGS_QA 皮肤 [run] 期望=非空且=UI.skin().display_name() 实得=鎏金御用 PASS
KUSHAN_SETTINGS_QA 音量 [run] 期望=0.42 实得=0.42 PASS
KUSHAN_SETTINGS_QA 清缓存 [run] 期望=0 实得=0 PASS (清前=12 清后=0)
KUSHAN_SETTINGS_QA 语音开关 [run·翻回] 期望=true 实得=true PASS
```
## ② verify(**冷启后**回读 —— 本项要证的就是这一档)
```
KUSHAN_SETTINGS_QA 字号 [verify] 期望=1.2 实得=1.2 PASS
KUSHAN_SETTINGS_QA 皮肤 [verify] 期望=非空且=UI.skin().display_name() 实得=鎏金御用 PASS
KUSHAN_SETTINGS_QA 音量 [verify] 期望=0.42 实得=0.42 PASS
KUSHAN_SETTINGS_QA 清缓存 [verify] 期望=0 实得=0 PASS
```
⇒ **四项(字号/皮肤/音量/缓存)跨冷启持久化成立** ✓(持久化落点 `user://settings.json`,即应用私有目录)。
两轮日志时间戳:run `11:48:57`(pid 21288)→ verify `11:49:25`(**pid 21579,另一个进程** ⇒ 确为重启后回读,不是同一进程内自证)。
## 遗留
- **语音助手开关**只在 `run` 档打了(`[run·翻回]`),`verify` 档**不回读该项** ⇒ 「开关本身跨重启」未单独立证(其落点同 `settings.json`)。
- `user://settings.json` 在**发布包**里属应用私有目录(`run-as` 不可用)⇒ 现场未直读文件原文,以上以驱动回读为准。
## 附带订正
`scripts/settings_qa.gd` 头注沿用旧话「本机**游戏模式拦注入触摸**」——该判断已于 2026-10-02 被推翻
(真因是坐标用错:`input tap` 要**物理**=逻辑×窗口宽/720;三条硬证见 `evidence/TASK-B014-TOUCH/touch_proof.txt`)。本轮已改注释。
### TASK-B011-TRADE-SAY (2026-10-02 11:48:39)
# TASK-B011-TRADE-SAY — 「对话成交」真机验收(商品匹配/买/卖/余额变化)
**口径**:交易走对话、不走面板(41 号 §九十四 S4 / 用户令 2026-10-01);钱货服务端裁决(`/api/trade/*`),
本地只镜像。**本件验的就是玩家那句人话** —— `TRADE_QA_SAY` 把句子喂进 `_send_chat`(与玩家手打同一入口)。
**设备/包**:三星 `R3CR704Q72V` · 1.0.365 · `AUTO_ENTER=59`(伯克·祖米热,在 670 巴扎馕摊,本屋掌柜 21 阿依古丽);
货架真源 `shop_21_8` 蜂蜜馕 单价 5.00(服务端含税报 5.10)。
## 一、负例:零余额钱包(KS0b828…,0.00)
```
KUSHAN_SAY_QA 本屋掌柜=21 要说的话=买 蜂蜜馕 一件
KUSHAN_DT 到手=[买 蜂蜜馕 一件] 买词=true 卖词=false 对象=npc:21 ← 按名匹配到本屋货架 ✓
KUSHAN_DT 买回执={"error":"余额不足:需 5.10,有 0.00","success":false,"tx_id":null} ← 服务端原话 ✓
KUSHAN_SAY_QA 事后钱=300.0 背包件数=2 ; final ksc=300.0 bag=2
```
**库侧**:`wallet_accounts` 0.00 不变;`npc_transaction_log` 无新行(最近仍是 10-01 23:07 的 76/77/78)⇒ **零状态变更** ✓
## 二、正例:有余额钱包(KS972f…,1018.50)——「买」→「卖」
```
说=[买 蜂蜜馕 一件] 事前钱=300.0 背包件数=2
KUSHAN_DT 买回执={"action":"buy","item_name":"蜂蜜馕","quantity":1,"unit_price":5.1,"total_din":"5.1",
"ksc_remaining":"1013.4","stock_left":17,"success":true,"tx_id":"tx-buy-1790912836763-d26f48"}
KUSHAN_DT bag_buy rows=3 total=4 ; 事后钱=1013.4 背包件数=3
说=[卖 蜂蜜馕 一件]
KUSHAN_DT sell_key=[shop_21_8] 反查=shop_21_8 镜像名=[蜂蜜馕] id=0 原键=[shop_21_8] ← 镜像键反查货架键 ✓
KUSHAN_DT 卖回执={"action":"sell","item_name":"蜂蜜馕","quantity":1,"total_din":"3.06",
"ksc_remaining":"1016.46","stock_left":17,"success":true,"tx_id":"tx-sell-1790912839778-75852f"}
KUSHAN_DT bag_sell rows=2 total=3 ; 事后钱=1016.46 背包件数=2
KUSHAN_SAY_QA DONE
```
**库侧对账(硬数字)**:
- 余额 `KS972f…` **1018.50 → 1016.46**(−5.10 买 +3.06 卖 = −2.04 ✓)
- `npc_transaction_log` 新增 **79** `buy` 蜂蜜馕×1 `total_ksc=5.10` `committed` 11:47:16、**80** `sell` 蜂蜜馕×1 `3.06` `committed` 11:47:19 ✓
- `character_inventory`:买时新建行 qty=1(id 59),卖出按**归零删行**(B-057 修法)⇒ 该钱包当时零行;为证落物独立复验:
直打 `POST /api/trade/buy`(同钱包同货)⇒ 立刻回读得到 **id=60 KS972f… shop_21_8 qty=1** ✓(先前的「零行」是买后即卖的正常结果,**不是缺陷** —— 教训 #63 同款:先复验再定性)
## 三、判定
| 子判据 | 结果 | 证据 |
| --- | --- | --- |
| 商品列表(按名匹配本屋货架) | ✅ | `买词=true 对象=npc:21` + `sell_key=[shop_21_8] 反查=…镜像名=[蜂蜜馕]` |
### TASK-B012-QUEST (2026-10-02 11:39:20)
# TASK-B012-QUEST — 任务环真机全链验收(接取→进度→交差)+ 交差 500 修复(2026-10-02)