Category: Uncategorized

  • 版本 1.0.402 开发日志

    构建 1.0.402(code 402)· 2026-10-04 05:10:14 · sha256 df0502b16ff0e8fc…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 05:06:10 | 本包:kushan-1.0.402.apk(1.0.402 / code 402,sha256 df0502b16ff0e8fc…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.401 开发日志

    构建 1.0.401(code 401)· 2026-10-04 04:57:12 · sha256 e53b236418409f2b…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 04:53:12 | 本包:kushan-1.0.401.apk(1.0.401 / code 401,sha256 e53b236418409f2b…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.400 开发日志

    构建 1.0.400(code 400)· 2026-10-04 04:21:26 · sha256 02aec4d5da31a1f6…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 04:17:06 | 本包:kushan-1.0.400.apk(1.0.400 / code 400,sha256 02aec4d5da31a1f6…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.399 开发日志

    构建 1.0.399(code 399)· 2026-10-04 03:48:21 · sha256 7d1674b34bd2a13a…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 03:43:56 | 本包:kushan-1.0.399.apk(1.0.399 / code 399,sha256 7d1674b34bd2a13a…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.398 开发日志

    构建 1.0.398(code 398)· 2026-10-04 03:28:03 · sha256 f13bccfb5cad07ff…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 03:23:34 | 本包:kushan-1.0.398.apk(1.0.398 / code 398,sha256 f13bccfb5cad07ff…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.397 开发日志

    构建 1.0.397(code 397)· 2026-10-04 03:15:18 · sha256 2345b8b707b5c01b…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 03:11:12 | 本包:kushan-1.0.397.apk(1.0.397 / code 397,sha256 2345b8b707b5c01b…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.396 开发日志

    构建 1.0.396(code 396)· 2026-10-04 02:52:09 · sha256 5f6c588c73ed2820…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 02:48:02 | 本包:kushan-1.0.396.apk(1.0.396 / code 396,sha256 5f6c588c73ed2820…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.395 开发日志

    构建 1.0.395(code 395)· 2026-10-04 01:40:58 · sha256 55f99340fb5c95ee…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 01:36:45 | 本包:kushan-1.0.395.apk(1.0.395 / code 395,sha256 55f99340fb5c95ee…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.394 开发日志

    构建 1.0.394(code 394)· 2026-10-03 21:31:53 · sha256 1c233762370be27d…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-03 21:27:48 | 本包:kushan-1.0.394.apk(1.0.394 / code 394,sha256 1c233762370be27d…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |
    
    
  • 版本 1.0.393 开发日志

    构建 1.0.393(code 393)· 2026-10-03 21:24:06 · sha256 74ccc532f556ad74…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-03 21:20:00 | 本包:kushan-1.0.393.apk(1.0.393 / code 393,sha256 74ccc532f556ad74…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-CINE-PACK  (2026-10-03 01:39:43)
    
    # B-078 资源包化:过场片移出 APK、按需下载(用户令 2026-10-02「视频丢到资源包」)
    
    ## 现状摸底(本轮实测)
    - 包内片源:`assets/cine/*.ogv`(15 个文件,仓内 41MB;APK 内约 **20MB**:`21_first.ogv` 4.5MB、`25_first` 4.4MB、`23_first` 3.7MB、`1_first` 3.1MB、`37_first` 2.8MB…)。
    - 取件机制**已具备一半**:`scripts/cine_lib.gd` 与立绘同款 —— `user://cine/` 缓存 + 在线清单 `user://cine/index.json` + **包内目录兜底**(`resolve()`:本地缓存 → 包内;网络归 net 层,本模块不碰网络)。
    - 导出排除表**已有先例**:`export_presets.cfg` 的 `exclude_filter` 里已排除 `assets/portraits/*`,**但没排 `assets/cine/*`** ⇒ 这是「移出 APK」那一步的落点。
    - **缺的那一半**:立绘有下载器(`scripts/room/portrait_fetch.gd`、`profile_view.gd`、`npc_panel.gd` 调 `PL.save_disk`),**过场片没有下载器**(`cine_player.gd` 只调 `CL.resolve()`)。
    - 托管落点现成:nw 站的 `/files/`(203 站点目录 `/mnt/data2/www/wwwroot/kushan-nw/files/` → 公网 `https://nw.tripee.cn/files/`、Tailscale `http://100.127.177.38:8088/files/`、局域网 `http://192.168.50.203:8088/files/`),镜像到云机 `/srv/kushan-files/`。
    - 相关参数:`cine.online_base`(**当前为空**)、`cine.ext=.ogv`、`cine.cache_max_mb=64`。
    
    ## 实施方案(按 107 号 S0→S8,一功能一文件)
    1. 新增 `scripts/room/cine_fetch.gd`(对照 `room/portrait_fetch.gd`):按 `cine.online_base` 拉 `index.json` → 按名拉 `.ogv` → `CL.save_index()`/`CL.save_disk()`;三基址候选(公网/Tailscale/局域网)照 `net_endpoints` 口径。
    2. `cine_player.gd` 在 `CL.resolve()` 返空且 `CL.index_has()` 为真时调取件(**只补取件调用,不改播放逻辑**)。
    3. 上传:`assets/cine/*.ogv` → `/files/cine/`(203 本地 + 云机镜像),并生成 `/files/cine/index.json`(名→大小/sha256)。
    4. `data/params.json` 置 `cine.online_base`(三链取一,仍受「外网口径待人拍板」约束 ⇒ 先写内网基址,公网基址随更新通道一并拍板)。
    5. `export_presets.cfg` 在 `exclude_filter` 追加 `assets/cine/*`。
    6. 出包(预期 APK ≈131.8MB → **≈112MB**,即减掉片源那约 20MB)+真机验:**无缓存时能下载并播放**、**断网时优雅降级**(不卡死、不报脚本错)、再次进入离线可播。
    7. 护栏:新增 `tools/verify_cine_pack.py` —— ① 排除表必须含 `assets/cine/*`;② 仓内片源与远端清单逐条对齐(数量/大小);③ `cine.online_base` 非空且与 `tools/hosts.sh` 口径一致。
    
    ## 本轮边界
    - **未动任何片源与排除表**:在「下载器」落地前把包内兜底删掉=过场直接失播 ⇒ 先补取件、再拆包,顺序不能反(本轮只立项+摸底,未见红)。
    
    ## 1.0.389 重出(排除表改走参数)
    
    ## 1.0.389 出包与真机(本轮收尾)
    - APK:**112721647 字节**(改前 1.0.388=131846522);包内 `\.ogv` 条目=**0**、`assets/cine/` 条目=0
    - 资源包:203 站点 5 片+index.json(18.6MB),云机镜像 6 文件;三链回读 200(公网/Tailscale/局域网)
    - 真机 `[Cine] got` 命中=0(清端上 `files/cine` 缓存后跑)
    - 护栏:`python3 tools/verify_cine_pack.py` ⇒ PASS 4 FAIL 0;全量 `run_verify_all.sh` ⇒ PASS 96 FAIL 0
    - **真因**:[1/6] 备份 preset+params、把签名库路径替换成本机路径、注入排除过滤表(版本=standard)
      已把 pack.edition 设为 standard,排除表 assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*
      已替换 keystore/release 与 keystore/debug
      exclude_filter=assets/portraits/*,evidence/*,docs/*,tasks/*,tools/*,data/private/*,edition/*,dist/*,addons/gut/*,kushan_db/*,backup_archive/*,tests/*,release/*,instances/*,_cl_/*,.venv/*,*.md,*.py,*.sh,*.sql,*.log,assets/cine/*(22 条)
      package/unique_name=com.kushan.dynasty
      应用名=贵霜帝国(出包后还原 project.godot)
    [2/6] 装配原生插件(真源 android_plugins/ → 构建模板 android/build/;幂等)
      [assemble] kushanmic/KushanMicPlugin.java → java/org/godotengine/plugin/kushan/KushanMicPlugin.java
      [assemble] manifest 已有注册 org.godotengine.plugin.v2.KushanMic(不动)
      [assemble] 装配完成:java 1 个,meta-data 1 条
      [assemble] wrapper 已是镜像源(不动)
    
    ### TASK-PKG-SIZE  (2026-10-02 21:55:55)
    
    # 包体构成与可裁项(2026-10-02·深化轮)
    
    ## 实测(1.0.388)
    - APK 总大小:**131846522 字节**(≈131.8MB)
    - sha256:`53a9c0cfc29ee1814d50ac48510f4eb3…`
    
    ## APK 内最大条目(unzip -l 实测)
    ```
         178.4 MB  
          67.8 MB  lib/arm64-v8a/libgodot_android.so
           4.9 MB  classes.dex
           4.5 MB  assets/assets/cine/21_first.ogv
           4.4 MB  assets/assets/cine/25_first.ogv
           3.7 MB  assets/assets/cine/23_first.ogv
           3.1 MB  assets/assets/cine/1_first.ogv
           2.8 MB  assets/assets/cine/37_first.ogv
           1.6 MB  assets/data/world.json
           1.5 MB  assets/.godot/imported/game_serif_sc.otf-fee6e8dbe9021132ab5d30e59a28dc70.fontdata
           1.3 MB  lib/arm64-v8a/libc++_shared.so
           1.2 MB  assets/.godot/imported/orchard_gate.png-2913d0a41c09cf2923d4b4c21b829fd3.ctex
           1.2 MB  assets/.godot/imported/bazaar_day.png-e23e46e519d2ead442183eab5a88ff55.ctex
           1.1 MB  assets/.godot/imported/bazaar_day.png-0c55d8c07ebe6adf1265f6e250f76503.ctex
    ```
    
    ## 仓内 assets 各大类(真源,非 APK 内)
    ```
    1.9G	assets/portraits
    59M	assets/avatars
    41M	assets/cine
    30M	assets/scenes
    14M	assets/refcards
    6.9M	assets/audio
    2.0M	assets/fonts
    1.7M	assets/companion
    1.7M	assets/branding
    28K	assets/textures
    12K	assets/ui
    assets 合计: 2.1G
    ```
    
    
    ### TASK-DEEPEN-20261002  (2026-10-02 21:39:54)
    
    # 深化轮 2026-10-02:技术债/一致性清点(不依赖用户拍板的部分)
    
    ## ① `verify_track_wire` 偶发红 → 实测已不复现(本项收口)
    历史记录(memory/待人否清单)称「`verify_track_wire` 套件偶发红、单跑绿」。本轮实测:
    ```
    run1: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run2: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    run3: rc=0 | === 埋点护栏:PASS=5 FAIL=0 ===
    ```
    外加全量 `run_verify_all.sh` ⇒ **PASS=95 FAIL=0**(该件在回归里同样绿)。⇒ 该项**已不复现**,从待人否清单移除。
    
    ## ② 68 号状态列读取的坑(自记,防再踩)
    用「按 `|` 切列取最后一格」的脚本读 68 号状态**不可靠**:① 部分行以 `|` 结尾 ⇒ 末格为空;② 单元格内含**字面 `|`**(如 B-039 判据里的 `买 …|把 … 卖出去`)⇒ 切列错位。
    后果:本轮先误判 B-038/39/40、B-066、B-046 为「未验」。**正解**:直接在该行里找状态标记的**成对形态**(`✅ **已` / `⚠️ **` / `🚧 **`),或读主行的第 3 格(状态列)而非末格。
    
    ## ③ 本轮已收口的相邻项
    B-046(运维默认值不再指 52+新护栏,见 `evidence/TASK-B046-HOSTS/`)、B-049/B-050/B-041(见 `evidence/TASK-TUTORIAL-WALLET-STEP/` 与 `evidence/TASK-TUTORIAL-QA/`)。
    
    ### TASK-B046-HOSTS  (2026-10-02 21:30:19)
    
    # B-046 收口(地址单一真源)
    
    ## 判据
    「各脚本的 host 取单一真源、默认即云机」——迁移后网关/库真源在云机,运维脚本再跑不得把代码发回已降级的 52。
    
    ## 本轮改动(7 处有效默认值 → 真源)
    | 文件 | 改前默认 | 改后 |
    |---|---|---|
    | `tools/verify_m1_params.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203`(真源仓在 203) |
    | `tools/snapshot.sh` | `${SSH_HOST:-czdcc@192.168.50.52}` | `czdcc@192.168.50.203` |
    | `tools/backup_series.py` | `czdcc@192.168.50.52` | `czdcc@192.168.50.203` |
    | `tools/smoke_newbie_story.py` | `KUSHAN_MUD_HOST=192.168.50.52` | `100.123.201.98`(=`hosts.sh` 的 `KUSHAN_GW_HOST`) |
    | `tools/smoke_roomgraph_walk.py` | 同上 | 同上 |
    | `tools/smoke_mud_login.py` | 同上 | 同上 |
    | `tools/publish_external.py` | 写死 `czdcc@192.168.50.52` 与 `http://192.168.50.52:8000` | 外置 `KUSHAN_PUB_HOST`/`KUSHAN_PUB_BASE`(默认云机/公网前门)+**退役机拒发闸** |