版本 1.0.372 开发日志

构建 1.0.372(code 372)· 2026-10-02 13:54:33 · sha256 1512461f8a735729…

下载:公网 · Tailscale · 局域网

开发日志(本轮摘要)

# 贵霜帝国 · 内网开发版 · 本轮开发记录

生成时间:2026-10-02 13:49:45 | 本包:kushan-1.0.372.apk(1.0.372 / code 372,sha256 1512461f8a735729…)

## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)

### TASK-B014-NOTICE  (2026-10-02 13:38:10)

# TASK-B014-NOTICE —— 68 号 B-14「告示牌(律令入口)」落地 + 真机验证(2026-10-02 · 1.0.371)

## 判据(68 号 B-14 原文)
> 镇上立告示木牌,点开列出当前生效律令 | 验法:真机点告示 → 截图

## 本轮做了什么(此前**客户端零实现**:`scripts/` 里 grep 不到「告示/律令」)
1. **新面板** `scripts/room/notice_panel.gd`(一功能一文件):把「当前生效律令」画进房间交互区。
   - 真源:`data/laws_xiangfei.json`(70 号 §二《律令政策真源》的 `laws` 数组)+ 参数 `law.enabled_ids`(生效编号)。
   - **只读不裁**:名单读参数、正文读数据文件,面板零硬编码(文案走 I18n、条数上限走参数、样式走 UI/UIConf)。
2. **入口(镇上才出)**:`scripts/room/room_layout.gd` 新增 `notice_here()` —— 按**所在地类型**判(`locations.type`),
   类型名单走参数 `law.notice_loc_types`(默认 `town,city,village,castle,district`);主菜单里多一项「📜 告示」。
3. **参数**(`data/params.json`,与 `law.*` 同组):`law.notice_loc_types`(str)、`law.notice_max`(int,默认 12,min1/max40)。
4. **文案**(`data/i18n.json`):`label.tag.notice` =「📜 告示」;`ui.room.t181~t184` = 面板标题/空表/页脚/日志。
   踩坑记:起初插到 `t017~t020`,**那几个号早被占用**(`t017` 已是「房间不存在」)⇒ JSON 允许重复键、`I18n` 取到旧值;
   改取**空闲号 t181~t184** 才对(教训:加 i18n 键前先查该命名空间的已用号)。

## 真机验证(1.0.371 · 三星 R3CR704Q72V · sha256 `见本轮汇报`)
- 房间:`KUSHAN_ROOM_LINES … 文="富贵街北"`(香妃镇 19 号房;location type=town ⇒ 入口出现 ✓)。
- 菜单:真点轨迹球物理 `(880,2525)` → 菜单自报出现「📜 告示」→ 真点其中心逻辑 `(519.5,1051)`=物理 `(692,1401)`。
- 面板自报(节选,`logcat_menuitems.txt`):
```
文=禁酒令 · 设计在册 | 文=教育限令 · 设计在册 | 文=宵禁与巡查 · 设计在册 | 文=告示即法 · 设计在册
文=广场立告示木牌…(正文) | 文=税与贡 · 设计在册 | 文=劝善戒恶队 · 设计在册
文=律令由香妃领颁行…(页脚)
```
- **判据对账**:`law.enabled_ids` 10 条 ⇒ 面板里**命中的条目名 10 个**(着装令、同行令、禁乐令、禁酒令、教育限令、
  宵禁与巡查、告示即法、税与贡、禁影像、劝善戒恶队)+页脚在场 ⇒ **RESULT=PASS**;截图 `b14_notice_room19.png`(目视)。

## 老实说的边界(未做/待定)
- **外观形态**:判据说「立告示**木牌**」,本轮落的是**菜单入口**(镇上可见、点开即列),**场景里那根木牌的美术外形没做**
  (mid 层场景点归 `room/layer_rects.gd` 布局体系管,属另一条线)⇒ 记作后续外观项,不谎报「木牌已立」。
- `laws_xiangfei.json` 里每条律令的 `open` 字段(如 L-01「罚金数额待人否」)**没有上屏** —— 那属「待人否」清单,按纪律不擅自编数。

### TASK-B014-BAG-USE  (2026-10-02 13:12:06)

# TASK-B014-BAG-USE ——「背包 / 物品可用」真机验证成立(2026-10-02 · 1.0.370 · 三星 R3CR704Q72V)

## 结论
**「物品可用」成立**:真机点开背包 → 真点「使用」→ 客户端 hp **30 → 42**(+12,恰等于 `heal.food_amount`)、
干馕数量 **2 → 1**。原文(`logcat_b014_bag_use.txt`,同一会话、连续三条读数):
```
KUSHAN_BAG_QA prep drop=20 hp=30 max=50 food_id=-2 name=干馕 qty=2
KUSHAN_BAG_QA t=51 hp=30/50 food_id=-2 name=干馕 qty=2 heal=12
KUSHAN_BAG_QA t=54 hp=42/50 food_id=-2 name=干馕 qty=1 heal=12     ← 真点「使用」之后
```
真点链:轨迹球物理 `(880,2525)` 收到 `KUSHAN_TOUCH (659.9999, 1893.751)` → 菜单自报出现 →
点「🎒 背包」逻辑 `(519.5,631)`=物理 `(693,841)` → 背包面板打开(自报「生命 30/50 | 克什 300.00」)→
点「使用」逻辑 `(519.5,612.5)`=物理 `(693,817)` → hp/数量在下一拍就变了。
截图 `b014_bag_after_use.png`(目视:面板与读数)。**判据=hp 变大 且数量变小(RESULT=PASS)**。

## 为什么直到今天才验成(根因,值得记住)
`GameState.use_item()` 的治疗分支要求 `stats.hp < Params.int_val("combat.player_max_hp")`;
而**服务端战斗是权威账、不回写客户端 `stats.hp`** —— 打完架客户端血量不变,
真机自报也一直是 `生命 51/50`(hp 还大于上限)⇒ 永远落在 `combat.hp_full` 分支、不消耗物品。
即「客户端 hp」与「服务端战斗 hp」是**两本账**。

## 本轮处置=加一个 cfg 门控的自检驱动(不改玩法)
`scripts/bag_qa.gd`(由 `room_view.gd` 按 `SETTINGS_QA` 同款门控挂上,**不写 cfg 零副作用**):
把客户端 hp 压到 `max - N`(默认 20)并每 3 秒打一条 `KUSHAN_BAG_QA`(hp/件 id/名/数量/该件回血)。
⇒ 让「真点使用」这一步能落到治疗分支上**被观察到**,而不是靠改产品数值或改断言。
用法:`kushan.cfg` 里 `BAG_QA=watch`(或 `BAG_QA=watch:35` 调压血量)。

## 顺带记一条工具坑(这次踩了)
`KUSHAN_MENUITEM` 自报里菜单项**带 emoji**(`文=🎒 背包`)⇒ grep 用 `文=背包` 匹配不到(少了一层通配),
害我第一次脚本取到 `(0,0)` 点位。正确写法:`grep '文=.*背包'`(或只 grep 关键词)。

## 仍待人拍板(设计岔路,不在本轮擅自改)
**两本账要不要统一**:① 服务端战斗结果回写客户端 `stats.hp`(客户端血量跟服务端走);
② 明确「客户端 hp」只用作出征前快照 / 展示,治疗类物品的服务端权威路径另立。
两条都属玩法口径,**开发方倾向 ①(一处真源,省掉两套数值)**,但影响面涉及存档与战斗结算,故登记待人否。

### TASK-GUARD-DELETE-TOLERANT  (2026-10-02 12:55:47)

# TASK-GUARD-DELETE-TOLERANT(2026-10-02)——「参数键存在性」新护栏 + 5 个护栏的删件容忍

## 一、补上真实盲区:代码引用的参数键,没人静态扫(→ 新护栏 `tools/verify_param_keys_missing.py`)

**起因(真机逮到)**:1.0.366/367 真机日志有 `ERROR: [Params] 缺参(键不在任何层,也不在出厂 schema): net.quest_timeout_sec`。
`verify_param_wiring` 验的是**运行时行为**「缺参即报错」(H 段),扫不到「代码引用了不存在的键」——
那条代码路径只要测试没跑到,缺参就一直潜伏(本例潜伏到玩家上报差事才可能挂住请求,因为 `HTTPRequest.timeout = 0` 表示**永不超时**)。

**判据(与 `plugins/params.gd` 同源)**:参数存在 ⇔ `data/params.json` 的 `params` 袋里有这个键
(`_raw()` 里 `_effective()` 找不到层 + `meta()` 找不到 schema ⇒ push_error 并返回 0);
世界/帝国/领地/皮/个人各层都是**运行期覆盖**,不是存在性来源。

**做法**:扫 `scripts/`+`plugins/` 全部 `.gd` 里 `Params.<getter|meta|writer>("字面键")`(动态拼接跳过并计数),
与 `data/params.json` 求差。带理由白名单 `tools/param_keys_missing_whitelist.tsv`(键<tab>理由);
`params.json` 读不到 ⇒ `RESULT=SKIP`(不假红)。已转正为 `verify_` 前缀 ⇒ 自动进 `tools/run_verify_all.sh`。

**首跑就抓到 8 个真缺键**(全在 `scripts/voice_input.gd`):`assistant.mic.{sample_rate,channels,max_ms,min_ms,auto_send,enabled,asr_path,asr_timeout_sec}`。
查证=**改名没跟到底**:真名族是 `voice.*`(`voice.sample_rate=16000`/`voice.channels=1`/`voice.max_sec=8`/`voice.enabled=1`/`voice.endpoint=/api/asr`…),
而该文件读的是旧前缀 `assistant.mic.*` ⇒ 读到的全是 0/false/"":**采样率 0、声道 0、录音时长 0、`_mic_btn.visible=false`**(麦克风按钮根本不显示)。

**处置=删件而不是补参**:`scripts/voice_input.gd` 是语音重构前的遗留件 ——
① 全仓**无人实例化它**(只有两处注释提到名字,加 `tools/verify_ui_e21.gd` 的待核清单);
② 它按**旧 4 参**签名调 `MicBridge.bind(sample_rate, channels, max_ms, min_ms)`,而现核心 `scripts/core/mic_bridge.gd` 已是
**6 参** `bind(sample_rate, channels, max_sec, silence_sec, silence_rms, poll_sec)` ⇒ 就算被实例化也会炸;
③ 现役实现是 `scripts/room/voice_bar.gd`(文件头就写着「可调项全在参数 `voice.*`/`tts.*`」)。
⇒ 删 `scripts/voice_input.gd` + `.uid`,并同步 `tools/verify_ui_e21.gd` 的待核清单。删后扫描器 **缺键 0**(扫描键 388→376)。

## 二、删件把 5 个护栏打崩/打红 ⇒ 补「删件容忍」(护栏扩展·技术债)

删掉遗留件后全量回归报 **5 红**,且**不是行号漂移**、是真崩溃(`FileNotFoundError` traceback)/计数失真:
`verify_color`(C.5 站点 + C.6 改前↔改后逐处对账的计数)、`verify_client_i18n`(C1.3 与 C1.7 两处 cache 读件)、
`verify_semantic`(S.2 迁移点计数 + S.5 `_meta.sites` 站点)、`verify_wiring`(W.1 期望调用点)、`verify_fx`(F.5 站点)。

**处置口径**(沿用本仓既有纪律「护栏取不到数据必须报错或跳过,**不能拿空表比绿**」):**跳过 + 出声计数**。
逐处改为「文件不存在 ⇒ 计入 `已删件跳过 N` 并 continue」,行里不留判红、也不静默。
**没有剪基线**:先试过剪 `evidence/TASK-E19/E20/E25/*.tsv` 与 `data/ui_config.json` 的 `_meta.sites`,
副作用是 **21 个键的站点列表被剪空**(会在别的判据上产生新的假红),且让「改前现场」基线失真 ⇒ 全部回滚,改走护栏容忍。
(另记一条坑:往 TSV 里插 `#` 说明行会让只跳空行/表头行的护栏 `int(f[1])` 崩 `IndexError` ⇒ 基线文件保持纯数据,说明写在本文档。)

**复验**(每项单跑绿 + 出声报跳过数):

### TASK-ROOM-POPUP-SHELL  (2026-10-02 12:34:57)

# TASK-ROOM-POPUP-SHELL —「战后房间整块点不动」根因与修复(2026-10-02 · 1.0.367 真机复验通过)

## 现象(真机)
自动战斗打完 → 点「**收 手**」→ **房间整块点不动**:轨迹球(逻辑 `(660,1893.75)`=物理 `(880,2525)`)
的 `input tap` **已被游戏收到**(`KUSHAN_TOUCH` 有记录)却毫无反应;方向键同样无反应、也不换房。
界面看着像正常房间(10-02 起房间卡片 `card_bg_alpha=0`,空弹窗壳**看不见**)⇒ 极易误判为「卡死/注入失效」。