Category: 更新日志

版本迭代与开发进度记录

  • 版本 1.0.364 开发日志

    构建 1.0.364(code 364)· 2026-10-02 02:58:20 · sha256 09b4044d640b2e24…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-02 02:57:48 | 本包:kushan-1.0.364.apk(1.0.364 / code 364,sha256 09b4044d640b2e24…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-B037-RECUR  (2026-10-02 02:30:59)
    
    # TASK-B037-RECUR · B-037 结案 + 同类复发(**已收口**)
    
    **日期**:2026-10-02 02:40 | **包**:1.0.358(真机 `R3CR704Q72V`)
    
    ## 一、B-037 原判据的处置:**对象已不存在**
    `scripts/room/shop_panel.gd` 已随 41 号 §九十四 S3(b) 退场(文件实测不存在;`room_view.gd` 已不再引用)⇒ 「商店面板点不动」在当前代码里**无法复现**(面板本身没了)。**不因此只写「消解」就完事** —— 该缺陷的机制是**复发类**:
    `room_layout.gd` 内已有 4 处带「真机实测」注释的 `mouse_filter = MOUSE_FILTER_IGNORE` 处置(全屏底色/场景图/描述层…),说明「装饰层默认 STOP 把点击吃掉」在这个仓反复出现过。
    
    ## 二、复发网(新工具,**故意不叫 `verify_`**)
    `tools/scan_click_eaters.py` —— 扫房间界面里 `TextureRect/RichTextLabel/ColorRect/Panel/Label.new()` 的**非按钮变量**,看其后 40 行内是否显式 `MOUSE_FILTER_IGNORE`,列出候选。
    按仓库纪律(假阳性未清零前不得带 `verify_` 前缀、不进全量闸门),它是**给人看的候选清单**,输出落 `scan_click_eaters.txt`。
    
    **扫描结果与逐条裁决**(29 个文件,3 处已显式 IGNORE):
    ```
    ① scripts/room/map_screen.gd:120  bg = ColorRect.new()      → 不修:全屏地图遮罩,**应该**吃掉点击(挡住下层房间)
    ② scripts/room/room_person.gd:55  tr = TextureRect.new()     → ★修:立绘是装饰,父面板 p 才接交谈
    ③ scripts/room/room_refresh.gd:260 rt = RichTextLabel.new()  → 不修:出口「点文字走过去」的点击目标
    ```
    
    ## 三、本轮实修(②)+顺手收拾(遗留探针)
    1. `scripts/room/room_person.gd`:立绘 `TextureRect` 补 `mouse_filter = Control.MOUSE_FILTER_IGNORE`
       —— 父面板 `p` 已是 `STOP` 且 `gui_input` 接交谈;子层吃点击 ⇒ 表现就是「点立绘/名字(立绘范围内)没反应」,与 B-037 同机制。
    2. `scripts/room/room_refresh.gd:82`:**遗留探针**原先「每进一间房无条件扫屏打日志」(其上游注释写「验完即删」却一直在)⇒ 改 cfg 门控(`HIT_X/HIT_Y` 或 `MENU_DUMP=1` 才跑),生产零影响。
    
    ## 四、真机取证(1.0.358)
    ```
    (a) cfg 带 HIT_X/HIT_Y=470,760 ⇒ 探针行数=7   ← 探针功能保留,可继续做命中排查
    (b) cfg 不带                    ⇒ 探针行数=0   ← 门控生效,生产不再白扫屏/刷日志
    KUSHAN_HIT 点(470.0, 760.0) 命中 4 层,最上层=/root/Main/RoomView/@MarginContainer@105/@VB…(面板在顶层,正常)
       候选含 /root/Main/RoomView/@TextureRect@113(场景图层的 TextureRect **确实参与命中** ⇒ 该机制在真机确实存在)
    ```
    截图:`room358.png`(同包同 cfg,房间正常渲染)。
    
    ## 五、未验(如实记)
    - 「点立绘/名字」的**手指点击**未在本机取证(该机折叠屏外侧触控注入不可用,历史 E-010/B-061 同因);本轮以**代码判据+命中层证据**收口。
    - ①③ 两处按裁决**不改**(理由见上),若日后真机发现同点位点不动,按本卡口径复跑 `scan_click_eaters.py` 复核。
    
    ### TASK-MAP-MODULE-DEPS  (2026-10-02 02:24:20)
    
    # TASK-MAP-MODULE-DEPS · MAP-08 单向依赖(**已收口**)
    
    **日期**:2026-10-02 02:20 | **口径**:68 号 MAP-08(行数项 2026-09-26 已作废 ⇒ 见 G-010「只查职责不查行数」)
    
    ## 新护栏 `tools/verify_map_module_deps.py`(已自动纳入全量)
    判据:四模块内部引用**只能是** `map_screen → {map_nav, map_data, map_render}`;基础件不得反向引用 `map_screen`、彼此不得互引、不得成环。
    
    **正测(现仓)**:
    ```
       map_nav     → (无)
       map_data    → (无)
       map_render  → (无)
       map_screen  → map_data、map_nav、map_render
       ✔ 单向成立:3 条边全部向下,无反向边、无环 / RESULT=PASS
    ```
    
    **反测(临时往 `map_nav.gd` 注入 `preload("res://scripts/room/map_screen.gd")`,跑完 `git checkout` 还原)**:
    ```
       ✗ map_nav ↔ map_screen(成环)/ ✗ map_screen ↔ map_nav(成环)/ RESULT=FAIL(2 处)
    ```
    
    护栏**非空过**(正反两测均如预期)。**职责项**(一功能一文件)由既有 `tools/verify_one_job_per_file.py` 把关,本件不重复。
    
    **行数(仅记录,不作判据)**:`map_nav` 97/`map_data` 167/`map_render` 62/`map_screen` 267 行。
    
    ### TASK-MAP-WALK  (2026-10-02 02:15:43)
    
    # TASK-MAP-WALK · 四层地图真机验收(MAP-01/02/03/04/07 · **已收口**)
    
    **日期**:2026-10-02 01:20-02:05 | **包**:1.0.356(真机 `R3CR704Q72V`,真屏 display 3 `4630947232161729155`)
    **工具**:`tools/qa_map_walk.sh`(三层取图 + 切换)、`tools/qa_map_back_ab.sh`(退层 + 开关 A/B)、`tools/map_shot_metrics.py`(量图)
    **驱动**:cfg 通道 `MAP_QA_LAYER` / `MAP_QA_STEPS`(`jump|back|down|layer:N`)——**不用 Params**:安卓上 `user://` 是应用私有目录,推参数够不着(技能 §8 实测),故把自检接到**外部 kushan.cfg**(与 `AUTO_ENTER`/`TRADE_QA_SAY` 同一条)。
    
    ## 关键读数(原始输出)
    
    **MAP-01 全屏不裁切**(`tools/map_shot_metrics.py`,基准 `map.safe_px=24`):
    ```
    L1.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1457} 内容带=7 均亮=22.7 ⇒ 四边留白达标
    L2.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1721} 内容带=8 均亮=22.2 ⇒ 四边留白达标
    L3.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1997} 内容带=6 均亮=20.6 ⇒ 四边留白达标
    ```
    机身实测:`mDisplayCutout insets=Rect(0,0-960,93)`(顶部挖孔带 93px)、`navigationBars mFrame=[0,2490][960,2616]`;**两条系统栏在本 App 内 `mVisible=false`**(沉浸)⇒ 地图内容(上边距 32px、底边距 ≥1457px)既不压系统栏也不进挖孔带。
    
    **MAP-02 四层可进可退**(同一跑内,层号 1→2→3;`back` 两步 3→2→1):
    ```
    KUSHAN_MAP_LAYER 落层 want=1(回总图)      KUSHAN_MAP_QA 落层 want=1 now=1
    KUSHAN_MAP_LAYER 落层 want=2 lid=2 rid=0 ok=true   KUSHAN_MAP_QA 落层 want=2 now=2
    KUSHAN_MAP_LAYER 落层 want=3 lid=2 rid=100 ok=true KUSHAN_MAP_QA 落层 want=3 now=3
    KUSHAN_MAP_BLOCKS L1 rooms=287 locs=10 blocks=10 key0_type=4
    KUSHAN_MAP_BLOCKS L2 lid=2
    KUSHAN_MAP_QA step=1 cmd=back 前层=3 / KUSHAN_MAP_BACK ok=true 层后=2
    KUSHAN_MAP_QA step=2 cmd=back 前层=2 / KUSHAN_MAP_BACK ok=true 层后=1
    ```
    三层截图 **md5 互不相同**(`b20e4c78` / `ac64a08a` / `6aa265f1`)= 视图真的随层变了。
    
    **MAP-03 总图⇄场景切换**(点两次「切换」= 调按钮同一函数 `_on_jump`):
    ```
    step=1 cmd=jump 前层=2 / KUSHAN_MAP_JUMP 层前=2 / step=1 cmd=jump 后层=1
    step=2 cmd=jump 前层=1 / KUSHAN_MAP_JUMP 层前=1 / step=2 cmd=jump 后层=1   ← 第二次无效(见 B-072)
    ```
    帧序列 `J2=b20e4c78(L1) / J3=ac64a08a(L2) / J4..J6=b20e4c78(L1)` = 同一次运行里两种视图都拍到。
    
    **MAP-04 三层画法一致**:三层内容带 7/8/6、均由同一 `map_render` 模块出图(`show_tiles`/`show_rows` 同一套块状画法,代码同一处),三层截图各具(见上 md5)。
    
    **MAP-07 可回退**(同一包,只改 cfg):
    ```
    abA_开关关.png md5=bb8fc1b6 四边留白={'左':0,'右':1,'上':0,'下':1} 均亮=25.0(世界视图)
    
    ### TASK-MAP-05-06  (2026-10-02 00:06:35)
    
    # TASK-MAP-05-06 · 地图线两项评测(**已收口**)
    
    **日期**:2026-10-02 00:05-00:15 | 来源:68 号 §补录十九(四层地图)
    
    ## MAP-05 · 客户端 L3 楼栋房间集合 == `tools/map_building.py` 同栋集合
    **口径**:抽样 10 栋**比集合**(脚本),不看截图。**本脚本比全部 67 栋**(比抽样更强),抽样 10 栋逐条打印。
    
    **新护栏** `tools/verify_map_building_rooms.py`(自动纳入全量):
    - **从客户端源码真读**判据:正则取 `scripts/room/map_data.gd` 的 `const STREET_TYPES := [...]`
      (不另抄一份,否则护栏自己就是一个新的漂移源);
    - 字尾表从 **params** 读:`map.tail_street`/`map.tail_inner`(`data/params.json` 的 `params` 袋内,点号键);
    - 按**客户端判据**重算(街面=type ∈ 表 或 名字 `·` 后段以字尾结尾;楼内=type==interior 且名字不以街面字结尾,
      无 type 时客户端另有 `tail_inner` 兜底——本脚本照抄);再与工具 `map_building.buildings()` 比集合。
    
  • 版本 1.0.363 开发日志

    构建 1.0.363(code 363)· 2026-10-02 02:55:49 · sha256 2a824f2889af70b3…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-02 02:55:17 | 本包:kushan-1.0.363.apk(1.0.363 / code 363,sha256 2a824f2889af70b3…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-B037-RECUR  (2026-10-02 02:30:59)
    
    # TASK-B037-RECUR · B-037 结案 + 同类复发(**已收口**)
    
    **日期**:2026-10-02 02:40 | **包**:1.0.358(真机 `R3CR704Q72V`)
    
    ## 一、B-037 原判据的处置:**对象已不存在**
    `scripts/room/shop_panel.gd` 已随 41 号 §九十四 S3(b) 退场(文件实测不存在;`room_view.gd` 已不再引用)⇒ 「商店面板点不动」在当前代码里**无法复现**(面板本身没了)。**不因此只写「消解」就完事** —— 该缺陷的机制是**复发类**:
    `room_layout.gd` 内已有 4 处带「真机实测」注释的 `mouse_filter = MOUSE_FILTER_IGNORE` 处置(全屏底色/场景图/描述层…),说明「装饰层默认 STOP 把点击吃掉」在这个仓反复出现过。
    
    ## 二、复发网(新工具,**故意不叫 `verify_`**)
    `tools/scan_click_eaters.py` —— 扫房间界面里 `TextureRect/RichTextLabel/ColorRect/Panel/Label.new()` 的**非按钮变量**,看其后 40 行内是否显式 `MOUSE_FILTER_IGNORE`,列出候选。
    按仓库纪律(假阳性未清零前不得带 `verify_` 前缀、不进全量闸门),它是**给人看的候选清单**,输出落 `scan_click_eaters.txt`。
    
    **扫描结果与逐条裁决**(29 个文件,3 处已显式 IGNORE):
    ```
    ① scripts/room/map_screen.gd:120  bg = ColorRect.new()      → 不修:全屏地图遮罩,**应该**吃掉点击(挡住下层房间)
    ② scripts/room/room_person.gd:55  tr = TextureRect.new()     → ★修:立绘是装饰,父面板 p 才接交谈
    ③ scripts/room/room_refresh.gd:260 rt = RichTextLabel.new()  → 不修:出口「点文字走过去」的点击目标
    ```
    
    ## 三、本轮实修(②)+顺手收拾(遗留探针)
    1. `scripts/room/room_person.gd`:立绘 `TextureRect` 补 `mouse_filter = Control.MOUSE_FILTER_IGNORE`
       —— 父面板 `p` 已是 `STOP` 且 `gui_input` 接交谈;子层吃点击 ⇒ 表现就是「点立绘/名字(立绘范围内)没反应」,与 B-037 同机制。
    2. `scripts/room/room_refresh.gd:82`:**遗留探针**原先「每进一间房无条件扫屏打日志」(其上游注释写「验完即删」却一直在)⇒ 改 cfg 门控(`HIT_X/HIT_Y` 或 `MENU_DUMP=1` 才跑),生产零影响。
    
    ## 四、真机取证(1.0.358)
    ```
    (a) cfg 带 HIT_X/HIT_Y=470,760 ⇒ 探针行数=7   ← 探针功能保留,可继续做命中排查
    (b) cfg 不带                    ⇒ 探针行数=0   ← 门控生效,生产不再白扫屏/刷日志
    KUSHAN_HIT 点(470.0, 760.0) 命中 4 层,最上层=/root/Main/RoomView/@MarginContainer@105/@VB…(面板在顶层,正常)
       候选含 /root/Main/RoomView/@TextureRect@113(场景图层的 TextureRect **确实参与命中** ⇒ 该机制在真机确实存在)
    ```
    截图:`room358.png`(同包同 cfg,房间正常渲染)。
    
    ## 五、未验(如实记)
    - 「点立绘/名字」的**手指点击**未在本机取证(该机折叠屏外侧触控注入不可用,历史 E-010/B-061 同因);本轮以**代码判据+命中层证据**收口。
    - ①③ 两处按裁决**不改**(理由见上),若日后真机发现同点位点不动,按本卡口径复跑 `scan_click_eaters.py` 复核。
    
    ### TASK-MAP-MODULE-DEPS  (2026-10-02 02:24:20)
    
    # TASK-MAP-MODULE-DEPS · MAP-08 单向依赖(**已收口**)
    
    **日期**:2026-10-02 02:20 | **口径**:68 号 MAP-08(行数项 2026-09-26 已作废 ⇒ 见 G-010「只查职责不查行数」)
    
    ## 新护栏 `tools/verify_map_module_deps.py`(已自动纳入全量)
    判据:四模块内部引用**只能是** `map_screen → {map_nav, map_data, map_render}`;基础件不得反向引用 `map_screen`、彼此不得互引、不得成环。
    
    **正测(现仓)**:
    ```
       map_nav     → (无)
       map_data    → (无)
       map_render  → (无)
       map_screen  → map_data、map_nav、map_render
       ✔ 单向成立:3 条边全部向下,无反向边、无环 / RESULT=PASS
    ```
    
    **反测(临时往 `map_nav.gd` 注入 `preload("res://scripts/room/map_screen.gd")`,跑完 `git checkout` 还原)**:
    ```
       ✗ map_nav ↔ map_screen(成环)/ ✗ map_screen ↔ map_nav(成环)/ RESULT=FAIL(2 处)
    ```
    
    护栏**非空过**(正反两测均如预期)。**职责项**(一功能一文件)由既有 `tools/verify_one_job_per_file.py` 把关,本件不重复。
    
    **行数(仅记录,不作判据)**:`map_nav` 97/`map_data` 167/`map_render` 62/`map_screen` 267 行。
    
    ### TASK-MAP-WALK  (2026-10-02 02:15:43)
    
    # TASK-MAP-WALK · 四层地图真机验收(MAP-01/02/03/04/07 · **已收口**)
    
    **日期**:2026-10-02 01:20-02:05 | **包**:1.0.356(真机 `R3CR704Q72V`,真屏 display 3 `4630947232161729155`)
    **工具**:`tools/qa_map_walk.sh`(三层取图 + 切换)、`tools/qa_map_back_ab.sh`(退层 + 开关 A/B)、`tools/map_shot_metrics.py`(量图)
    **驱动**:cfg 通道 `MAP_QA_LAYER` / `MAP_QA_STEPS`(`jump|back|down|layer:N`)——**不用 Params**:安卓上 `user://` 是应用私有目录,推参数够不着(技能 §8 实测),故把自检接到**外部 kushan.cfg**(与 `AUTO_ENTER`/`TRADE_QA_SAY` 同一条)。
    
    ## 关键读数(原始输出)
    
    **MAP-01 全屏不裁切**(`tools/map_shot_metrics.py`,基准 `map.safe_px=24`):
    ```
    L1.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1457} 内容带=7 均亮=22.7 ⇒ 四边留白达标
    L2.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1721} 内容带=8 均亮=22.2 ⇒ 四边留白达标
    L3.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1997} 内容带=6 均亮=20.6 ⇒ 四边留白达标
    ```
    机身实测:`mDisplayCutout insets=Rect(0,0-960,93)`(顶部挖孔带 93px)、`navigationBars mFrame=[0,2490][960,2616]`;**两条系统栏在本 App 内 `mVisible=false`**(沉浸)⇒ 地图内容(上边距 32px、底边距 ≥1457px)既不压系统栏也不进挖孔带。
    
    **MAP-02 四层可进可退**(同一跑内,层号 1→2→3;`back` 两步 3→2→1):
    ```
    KUSHAN_MAP_LAYER 落层 want=1(回总图)      KUSHAN_MAP_QA 落层 want=1 now=1
    KUSHAN_MAP_LAYER 落层 want=2 lid=2 rid=0 ok=true   KUSHAN_MAP_QA 落层 want=2 now=2
    KUSHAN_MAP_LAYER 落层 want=3 lid=2 rid=100 ok=true KUSHAN_MAP_QA 落层 want=3 now=3
    KUSHAN_MAP_BLOCKS L1 rooms=287 locs=10 blocks=10 key0_type=4
    KUSHAN_MAP_BLOCKS L2 lid=2
    KUSHAN_MAP_QA step=1 cmd=back 前层=3 / KUSHAN_MAP_BACK ok=true 层后=2
    KUSHAN_MAP_QA step=2 cmd=back 前层=2 / KUSHAN_MAP_BACK ok=true 层后=1
    ```
    三层截图 **md5 互不相同**(`b20e4c78` / `ac64a08a` / `6aa265f1`)= 视图真的随层变了。
    
    **MAP-03 总图⇄场景切换**(点两次「切换」= 调按钮同一函数 `_on_jump`):
    ```
    step=1 cmd=jump 前层=2 / KUSHAN_MAP_JUMP 层前=2 / step=1 cmd=jump 后层=1
    step=2 cmd=jump 前层=1 / KUSHAN_MAP_JUMP 层前=1 / step=2 cmd=jump 后层=1   ← 第二次无效(见 B-072)
    ```
    帧序列 `J2=b20e4c78(L1) / J3=ac64a08a(L2) / J4..J6=b20e4c78(L1)` = 同一次运行里两种视图都拍到。
    
    **MAP-04 三层画法一致**:三层内容带 7/8/6、均由同一 `map_render` 模块出图(`show_tiles`/`show_rows` 同一套块状画法,代码同一处),三层截图各具(见上 md5)。
    
    **MAP-07 可回退**(同一包,只改 cfg):
    ```
    abA_开关关.png md5=bb8fc1b6 四边留白={'左':0,'右':1,'上':0,'下':1} 均亮=25.0(世界视图)
    
    ### TASK-MAP-05-06  (2026-10-02 00:06:35)
    
    # TASK-MAP-05-06 · 地图线两项评测(**已收口**)
    
    **日期**:2026-10-02 00:05-00:15 | 来源:68 号 §补录十九(四层地图)
    
    ## MAP-05 · 客户端 L3 楼栋房间集合 == `tools/map_building.py` 同栋集合
    **口径**:抽样 10 栋**比集合**(脚本),不看截图。**本脚本比全部 67 栋**(比抽样更强),抽样 10 栋逐条打印。
    
    **新护栏** `tools/verify_map_building_rooms.py`(自动纳入全量):
    - **从客户端源码真读**判据:正则取 `scripts/room/map_data.gd` 的 `const STREET_TYPES := [...]`
      (不另抄一份,否则护栏自己就是一个新的漂移源);
    - 字尾表从 **params** 读:`map.tail_street`/`map.tail_inner`(`data/params.json` 的 `params` 袋内,点号键);
    - 按**客户端判据**重算(街面=type ∈ 表 或 名字 `·` 后段以字尾结尾;楼内=type==interior 且名字不以街面字结尾,
      无 type 时客户端另有 `tail_inner` 兜底——本脚本照抄);再与工具 `map_building.buildings()` 比集合。
    
  • 版本 1.0.362 开发日志

    构建 1.0.362(code 362)· 2026-10-02 02:53:32 · sha256 9778279ae5730b19…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-02 02:53:00 | 本包:kushan-1.0.362.apk(1.0.362 / code 362,sha256 9778279ae5730b19…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-B037-RECUR  (2026-10-02 02:30:59)
    
    # TASK-B037-RECUR · B-037 结案 + 同类复发(**已收口**)
    
    **日期**:2026-10-02 02:40 | **包**:1.0.358(真机 `R3CR704Q72V`)
    
    ## 一、B-037 原判据的处置:**对象已不存在**
    `scripts/room/shop_panel.gd` 已随 41 号 §九十四 S3(b) 退场(文件实测不存在;`room_view.gd` 已不再引用)⇒ 「商店面板点不动」在当前代码里**无法复现**(面板本身没了)。**不因此只写「消解」就完事** —— 该缺陷的机制是**复发类**:
    `room_layout.gd` 内已有 4 处带「真机实测」注释的 `mouse_filter = MOUSE_FILTER_IGNORE` 处置(全屏底色/场景图/描述层…),说明「装饰层默认 STOP 把点击吃掉」在这个仓反复出现过。
    
    ## 二、复发网(新工具,**故意不叫 `verify_`**)
    `tools/scan_click_eaters.py` —— 扫房间界面里 `TextureRect/RichTextLabel/ColorRect/Panel/Label.new()` 的**非按钮变量**,看其后 40 行内是否显式 `MOUSE_FILTER_IGNORE`,列出候选。
    按仓库纪律(假阳性未清零前不得带 `verify_` 前缀、不进全量闸门),它是**给人看的候选清单**,输出落 `scan_click_eaters.txt`。
    
    **扫描结果与逐条裁决**(29 个文件,3 处已显式 IGNORE):
    ```
    ① scripts/room/map_screen.gd:120  bg = ColorRect.new()      → 不修:全屏地图遮罩,**应该**吃掉点击(挡住下层房间)
    ② scripts/room/room_person.gd:55  tr = TextureRect.new()     → ★修:立绘是装饰,父面板 p 才接交谈
    ③ scripts/room/room_refresh.gd:260 rt = RichTextLabel.new()  → 不修:出口「点文字走过去」的点击目标
    ```
    
    ## 三、本轮实修(②)+顺手收拾(遗留探针)
    1. `scripts/room/room_person.gd`:立绘 `TextureRect` 补 `mouse_filter = Control.MOUSE_FILTER_IGNORE`
       —— 父面板 `p` 已是 `STOP` 且 `gui_input` 接交谈;子层吃点击 ⇒ 表现就是「点立绘/名字(立绘范围内)没反应」,与 B-037 同机制。
    2. `scripts/room/room_refresh.gd:82`:**遗留探针**原先「每进一间房无条件扫屏打日志」(其上游注释写「验完即删」却一直在)⇒ 改 cfg 门控(`HIT_X/HIT_Y` 或 `MENU_DUMP=1` 才跑),生产零影响。
    
    ## 四、真机取证(1.0.358)
    ```
    (a) cfg 带 HIT_X/HIT_Y=470,760 ⇒ 探针行数=7   ← 探针功能保留,可继续做命中排查
    (b) cfg 不带                    ⇒ 探针行数=0   ← 门控生效,生产不再白扫屏/刷日志
    KUSHAN_HIT 点(470.0, 760.0) 命中 4 层,最上层=/root/Main/RoomView/@MarginContainer@105/@VB…(面板在顶层,正常)
       候选含 /root/Main/RoomView/@TextureRect@113(场景图层的 TextureRect **确实参与命中** ⇒ 该机制在真机确实存在)
    ```
    截图:`room358.png`(同包同 cfg,房间正常渲染)。
    
    ## 五、未验(如实记)
    - 「点立绘/名字」的**手指点击**未在本机取证(该机折叠屏外侧触控注入不可用,历史 E-010/B-061 同因);本轮以**代码判据+命中层证据**收口。
    - ①③ 两处按裁决**不改**(理由见上),若日后真机发现同点位点不动,按本卡口径复跑 `scan_click_eaters.py` 复核。
    
    ### TASK-MAP-MODULE-DEPS  (2026-10-02 02:24:20)
    
    # TASK-MAP-MODULE-DEPS · MAP-08 单向依赖(**已收口**)
    
    **日期**:2026-10-02 02:20 | **口径**:68 号 MAP-08(行数项 2026-09-26 已作废 ⇒ 见 G-010「只查职责不查行数」)
    
    ## 新护栏 `tools/verify_map_module_deps.py`(已自动纳入全量)
    判据:四模块内部引用**只能是** `map_screen → {map_nav, map_data, map_render}`;基础件不得反向引用 `map_screen`、彼此不得互引、不得成环。
    
    **正测(现仓)**:
    ```
       map_nav     → (无)
       map_data    → (无)
       map_render  → (无)
       map_screen  → map_data、map_nav、map_render
       ✔ 单向成立:3 条边全部向下,无反向边、无环 / RESULT=PASS
    ```
    
    **反测(临时往 `map_nav.gd` 注入 `preload("res://scripts/room/map_screen.gd")`,跑完 `git checkout` 还原)**:
    ```
       ✗ map_nav ↔ map_screen(成环)/ ✗ map_screen ↔ map_nav(成环)/ RESULT=FAIL(2 处)
    ```
    
    护栏**非空过**(正反两测均如预期)。**职责项**(一功能一文件)由既有 `tools/verify_one_job_per_file.py` 把关,本件不重复。
    
    **行数(仅记录,不作判据)**:`map_nav` 97/`map_data` 167/`map_render` 62/`map_screen` 267 行。
    
    ### TASK-MAP-WALK  (2026-10-02 02:15:43)
    
    # TASK-MAP-WALK · 四层地图真机验收(MAP-01/02/03/04/07 · **已收口**)
    
    **日期**:2026-10-02 01:20-02:05 | **包**:1.0.356(真机 `R3CR704Q72V`,真屏 display 3 `4630947232161729155`)
    **工具**:`tools/qa_map_walk.sh`(三层取图 + 切换)、`tools/qa_map_back_ab.sh`(退层 + 开关 A/B)、`tools/map_shot_metrics.py`(量图)
    **驱动**:cfg 通道 `MAP_QA_LAYER` / `MAP_QA_STEPS`(`jump|back|down|layer:N`)——**不用 Params**:安卓上 `user://` 是应用私有目录,推参数够不着(技能 §8 实测),故把自检接到**外部 kushan.cfg**(与 `AUTO_ENTER`/`TRADE_QA_SAY` 同一条)。
    
    ## 关键读数(原始输出)
    
    **MAP-01 全屏不裁切**(`tools/map_shot_metrics.py`,基准 `map.safe_px=24`):
    ```
    L1.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1457} 内容带=7 均亮=22.7 ⇒ 四边留白达标
    L2.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1721} 内容带=8 均亮=22.2 ⇒ 四边留白达标
    L3.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1997} 内容带=6 均亮=20.6 ⇒ 四边留白达标
    ```
    机身实测:`mDisplayCutout insets=Rect(0,0-960,93)`(顶部挖孔带 93px)、`navigationBars mFrame=[0,2490][960,2616]`;**两条系统栏在本 App 内 `mVisible=false`**(沉浸)⇒ 地图内容(上边距 32px、底边距 ≥1457px)既不压系统栏也不进挖孔带。
    
    **MAP-02 四层可进可退**(同一跑内,层号 1→2→3;`back` 两步 3→2→1):
    ```
    KUSHAN_MAP_LAYER 落层 want=1(回总图)      KUSHAN_MAP_QA 落层 want=1 now=1
    KUSHAN_MAP_LAYER 落层 want=2 lid=2 rid=0 ok=true   KUSHAN_MAP_QA 落层 want=2 now=2
    KUSHAN_MAP_LAYER 落层 want=3 lid=2 rid=100 ok=true KUSHAN_MAP_QA 落层 want=3 now=3
    KUSHAN_MAP_BLOCKS L1 rooms=287 locs=10 blocks=10 key0_type=4
    KUSHAN_MAP_BLOCKS L2 lid=2
    KUSHAN_MAP_QA step=1 cmd=back 前层=3 / KUSHAN_MAP_BACK ok=true 层后=2
    KUSHAN_MAP_QA step=2 cmd=back 前层=2 / KUSHAN_MAP_BACK ok=true 层后=1
    ```
    三层截图 **md5 互不相同**(`b20e4c78` / `ac64a08a` / `6aa265f1`)= 视图真的随层变了。
    
    **MAP-03 总图⇄场景切换**(点两次「切换」= 调按钮同一函数 `_on_jump`):
    ```
    step=1 cmd=jump 前层=2 / KUSHAN_MAP_JUMP 层前=2 / step=1 cmd=jump 后层=1
    step=2 cmd=jump 前层=1 / KUSHAN_MAP_JUMP 层前=1 / step=2 cmd=jump 后层=1   ← 第二次无效(见 B-072)
    ```
    帧序列 `J2=b20e4c78(L1) / J3=ac64a08a(L2) / J4..J6=b20e4c78(L1)` = 同一次运行里两种视图都拍到。
    
    **MAP-04 三层画法一致**:三层内容带 7/8/6、均由同一 `map_render` 模块出图(`show_tiles`/`show_rows` 同一套块状画法,代码同一处),三层截图各具(见上 md5)。
    
    **MAP-07 可回退**(同一包,只改 cfg):
    ```
    abA_开关关.png md5=bb8fc1b6 四边留白={'左':0,'右':1,'上':0,'下':1} 均亮=25.0(世界视图)
    
    ### TASK-MAP-05-06  (2026-10-02 00:06:35)
    
    # TASK-MAP-05-06 · 地图线两项评测(**已收口**)
    
    **日期**:2026-10-02 00:05-00:15 | 来源:68 号 §补录十九(四层地图)
    
    ## MAP-05 · 客户端 L3 楼栋房间集合 == `tools/map_building.py` 同栋集合
    **口径**:抽样 10 栋**比集合**(脚本),不看截图。**本脚本比全部 67 栋**(比抽样更强),抽样 10 栋逐条打印。
    
    **新护栏** `tools/verify_map_building_rooms.py`(自动纳入全量):
    - **从客户端源码真读**判据:正则取 `scripts/room/map_data.gd` 的 `const STREET_TYPES := [...]`
      (不另抄一份,否则护栏自己就是一个新的漂移源);
    - 字尾表从 **params** 读:`map.tail_street`/`map.tail_inner`(`data/params.json` 的 `params` 袋内,点号键);
    - 按**客户端判据**重算(街面=type ∈ 表 或 名字 `·` 后段以字尾结尾;楼内=type==interior 且名字不以街面字结尾,
      无 type 时客户端另有 `tail_inner` 兜底——本脚本照抄);再与工具 `map_building.buildings()` 比集合。
    
  • 版本 1.0.361 开发日志

    构建 1.0.361(code 361)· 2026-10-02 02:50:43 · sha256 d993ce0e3f8cf56f…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-02 02:50:10 | 本包:kushan-1.0.361.apk(1.0.361 / code 361,sha256 d993ce0e3f8cf56f…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-B037-RECUR  (2026-10-02 02:30:59)
    
    # TASK-B037-RECUR · B-037 结案 + 同类复发(**已收口**)
    
    **日期**:2026-10-02 02:40 | **包**:1.0.358(真机 `R3CR704Q72V`)
    
    ## 一、B-037 原判据的处置:**对象已不存在**
    `scripts/room/shop_panel.gd` 已随 41 号 §九十四 S3(b) 退场(文件实测不存在;`room_view.gd` 已不再引用)⇒ 「商店面板点不动」在当前代码里**无法复现**(面板本身没了)。**不因此只写「消解」就完事** —— 该缺陷的机制是**复发类**:
    `room_layout.gd` 内已有 4 处带「真机实测」注释的 `mouse_filter = MOUSE_FILTER_IGNORE` 处置(全屏底色/场景图/描述层…),说明「装饰层默认 STOP 把点击吃掉」在这个仓反复出现过。
    
    ## 二、复发网(新工具,**故意不叫 `verify_`**)
    `tools/scan_click_eaters.py` —— 扫房间界面里 `TextureRect/RichTextLabel/ColorRect/Panel/Label.new()` 的**非按钮变量**,看其后 40 行内是否显式 `MOUSE_FILTER_IGNORE`,列出候选。
    按仓库纪律(假阳性未清零前不得带 `verify_` 前缀、不进全量闸门),它是**给人看的候选清单**,输出落 `scan_click_eaters.txt`。
    
    **扫描结果与逐条裁决**(29 个文件,3 处已显式 IGNORE):
    ```
    ① scripts/room/map_screen.gd:120  bg = ColorRect.new()      → 不修:全屏地图遮罩,**应该**吃掉点击(挡住下层房间)
    ② scripts/room/room_person.gd:55  tr = TextureRect.new()     → ★修:立绘是装饰,父面板 p 才接交谈
    ③ scripts/room/room_refresh.gd:260 rt = RichTextLabel.new()  → 不修:出口「点文字走过去」的点击目标
    ```
    
    ## 三、本轮实修(②)+顺手收拾(遗留探针)
    1. `scripts/room/room_person.gd`:立绘 `TextureRect` 补 `mouse_filter = Control.MOUSE_FILTER_IGNORE`
       —— 父面板 `p` 已是 `STOP` 且 `gui_input` 接交谈;子层吃点击 ⇒ 表现就是「点立绘/名字(立绘范围内)没反应」,与 B-037 同机制。
    2. `scripts/room/room_refresh.gd:82`:**遗留探针**原先「每进一间房无条件扫屏打日志」(其上游注释写「验完即删」却一直在)⇒ 改 cfg 门控(`HIT_X/HIT_Y` 或 `MENU_DUMP=1` 才跑),生产零影响。
    
    ## 四、真机取证(1.0.358)
    ```
    (a) cfg 带 HIT_X/HIT_Y=470,760 ⇒ 探针行数=7   ← 探针功能保留,可继续做命中排查
    (b) cfg 不带                    ⇒ 探针行数=0   ← 门控生效,生产不再白扫屏/刷日志
    KUSHAN_HIT 点(470.0, 760.0) 命中 4 层,最上层=/root/Main/RoomView/@MarginContainer@105/@VB…(面板在顶层,正常)
       候选含 /root/Main/RoomView/@TextureRect@113(场景图层的 TextureRect **确实参与命中** ⇒ 该机制在真机确实存在)
    ```
    截图:`room358.png`(同包同 cfg,房间正常渲染)。
    
    ## 五、未验(如实记)
    - 「点立绘/名字」的**手指点击**未在本机取证(该机折叠屏外侧触控注入不可用,历史 E-010/B-061 同因);本轮以**代码判据+命中层证据**收口。
    - ①③ 两处按裁决**不改**(理由见上),若日后真机发现同点位点不动,按本卡口径复跑 `scan_click_eaters.py` 复核。
    
    ### TASK-MAP-MODULE-DEPS  (2026-10-02 02:24:20)
    
    # TASK-MAP-MODULE-DEPS · MAP-08 单向依赖(**已收口**)
    
    **日期**:2026-10-02 02:20 | **口径**:68 号 MAP-08(行数项 2026-09-26 已作废 ⇒ 见 G-010「只查职责不查行数」)
    
    ## 新护栏 `tools/verify_map_module_deps.py`(已自动纳入全量)
    判据:四模块内部引用**只能是** `map_screen → {map_nav, map_data, map_render}`;基础件不得反向引用 `map_screen`、彼此不得互引、不得成环。
    
    **正测(现仓)**:
    ```
       map_nav     → (无)
       map_data    → (无)
       map_render  → (无)
       map_screen  → map_data、map_nav、map_render
       ✔ 单向成立:3 条边全部向下,无反向边、无环 / RESULT=PASS
    ```
    
    **反测(临时往 `map_nav.gd` 注入 `preload("res://scripts/room/map_screen.gd")`,跑完 `git checkout` 还原)**:
    ```
       ✗ map_nav ↔ map_screen(成环)/ ✗ map_screen ↔ map_nav(成环)/ RESULT=FAIL(2 处)
    ```
    
    护栏**非空过**(正反两测均如预期)。**职责项**(一功能一文件)由既有 `tools/verify_one_job_per_file.py` 把关,本件不重复。
    
    **行数(仅记录,不作判据)**:`map_nav` 97/`map_data` 167/`map_render` 62/`map_screen` 267 行。
    
    ### TASK-MAP-WALK  (2026-10-02 02:15:43)
    
    # TASK-MAP-WALK · 四层地图真机验收(MAP-01/02/03/04/07 · **已收口**)
    
    **日期**:2026-10-02 01:20-02:05 | **包**:1.0.356(真机 `R3CR704Q72V`,真屏 display 3 `4630947232161729155`)
    **工具**:`tools/qa_map_walk.sh`(三层取图 + 切换)、`tools/qa_map_back_ab.sh`(退层 + 开关 A/B)、`tools/map_shot_metrics.py`(量图)
    **驱动**:cfg 通道 `MAP_QA_LAYER` / `MAP_QA_STEPS`(`jump|back|down|layer:N`)——**不用 Params**:安卓上 `user://` 是应用私有目录,推参数够不着(技能 §8 实测),故把自检接到**外部 kushan.cfg**(与 `AUTO_ENTER`/`TRADE_QA_SAY` 同一条)。
    
    ## 关键读数(原始输出)
    
    **MAP-01 全屏不裁切**(`tools/map_shot_metrics.py`,基准 `map.safe_px=24`):
    ```
    L1.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1457} 内容带=7 均亮=22.7 ⇒ 四边留白达标
    L2.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1721} 内容带=8 均亮=22.2 ⇒ 四边留白达标
    L3.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1997} 内容带=6 均亮=20.6 ⇒ 四边留白达标
    ```
    机身实测:`mDisplayCutout insets=Rect(0,0-960,93)`(顶部挖孔带 93px)、`navigationBars mFrame=[0,2490][960,2616]`;**两条系统栏在本 App 内 `mVisible=false`**(沉浸)⇒ 地图内容(上边距 32px、底边距 ≥1457px)既不压系统栏也不进挖孔带。
    
    **MAP-02 四层可进可退**(同一跑内,层号 1→2→3;`back` 两步 3→2→1):
    ```
    KUSHAN_MAP_LAYER 落层 want=1(回总图)      KUSHAN_MAP_QA 落层 want=1 now=1
    KUSHAN_MAP_LAYER 落层 want=2 lid=2 rid=0 ok=true   KUSHAN_MAP_QA 落层 want=2 now=2
    KUSHAN_MAP_LAYER 落层 want=3 lid=2 rid=100 ok=true KUSHAN_MAP_QA 落层 want=3 now=3
    KUSHAN_MAP_BLOCKS L1 rooms=287 locs=10 blocks=10 key0_type=4
    KUSHAN_MAP_BLOCKS L2 lid=2
    KUSHAN_MAP_QA step=1 cmd=back 前层=3 / KUSHAN_MAP_BACK ok=true 层后=2
    KUSHAN_MAP_QA step=2 cmd=back 前层=2 / KUSHAN_MAP_BACK ok=true 层后=1
    ```
    三层截图 **md5 互不相同**(`b20e4c78` / `ac64a08a` / `6aa265f1`)= 视图真的随层变了。
    
    **MAP-03 总图⇄场景切换**(点两次「切换」= 调按钮同一函数 `_on_jump`):
    ```
    step=1 cmd=jump 前层=2 / KUSHAN_MAP_JUMP 层前=2 / step=1 cmd=jump 后层=1
    step=2 cmd=jump 前层=1 / KUSHAN_MAP_JUMP 层前=1 / step=2 cmd=jump 后层=1   ← 第二次无效(见 B-072)
    ```
    帧序列 `J2=b20e4c78(L1) / J3=ac64a08a(L2) / J4..J6=b20e4c78(L1)` = 同一次运行里两种视图都拍到。
    
    **MAP-04 三层画法一致**:三层内容带 7/8/6、均由同一 `map_render` 模块出图(`show_tiles`/`show_rows` 同一套块状画法,代码同一处),三层截图各具(见上 md5)。
    
    **MAP-07 可回退**(同一包,只改 cfg):
    ```
    abA_开关关.png md5=bb8fc1b6 四边留白={'左':0,'右':1,'上':0,'下':1} 均亮=25.0(世界视图)
    
    ### TASK-MAP-05-06  (2026-10-02 00:06:35)
    
    # TASK-MAP-05-06 · 地图线两项评测(**已收口**)
    
    **日期**:2026-10-02 00:05-00:15 | 来源:68 号 §补录十九(四层地图)
    
    ## MAP-05 · 客户端 L3 楼栋房间集合 == `tools/map_building.py` 同栋集合
    **口径**:抽样 10 栋**比集合**(脚本),不看截图。**本脚本比全部 67 栋**(比抽样更强),抽样 10 栋逐条打印。
    
    **新护栏** `tools/verify_map_building_rooms.py`(自动纳入全量):
    - **从客户端源码真读**判据:正则取 `scripts/room/map_data.gd` 的 `const STREET_TYPES := [...]`
      (不另抄一份,否则护栏自己就是一个新的漂移源);
    - 字尾表从 **params** 读:`map.tail_street`/`map.tail_inner`(`data/params.json` 的 `params` 袋内,点号键);
    - 按**客户端判据**重算(街面=type ∈ 表 或 名字 `·` 后段以字尾结尾;楼内=type==interior 且名字不以街面字结尾,
      无 type 时客户端另有 `tail_inner` 兜底——本脚本照抄);再与工具 `map_building.buildings()` 比集合。
    
  • 版本 1.0.360 开发日志

    构建 1.0.360(code 360)· 2026-10-02 02:46:34 · sha256 7cc2e55da8f166f7…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-02 02:46:02 | 本包:kushan-1.0.360.apk(1.0.360 / code 360,sha256 7cc2e55da8f166f7…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-B037-RECUR  (2026-10-02 02:30:59)
    
    # TASK-B037-RECUR · B-037 结案 + 同类复发(**已收口**)
    
    **日期**:2026-10-02 02:40 | **包**:1.0.358(真机 `R3CR704Q72V`)
    
    ## 一、B-037 原判据的处置:**对象已不存在**
    `scripts/room/shop_panel.gd` 已随 41 号 §九十四 S3(b) 退场(文件实测不存在;`room_view.gd` 已不再引用)⇒ 「商店面板点不动」在当前代码里**无法复现**(面板本身没了)。**不因此只写「消解」就完事** —— 该缺陷的机制是**复发类**:
    `room_layout.gd` 内已有 4 处带「真机实测」注释的 `mouse_filter = MOUSE_FILTER_IGNORE` 处置(全屏底色/场景图/描述层…),说明「装饰层默认 STOP 把点击吃掉」在这个仓反复出现过。
    
    ## 二、复发网(新工具,**故意不叫 `verify_`**)
    `tools/scan_click_eaters.py` —— 扫房间界面里 `TextureRect/RichTextLabel/ColorRect/Panel/Label.new()` 的**非按钮变量**,看其后 40 行内是否显式 `MOUSE_FILTER_IGNORE`,列出候选。
    按仓库纪律(假阳性未清零前不得带 `verify_` 前缀、不进全量闸门),它是**给人看的候选清单**,输出落 `scan_click_eaters.txt`。
    
    **扫描结果与逐条裁决**(29 个文件,3 处已显式 IGNORE):
    ```
    ① scripts/room/map_screen.gd:120  bg = ColorRect.new()      → 不修:全屏地图遮罩,**应该**吃掉点击(挡住下层房间)
    ② scripts/room/room_person.gd:55  tr = TextureRect.new()     → ★修:立绘是装饰,父面板 p 才接交谈
    ③ scripts/room/room_refresh.gd:260 rt = RichTextLabel.new()  → 不修:出口「点文字走过去」的点击目标
    ```
    
    ## 三、本轮实修(②)+顺手收拾(遗留探针)
    1. `scripts/room/room_person.gd`:立绘 `TextureRect` 补 `mouse_filter = Control.MOUSE_FILTER_IGNORE`
       —— 父面板 `p` 已是 `STOP` 且 `gui_input` 接交谈;子层吃点击 ⇒ 表现就是「点立绘/名字(立绘范围内)没反应」,与 B-037 同机制。
    2. `scripts/room/room_refresh.gd:82`:**遗留探针**原先「每进一间房无条件扫屏打日志」(其上游注释写「验完即删」却一直在)⇒ 改 cfg 门控(`HIT_X/HIT_Y` 或 `MENU_DUMP=1` 才跑),生产零影响。
    
    ## 四、真机取证(1.0.358)
    ```
    (a) cfg 带 HIT_X/HIT_Y=470,760 ⇒ 探针行数=7   ← 探针功能保留,可继续做命中排查
    (b) cfg 不带                    ⇒ 探针行数=0   ← 门控生效,生产不再白扫屏/刷日志
    KUSHAN_HIT 点(470.0, 760.0) 命中 4 层,最上层=/root/Main/RoomView/@MarginContainer@105/@VB…(面板在顶层,正常)
       候选含 /root/Main/RoomView/@TextureRect@113(场景图层的 TextureRect **确实参与命中** ⇒ 该机制在真机确实存在)
    ```
    截图:`room358.png`(同包同 cfg,房间正常渲染)。
    
    ## 五、未验(如实记)
    - 「点立绘/名字」的**手指点击**未在本机取证(该机折叠屏外侧触控注入不可用,历史 E-010/B-061 同因);本轮以**代码判据+命中层证据**收口。
    - ①③ 两处按裁决**不改**(理由见上),若日后真机发现同点位点不动,按本卡口径复跑 `scan_click_eaters.py` 复核。
    
    ### TASK-MAP-MODULE-DEPS  (2026-10-02 02:24:20)
    
    # TASK-MAP-MODULE-DEPS · MAP-08 单向依赖(**已收口**)
    
    **日期**:2026-10-02 02:20 | **口径**:68 号 MAP-08(行数项 2026-09-26 已作废 ⇒ 见 G-010「只查职责不查行数」)
    
    ## 新护栏 `tools/verify_map_module_deps.py`(已自动纳入全量)
    判据:四模块内部引用**只能是** `map_screen → {map_nav, map_data, map_render}`;基础件不得反向引用 `map_screen`、彼此不得互引、不得成环。
    
    **正测(现仓)**:
    ```
       map_nav     → (无)
       map_data    → (无)
       map_render  → (无)
       map_screen  → map_data、map_nav、map_render
       ✔ 单向成立:3 条边全部向下,无反向边、无环 / RESULT=PASS
    ```
    
    **反测(临时往 `map_nav.gd` 注入 `preload("res://scripts/room/map_screen.gd")`,跑完 `git checkout` 还原)**:
    ```
       ✗ map_nav ↔ map_screen(成环)/ ✗ map_screen ↔ map_nav(成环)/ RESULT=FAIL(2 处)
    ```
    
    护栏**非空过**(正反两测均如预期)。**职责项**(一功能一文件)由既有 `tools/verify_one_job_per_file.py` 把关,本件不重复。
    
    **行数(仅记录,不作判据)**:`map_nav` 97/`map_data` 167/`map_render` 62/`map_screen` 267 行。
    
    ### TASK-MAP-WALK  (2026-10-02 02:15:43)
    
    # TASK-MAP-WALK · 四层地图真机验收(MAP-01/02/03/04/07 · **已收口**)
    
    **日期**:2026-10-02 01:20-02:05 | **包**:1.0.356(真机 `R3CR704Q72V`,真屏 display 3 `4630947232161729155`)
    **工具**:`tools/qa_map_walk.sh`(三层取图 + 切换)、`tools/qa_map_back_ab.sh`(退层 + 开关 A/B)、`tools/map_shot_metrics.py`(量图)
    **驱动**:cfg 通道 `MAP_QA_LAYER` / `MAP_QA_STEPS`(`jump|back|down|layer:N`)——**不用 Params**:安卓上 `user://` 是应用私有目录,推参数够不着(技能 §8 实测),故把自检接到**外部 kushan.cfg**(与 `AUTO_ENTER`/`TRADE_QA_SAY` 同一条)。
    
    ## 关键读数(原始输出)
    
    **MAP-01 全屏不裁切**(`tools/map_shot_metrics.py`,基准 `map.safe_px=24`):
    ```
    L1.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1457} 内容带=7 均亮=22.7 ⇒ 四边留白达标
    L2.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1721} 内容带=8 均亮=22.2 ⇒ 四边留白达标
    L3.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1997} 内容带=6 均亮=20.6 ⇒ 四边留白达标
    ```
    机身实测:`mDisplayCutout insets=Rect(0,0-960,93)`(顶部挖孔带 93px)、`navigationBars mFrame=[0,2490][960,2616]`;**两条系统栏在本 App 内 `mVisible=false`**(沉浸)⇒ 地图内容(上边距 32px、底边距 ≥1457px)既不压系统栏也不进挖孔带。
    
    **MAP-02 四层可进可退**(同一跑内,层号 1→2→3;`back` 两步 3→2→1):
    ```
    KUSHAN_MAP_LAYER 落层 want=1(回总图)      KUSHAN_MAP_QA 落层 want=1 now=1
    KUSHAN_MAP_LAYER 落层 want=2 lid=2 rid=0 ok=true   KUSHAN_MAP_QA 落层 want=2 now=2
    KUSHAN_MAP_LAYER 落层 want=3 lid=2 rid=100 ok=true KUSHAN_MAP_QA 落层 want=3 now=3
    KUSHAN_MAP_BLOCKS L1 rooms=287 locs=10 blocks=10 key0_type=4
    KUSHAN_MAP_BLOCKS L2 lid=2
    KUSHAN_MAP_QA step=1 cmd=back 前层=3 / KUSHAN_MAP_BACK ok=true 层后=2
    KUSHAN_MAP_QA step=2 cmd=back 前层=2 / KUSHAN_MAP_BACK ok=true 层后=1
    ```
    三层截图 **md5 互不相同**(`b20e4c78` / `ac64a08a` / `6aa265f1`)= 视图真的随层变了。
    
    **MAP-03 总图⇄场景切换**(点两次「切换」= 调按钮同一函数 `_on_jump`):
    ```
    step=1 cmd=jump 前层=2 / KUSHAN_MAP_JUMP 层前=2 / step=1 cmd=jump 后层=1
    step=2 cmd=jump 前层=1 / KUSHAN_MAP_JUMP 层前=1 / step=2 cmd=jump 后层=1   ← 第二次无效(见 B-072)
    ```
    帧序列 `J2=b20e4c78(L1) / J3=ac64a08a(L2) / J4..J6=b20e4c78(L1)` = 同一次运行里两种视图都拍到。
    
    **MAP-04 三层画法一致**:三层内容带 7/8/6、均由同一 `map_render` 模块出图(`show_tiles`/`show_rows` 同一套块状画法,代码同一处),三层截图各具(见上 md5)。
    
    **MAP-07 可回退**(同一包,只改 cfg):
    ```
    abA_开关关.png md5=bb8fc1b6 四边留白={'左':0,'右':1,'上':0,'下':1} 均亮=25.0(世界视图)
    
    ### TASK-MAP-05-06  (2026-10-02 00:06:35)
    
    # TASK-MAP-05-06 · 地图线两项评测(**已收口**)
    
    **日期**:2026-10-02 00:05-00:15 | 来源:68 号 §补录十九(四层地图)
    
    ## MAP-05 · 客户端 L3 楼栋房间集合 == `tools/map_building.py` 同栋集合
    **口径**:抽样 10 栋**比集合**(脚本),不看截图。**本脚本比全部 67 栋**(比抽样更强),抽样 10 栋逐条打印。
    
    **新护栏** `tools/verify_map_building_rooms.py`(自动纳入全量):
    - **从客户端源码真读**判据:正则取 `scripts/room/map_data.gd` 的 `const STREET_TYPES := [...]`
      (不另抄一份,否则护栏自己就是一个新的漂移源);
    - 字尾表从 **params** 读:`map.tail_street`/`map.tail_inner`(`data/params.json` 的 `params` 袋内,点号键);
    - 按**客户端判据**重算(街面=type ∈ 表 或 名字 `·` 后段以字尾结尾;楼内=type==interior 且名字不以街面字结尾,
      无 type 时客户端另有 `tail_inner` 兜底——本脚本照抄);再与工具 `map_building.buildings()` 比集合。
    
  • 版本 1.0.359 开发日志

    构建 1.0.359(code 359)· 2026-10-02 02:44:14 · sha256 c35b703fc90c011a…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-02 02:43:42 | 本包:kushan-1.0.359.apk(1.0.359 / code 359,sha256 c35b703fc90c011a…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-B037-RECUR  (2026-10-02 02:30:59)
    
    # TASK-B037-RECUR · B-037 结案 + 同类复发(**已收口**)
    
    **日期**:2026-10-02 02:40 | **包**:1.0.358(真机 `R3CR704Q72V`)
    
    ## 一、B-037 原判据的处置:**对象已不存在**
    `scripts/room/shop_panel.gd` 已随 41 号 §九十四 S3(b) 退场(文件实测不存在;`room_view.gd` 已不再引用)⇒ 「商店面板点不动」在当前代码里**无法复现**(面板本身没了)。**不因此只写「消解」就完事** —— 该缺陷的机制是**复发类**:
    `room_layout.gd` 内已有 4 处带「真机实测」注释的 `mouse_filter = MOUSE_FILTER_IGNORE` 处置(全屏底色/场景图/描述层…),说明「装饰层默认 STOP 把点击吃掉」在这个仓反复出现过。
    
    ## 二、复发网(新工具,**故意不叫 `verify_`**)
    `tools/scan_click_eaters.py` —— 扫房间界面里 `TextureRect/RichTextLabel/ColorRect/Panel/Label.new()` 的**非按钮变量**,看其后 40 行内是否显式 `MOUSE_FILTER_IGNORE`,列出候选。
    按仓库纪律(假阳性未清零前不得带 `verify_` 前缀、不进全量闸门),它是**给人看的候选清单**,输出落 `scan_click_eaters.txt`。
    
    **扫描结果与逐条裁决**(29 个文件,3 处已显式 IGNORE):
    ```
    ① scripts/room/map_screen.gd:120  bg = ColorRect.new()      → 不修:全屏地图遮罩,**应该**吃掉点击(挡住下层房间)
    ② scripts/room/room_person.gd:55  tr = TextureRect.new()     → ★修:立绘是装饰,父面板 p 才接交谈
    ③ scripts/room/room_refresh.gd:260 rt = RichTextLabel.new()  → 不修:出口「点文字走过去」的点击目标
    ```
    
    ## 三、本轮实修(②)+顺手收拾(遗留探针)
    1. `scripts/room/room_person.gd`:立绘 `TextureRect` 补 `mouse_filter = Control.MOUSE_FILTER_IGNORE`
       —— 父面板 `p` 已是 `STOP` 且 `gui_input` 接交谈;子层吃点击 ⇒ 表现就是「点立绘/名字(立绘范围内)没反应」,与 B-037 同机制。
    2. `scripts/room/room_refresh.gd:82`:**遗留探针**原先「每进一间房无条件扫屏打日志」(其上游注释写「验完即删」却一直在)⇒ 改 cfg 门控(`HIT_X/HIT_Y` 或 `MENU_DUMP=1` 才跑),生产零影响。
    
    ## 四、真机取证(1.0.358)
    ```
    (a) cfg 带 HIT_X/HIT_Y=470,760 ⇒ 探针行数=7   ← 探针功能保留,可继续做命中排查
    (b) cfg 不带                    ⇒ 探针行数=0   ← 门控生效,生产不再白扫屏/刷日志
    KUSHAN_HIT 点(470.0, 760.0) 命中 4 层,最上层=/root/Main/RoomView/@MarginContainer@105/@VB…(面板在顶层,正常)
       候选含 /root/Main/RoomView/@TextureRect@113(场景图层的 TextureRect **确实参与命中** ⇒ 该机制在真机确实存在)
    ```
    截图:`room358.png`(同包同 cfg,房间正常渲染)。
    
    ## 五、未验(如实记)
    - 「点立绘/名字」的**手指点击**未在本机取证(该机折叠屏外侧触控注入不可用,历史 E-010/B-061 同因);本轮以**代码判据+命中层证据**收口。
    - ①③ 两处按裁决**不改**(理由见上),若日后真机发现同点位点不动,按本卡口径复跑 `scan_click_eaters.py` 复核。
    
    ### TASK-MAP-MODULE-DEPS  (2026-10-02 02:24:20)
    
    # TASK-MAP-MODULE-DEPS · MAP-08 单向依赖(**已收口**)
    
    **日期**:2026-10-02 02:20 | **口径**:68 号 MAP-08(行数项 2026-09-26 已作废 ⇒ 见 G-010「只查职责不查行数」)
    
    ## 新护栏 `tools/verify_map_module_deps.py`(已自动纳入全量)
    判据:四模块内部引用**只能是** `map_screen → {map_nav, map_data, map_render}`;基础件不得反向引用 `map_screen`、彼此不得互引、不得成环。
    
    **正测(现仓)**:
    ```
       map_nav     → (无)
       map_data    → (无)
       map_render  → (无)
       map_screen  → map_data、map_nav、map_render
       ✔ 单向成立:3 条边全部向下,无反向边、无环 / RESULT=PASS
    ```
    
    **反测(临时往 `map_nav.gd` 注入 `preload("res://scripts/room/map_screen.gd")`,跑完 `git checkout` 还原)**:
    ```
       ✗ map_nav ↔ map_screen(成环)/ ✗ map_screen ↔ map_nav(成环)/ RESULT=FAIL(2 处)
    ```
    
    护栏**非空过**(正反两测均如预期)。**职责项**(一功能一文件)由既有 `tools/verify_one_job_per_file.py` 把关,本件不重复。
    
    **行数(仅记录,不作判据)**:`map_nav` 97/`map_data` 167/`map_render` 62/`map_screen` 267 行。
    
    ### TASK-MAP-WALK  (2026-10-02 02:15:43)
    
    # TASK-MAP-WALK · 四层地图真机验收(MAP-01/02/03/04/07 · **已收口**)
    
    **日期**:2026-10-02 01:20-02:05 | **包**:1.0.356(真机 `R3CR704Q72V`,真屏 display 3 `4630947232161729155`)
    **工具**:`tools/qa_map_walk.sh`(三层取图 + 切换)、`tools/qa_map_back_ab.sh`(退层 + 开关 A/B)、`tools/map_shot_metrics.py`(量图)
    **驱动**:cfg 通道 `MAP_QA_LAYER` / `MAP_QA_STEPS`(`jump|back|down|layer:N`)——**不用 Params**:安卓上 `user://` 是应用私有目录,推参数够不着(技能 §8 实测),故把自检接到**外部 kushan.cfg**(与 `AUTO_ENTER`/`TRADE_QA_SAY` 同一条)。
    
    ## 关键读数(原始输出)
    
    **MAP-01 全屏不裁切**(`tools/map_shot_metrics.py`,基准 `map.safe_px=24`):
    ```
    L1.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1457} 内容带=7 均亮=22.7 ⇒ 四边留白达标
    L2.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1721} 内容带=8 均亮=22.2 ⇒ 四边留白达标
    L3.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1997} 内容带=6 均亮=20.6 ⇒ 四边留白达标
    ```
    机身实测:`mDisplayCutout insets=Rect(0,0-960,93)`(顶部挖孔带 93px)、`navigationBars mFrame=[0,2490][960,2616]`;**两条系统栏在本 App 内 `mVisible=false`**(沉浸)⇒ 地图内容(上边距 32px、底边距 ≥1457px)既不压系统栏也不进挖孔带。
    
    **MAP-02 四层可进可退**(同一跑内,层号 1→2→3;`back` 两步 3→2→1):
    ```
    KUSHAN_MAP_LAYER 落层 want=1(回总图)      KUSHAN_MAP_QA 落层 want=1 now=1
    KUSHAN_MAP_LAYER 落层 want=2 lid=2 rid=0 ok=true   KUSHAN_MAP_QA 落层 want=2 now=2
    KUSHAN_MAP_LAYER 落层 want=3 lid=2 rid=100 ok=true KUSHAN_MAP_QA 落层 want=3 now=3
    KUSHAN_MAP_BLOCKS L1 rooms=287 locs=10 blocks=10 key0_type=4
    KUSHAN_MAP_BLOCKS L2 lid=2
    KUSHAN_MAP_QA step=1 cmd=back 前层=3 / KUSHAN_MAP_BACK ok=true 层后=2
    KUSHAN_MAP_QA step=2 cmd=back 前层=2 / KUSHAN_MAP_BACK ok=true 层后=1
    ```
    三层截图 **md5 互不相同**(`b20e4c78` / `ac64a08a` / `6aa265f1`)= 视图真的随层变了。
    
    **MAP-03 总图⇄场景切换**(点两次「切换」= 调按钮同一函数 `_on_jump`):
    ```
    step=1 cmd=jump 前层=2 / KUSHAN_MAP_JUMP 层前=2 / step=1 cmd=jump 后层=1
    step=2 cmd=jump 前层=1 / KUSHAN_MAP_JUMP 层前=1 / step=2 cmd=jump 后层=1   ← 第二次无效(见 B-072)
    ```
    帧序列 `J2=b20e4c78(L1) / J3=ac64a08a(L2) / J4..J6=b20e4c78(L1)` = 同一次运行里两种视图都拍到。
    
    **MAP-04 三层画法一致**:三层内容带 7/8/6、均由同一 `map_render` 模块出图(`show_tiles`/`show_rows` 同一套块状画法,代码同一处),三层截图各具(见上 md5)。
    
    **MAP-07 可回退**(同一包,只改 cfg):
    ```
    abA_开关关.png md5=bb8fc1b6 四边留白={'左':0,'右':1,'上':0,'下':1} 均亮=25.0(世界视图)
    
    ### TASK-MAP-05-06  (2026-10-02 00:06:35)
    
    # TASK-MAP-05-06 · 地图线两项评测(**已收口**)
    
    **日期**:2026-10-02 00:05-00:15 | 来源:68 号 §补录十九(四层地图)
    
    ## MAP-05 · 客户端 L3 楼栋房间集合 == `tools/map_building.py` 同栋集合
    **口径**:抽样 10 栋**比集合**(脚本),不看截图。**本脚本比全部 67 栋**(比抽样更强),抽样 10 栋逐条打印。
    
    **新护栏** `tools/verify_map_building_rooms.py`(自动纳入全量):
    - **从客户端源码真读**判据:正则取 `scripts/room/map_data.gd` 的 `const STREET_TYPES := [...]`
      (不另抄一份,否则护栏自己就是一个新的漂移源);
    - 字尾表从 **params** 读:`map.tail_street`/`map.tail_inner`(`data/params.json` 的 `params` 袋内,点号键);
    - 按**客户端判据**重算(街面=type ∈ 表 或 名字 `·` 后段以字尾结尾;楼内=type==interior 且名字不以街面字结尾,
      无 type 时客户端另有 `tail_inner` 兜底——本脚本照抄);再与工具 `map_building.buildings()` 比集合。
    
  • 版本 1.0.358 开发日志

    构建 1.0.358(code 358)· 2026-10-02 02:31:11 · sha256 f932caf5baf3ae21…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-02 02:30:38 | 本包:kushan-1.0.358.apk(1.0.358 / code 358,sha256 f932caf5baf3ae21…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-MAP-MODULE-DEPS  (2026-10-02 02:24:20)
    
    # TASK-MAP-MODULE-DEPS · MAP-08 单向依赖(**已收口**)
    
    **日期**:2026-10-02 02:20 | **口径**:68 号 MAP-08(行数项 2026-09-26 已作废 ⇒ 见 G-010「只查职责不查行数」)
    
    ## 新护栏 `tools/verify_map_module_deps.py`(已自动纳入全量)
    判据:四模块内部引用**只能是** `map_screen → {map_nav, map_data, map_render}`;基础件不得反向引用 `map_screen`、彼此不得互引、不得成环。
    
    **正测(现仓)**:
    ```
       map_nav     → (无)
       map_data    → (无)
       map_render  → (无)
       map_screen  → map_data、map_nav、map_render
       ✔ 单向成立:3 条边全部向下,无反向边、无环 / RESULT=PASS
    ```
    
    **反测(临时往 `map_nav.gd` 注入 `preload("res://scripts/room/map_screen.gd")`,跑完 `git checkout` 还原)**:
    ```
       ✗ map_nav ↔ map_screen(成环)/ ✗ map_screen ↔ map_nav(成环)/ RESULT=FAIL(2 处)
    ```
    
    护栏**非空过**(正反两测均如预期)。**职责项**(一功能一文件)由既有 `tools/verify_one_job_per_file.py` 把关,本件不重复。
    
    **行数(仅记录,不作判据)**:`map_nav` 97/`map_data` 167/`map_render` 62/`map_screen` 267 行。
    
    ### TASK-MAP-WALK  (2026-10-02 02:15:43)
    
    # TASK-MAP-WALK · 四层地图真机验收(MAP-01/02/03/04/07 · **已收口**)
    
    **日期**:2026-10-02 01:20-02:05 | **包**:1.0.356(真机 `R3CR704Q72V`,真屏 display 3 `4630947232161729155`)
    **工具**:`tools/qa_map_walk.sh`(三层取图 + 切换)、`tools/qa_map_back_ab.sh`(退层 + 开关 A/B)、`tools/map_shot_metrics.py`(量图)
    **驱动**:cfg 通道 `MAP_QA_LAYER` / `MAP_QA_STEPS`(`jump|back|down|layer:N`)——**不用 Params**:安卓上 `user://` 是应用私有目录,推参数够不着(技能 §8 实测),故把自检接到**外部 kushan.cfg**(与 `AUTO_ENTER`/`TRADE_QA_SAY` 同一条)。
    
    ## 关键读数(原始输出)
    
    **MAP-01 全屏不裁切**(`tools/map_shot_metrics.py`,基准 `map.safe_px=24`):
    ```
    L1.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1457} 内容带=7 均亮=22.7 ⇒ 四边留白达标
    L2.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1721} 内容带=8 均亮=22.2 ⇒ 四边留白达标
    L3.png (960,2616) 四边留白={'左':32,'右':33,'上':32,'下':1997} 内容带=6 均亮=20.6 ⇒ 四边留白达标
    ```
    机身实测:`mDisplayCutout insets=Rect(0,0-960,93)`(顶部挖孔带 93px)、`navigationBars mFrame=[0,2490][960,2616]`;**两条系统栏在本 App 内 `mVisible=false`**(沉浸)⇒ 地图内容(上边距 32px、底边距 ≥1457px)既不压系统栏也不进挖孔带。
    
    **MAP-02 四层可进可退**(同一跑内,层号 1→2→3;`back` 两步 3→2→1):
    ```
    KUSHAN_MAP_LAYER 落层 want=1(回总图)      KUSHAN_MAP_QA 落层 want=1 now=1
    KUSHAN_MAP_LAYER 落层 want=2 lid=2 rid=0 ok=true   KUSHAN_MAP_QA 落层 want=2 now=2
    KUSHAN_MAP_LAYER 落层 want=3 lid=2 rid=100 ok=true KUSHAN_MAP_QA 落层 want=3 now=3
    KUSHAN_MAP_BLOCKS L1 rooms=287 locs=10 blocks=10 key0_type=4
    KUSHAN_MAP_BLOCKS L2 lid=2
    KUSHAN_MAP_QA step=1 cmd=back 前层=3 / KUSHAN_MAP_BACK ok=true 层后=2
    KUSHAN_MAP_QA step=2 cmd=back 前层=2 / KUSHAN_MAP_BACK ok=true 层后=1
    ```
    三层截图 **md5 互不相同**(`b20e4c78` / `ac64a08a` / `6aa265f1`)= 视图真的随层变了。
    
    **MAP-03 总图⇄场景切换**(点两次「切换」= 调按钮同一函数 `_on_jump`):
    ```
    step=1 cmd=jump 前层=2 / KUSHAN_MAP_JUMP 层前=2 / step=1 cmd=jump 后层=1
    step=2 cmd=jump 前层=1 / KUSHAN_MAP_JUMP 层前=1 / step=2 cmd=jump 后层=1   ← 第二次无效(见 B-072)
    ```
    帧序列 `J2=b20e4c78(L1) / J3=ac64a08a(L2) / J4..J6=b20e4c78(L1)` = 同一次运行里两种视图都拍到。
    
    **MAP-04 三层画法一致**:三层内容带 7/8/6、均由同一 `map_render` 模块出图(`show_tiles`/`show_rows` 同一套块状画法,代码同一处),三层截图各具(见上 md5)。
    
    **MAP-07 可回退**(同一包,只改 cfg):
    ```
    abA_开关关.png md5=bb8fc1b6 四边留白={'左':0,'右':1,'上':0,'下':1} 均亮=25.0(世界视图)
    
    ### TASK-MAP-05-06  (2026-10-02 00:06:35)
    
    # TASK-MAP-05-06 · 地图线两项评测(**已收口**)
    
    **日期**:2026-10-02 00:05-00:15 | 来源:68 号 §补录十九(四层地图)
    
    ## MAP-05 · 客户端 L3 楼栋房间集合 == `tools/map_building.py` 同栋集合
    **口径**:抽样 10 栋**比集合**(脚本),不看截图。**本脚本比全部 67 栋**(比抽样更强),抽样 10 栋逐条打印。
    
    **新护栏** `tools/verify_map_building_rooms.py`(自动纳入全量):
    - **从客户端源码真读**判据:正则取 `scripts/room/map_data.gd` 的 `const STREET_TYPES := [...]`
      (不另抄一份,否则护栏自己就是一个新的漂移源);
    - 字尾表从 **params** 读:`map.tail_street`/`map.tail_inner`(`data/params.json` 的 `params` 袋内,点号键);
    - 按**客户端判据**重算(街面=type ∈ 表 或 名字 `·` 后段以字尾结尾;楼内=type==interior 且名字不以街面字结尾,
      无 type 时客户端另有 `tail_inner` 兜底——本脚本照抄);再与工具 `map_building.buildings()` 比集合。
    
    **实跑输出**:
    ```
    客户端源码 STREET_TYPES=['street','alley','road','junction','plaza','court']
    params tail_street=['街','巷','道','路','市口','广场','口']
    params tail_inner=['院','厅','房','室','屋','阁','堂','厨','厩','库','铺','店','间','廊','楼','亭','舍','庄','宅','居']
    楼栋数:客户端判据 67 栋 | 工具 67 栋
      抽样 房2  外院      ⇒ 同   抽样 房5  内院      ⇒ 同   抽样 房17  旅店      ⇒ 同
      抽样 房103 白杨甸甸门 ⇒ 同   抽样 房104 沙枣屯屯口 ⇒ 同   抽样 房105 石桥驿驿站 ⇒ 同
      抽样 房110 香妃堡前庭 ⇒ 同   抽样 房211 村中巷     ⇒ 同   抽样 房221 庄中街     ⇒ 同   抽样 房231 甸中巷     ⇒ 同
    ✔ MAP-05:67 栋全部同集合(客户端判据 == 工具判据),抽样 10 栋逐条一致
    ```
    > 自查中发现并当场修掉一个**假绿**:首版取参数只查 JSON 顶层 ⇒ `tail_street=[]`(空表),
    > 比集合虽然也「全同」,但那是**空表比的假绿**(名字判据根本没参与)。修正为「先查 `params` 袋、再回落」后才取到真表
    > ——教训:**护栏自己取不到数据时必须报错/跳过,不能拿空表比出绿**。
    
    ## MAP-06 · 新增参数/文案/色全有值、无硬编码
    **验法**:`bash tools/run_verify_all.sh` 全绿。**实跑**:`PASS=87 FAIL=0`(读数 86→87 = 本轮新增 MAP-05 护栏)。
    
    ### TASK-B069-B071  (2026-10-01 23:52:25)
    
    # TASK-B069-B071 · 卖路径「挑错货 / 拼错键」收口(**已收口**)
    
    **日期**:2026-10-01 23:44-23:52 | **包**:1.0.352(已装机)
    
    ## 一、真因(三轮才追到,前两轮修丁都不够)
    1. **镜像缺键**:`trade_bridge.mirror_items()` 读了服务端 `item_key` 却**没写进镜像条目**(已修);但**启动来源不是它** ——
       启动背包来自**本地存档**(`game_state.gd:639 inventory = parsed.get("inventory", [])`),条目 `id=-2`、无 `item_key`。
    2. **名字匹配挑错货(B-071,真凶)**:弱匹配把「**共享一个字**」当成命中 ⇒ 说「我卖一份蜂蜜馕」时,
       `name_hit("干馕", …)`=0,但 `shares_char("干馕","我卖一份蜂蜜馕")` 命中「馕」⇒ 唯一的 weak 候选被采纳 ⇒ 选中**开局背包的「干馕」**(
       非商店货、id=-2)⇒ 拼出 **`shop_21_-2`** ⇒ 服务端以「商品不在该商店货架」拒。
       注:「干馕」是 `data/params.json` 的开局背包物(水囊/干馕),与服务端 `data/world.json` 的「蜂蜜馕」**不是同一件货**;
       `grep 干馕` 全仓只此一处(开局背包),非数据打架 ⇒ 问题在**匹配过宽**。
    
    ## 二、修法(纯客户端,不动网关契约)
    - **弱匹配收严**(`dialogue_trade.gd` 两处:商店匹配 + 背包匹配):货名 **≥3 字**才允许「共享一个字」算命中。
      ⇒ 2 字的「干馕」不再能靠一个「馕」混进来;而「我买串」→`烤羊肉串`(4 字、共享尾字)这类口语简写**依旧可用**。
    - **键不合法就不发请求**(B-069 加固):拿不到 `^shop_\d+_\d+$` 形状的键时**直接回一句明白话**(复用既有 i18n 键 `ui.room.t165`),
      **绝不**拿硬拼键去撞服务端、也绝不把撞出来的错回执当成交易结果报给玩家。
    
  • 版本 1.0.357 开发日志

    构建 1.0.357(code 357)· 2026-10-02 02:26:19 · sha256 4c4f58f0c3c7c2c6…

    下载:公网 · Tailscale · 局域网

    开发日志(末尾摘录)

    
    ---
    
    ## 2026-09-16 — 登录页必现 + 主界面太阁风格方向(现场记录)
    
    **做了什么**
    1. 登录页必现:main.tscn 无条件加载 login.tscn + 「进入游戏」按钮常显,点击进主界面(3 文件:project.godot/main.gd/login.gd)
    2. 修复 project.godot autoload 丢失 LoginState(游戏 break 根因,已用 MCP autoload_manage 加回)
    3. 皮肤试改「大航海米黄羊皮纸」→ **用户否定**:「还不如原来的颜色配比」,直指我做了廉价平涂米黄,丢了深色+金饰的质感和层次
    4. 用户明确:**进去以后的主页面要「太阁立志传样式」**(非大航海)。面板配色已回滚为深色+金色(ui_helpers.gd panel 深棕 0.16,0.14,0.11 + 金边 0.72,0.55,0.30)
    5. APK 打包 v1.0.18(29,056,887 字节,sha256 fe4c43cc)已出,Tailscale 8900 分享中
    
    **验证了什么**
    - Godot 无头 + MCP editor_state 确认登录页完整、进入游戏按钮常显、点击切到 /Main/Room_13
    - 截图 img_a10eb83fbe19(登录页)/img_fcb3ae33e678(房间) 像素分析命中大航海配色
    - **教训**:UI 皮肤改动前必须保留原深色+金色质感和层次对比,只加主题元素,禁止推倒重涂底色。改前先出方案确认
    - 本会话聊天记录已上传 backup_center.chat_transcripts(kushan, 5 条)
    
    **下一步(待用户确认太阁主界面具体布局)**
    - 主界面/主菜单改造为太阁立志传式(居中竖排日式菜单、卷轴/印章按钮、大标题)
    - 参考既有 `UI_GAMEPLAY_DESIGN_大纲.md` §0.2(羊皮纸#D8C29A+暗金#A98C4A+深蓝#1B3A5C)——但用户要的是太阁样,需重询配色与布局
    
    ---
    
    ## 2026-09-16 — 建立开发证据链体系 + 游戏界面开发大纲
    
    **做了什么**
    1. 基于大航海4 ROTA NOVA 手机版 UI 拆解,撰写游戏界面开发大纲
    2. 建立本证据链体系(README + 4 支柱文档)
    
    **验证了什么**
    - 大纲落地:`docs/UI_GAMEPLAY_DESIGN_大纲.md`(9,303 字节)
    - 证据链目录建立:`docs/DEVELOPMENT_LOG/`(本目录 5 文件)
    - 已核对项目现状:`KUSHAN_FRAMEWORK.md`(5层结构)`UI_NUMBERS_LOCKED.md`(数值定版)`TASK_mobile_ui_20260913.md`(手机适配)
    
    **产出了什么**
    - `docs/UI_GAMEPLAY_DESIGN_大纲.md`
    - `docs/DEVELOPMENT_LOG/{README,01_开发大纲,02_开发日志,03_任务计划书,04_版权与素材溯源}.md`
    
    ---
    
    ## 2026-09-13 — v1.0.4 竖版 UI 定版交付(历史归档)
    
    > 完整记录见 `../RESUME_20260913.md`
    
    **做了什么**
    1. 消息窗改为紧贴动作栏上方独立停靠面板(不进页面滚动区)
    2. 修 `scroll_following` 对 append_text 不生效、最新一条看不见
    3. 动作按钮 62 / NPC 行 50 定版(88 会挤掉名单,已定版)
    4. 年份 1889→1620,修 Godot 4 把 JSON 数字解析成 float 显示 `1620.0春`
    
    **验证了什么**
    - 7 个 NPC 全部一屏可见(桌面渲染 + OCR 实测)
    - 状态栏显示 `1620春`
    - APK 出包 sha256 `4DDCB6C65EF44CFFEC3435F32D19530AD7858636260F45AE5DAAF45575F9E2F7`
    
    **产出了什么**
    - `C:\kushan_out\kushan-portrait-v4.apk`(26,640,806 字节)
    - `203:/srv/fileshare/kushan-dynasty-v1.0.4-portrait.apk`
    - `C:\kushan_out\kushan_src_20260913.zip`(源码备份)