Category: Uncategorized

  • 版本 1.0.413 开发日志

    构建 1.0.413(code 413)· 2026-10-04 22:28:56 · sha256 262fde96d79b96dd…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 22:23:48 | 本包:kushan-1.0.413.apk(1.0.413 / code 413,sha256 262fde96d79b96dd…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-ART-ROSTER  (2026-10-04 20:49:49)
    
    # 口径说明 · 323 人 NPC 相片槽位排产表
    
    生成时间:2026-10-04 20:49:49 | 仓库:`/mnt/data2/home_czdcc/kushan_main`
    
    本目录交付件:
    
    | 文件 | 用途 |
    |---|---|
    | `roster.md` | 人读排产表,按优先级分三节列出全部 323 人 |
    | `roster.csv` | 机器可读版,UTF-8 带表头,一 NPC 一行 |
    | `readme.md` | 本文件,口径说明 |
    | `_roster_data.json` | 生成中间件(全量行 + 汇总),供下游程序消费 |
    
    ## 1. 任务口径
    
    - 画风取 **甲案**:沿用犍陀罗写实油画(不换画风、不重炼风格)。
    - 老图 **646 张不重出**;本表只排「缺失槽位」的新增出图。
    - 覆盖全库 **323** 名 NPC(`characters.type='npc'`)。
    - **甲案的代价**(须知悉):老图沿用,与「本作自定画风」新线**不同源**,将来短片/场景图接起来会有风格落差;好处是零重出成本、已认过的脸不变、老图整份留档可回退。
    
    ## 2. 数据真源(全部只读;生成脚本不含任何硬编码数值)
    
    | 口径 | 真源 |
    |---|---|
    | 每人槽位/档位 | `data/npc_photo_slots.json`(`character_rank.tier` 落档结果,323 行) |
    | 槽位与张数规则 | `data/npc_performance.json` → `photos.count_by_tier`(low/mid/high = 2/3/5) |
    | 身份档位落档表 | `data/npc_rank_map.json`(title → tier 1–10) |
    | 装扮档位映射 | `data/params.json` → 键 `dress.tier_from_status` / `dress.max_tier` |
    | 归属房间/聚落、身份 | `kushan` 库:`characters` / `rooms` / `locations` |
    | 剧情挂靠 | `kushan` 库:`quest_chains.entry_npc_id` / `quest_templates.giver_id`(`active=1`) |
    | 现有老图 | `/srv/fileshare/kushan_photos/`(对外前缀 `/kushan_photos/`) |
    | 逐人出图 prompt | `data/npc_prompts_full.json`(323 条;出图时拼 `[风格块] + [本人 prompt] + [负向禁性表]`) |
    
    取库凭据一律走仓内唯一通道 `bash tools/query_kushan.sh "<SQL>"`——脚本**不连库、不内嵌口令**。
    
    ## 3. 槽位与张数规则(按身份档 → 2/3/5 张)
    
    | 带 | 身份档位 | 每人槽位 | 张数 | 已有 | 缺口/人 |
    |---|---|---|---|---|---|
    | low | 1–3 | avatar, full | 2 | 2 | 0 |
    
    ### TASK-D13  (2026-10-04 20:39:58)
    
    # TASK-D13 · 装扮规则链「随规则变」取证
    
    判据(68 号 D-13):同一房间换主人规则后,立绘装扮随之改变 | 改前/改后两张并排截图。
    
    ## 复跑命令(原始命令,可重放)
    
    渲染入口:`--render-panel npccard:<cid> --render-output <绝对路径>.png`。
    坑一:`--headless` 直跑 `save_png` 返回 **err=-1**(不出图),必须 `xvfb-run`。
    坑二:注入 JSON 的 mode 键必须是 `dress_tier.gd` 的 `MODE_INNER` 值 **`inner`**(不是 `interior`),否则静默回落世界默认。
    
    ```bash
    export HOME=/home/czdcc
    export KUSHAN_QA_CHAIN=l1          # 走 L1 主语链;改前留空
    export KUSHAN_QA_OWNER_JSON='{"inner":{"xiangfei_tier":5}}'   # 改后;改前不设
    export KUSHAN_DRESS_DUMP=1
    G="/mnt/data2/home_czdcc/贵霜帝国/godot/Godot_v4.7.2-stable_linux.x86_64"
    xvfb-run -a "$G" --path /home/czdcc/kushan_main -- \
      --render-panel npccard:10 --render-output /home/czdcc/kushan_main/evidence/TASK-D13/card_cid10_after.png
    ```
    
    同 cid=10(房间 6,rtype=interior)、同一张卡、同一次渲染入口,只改「场所主人规矩」注入。
    
    ## 自报原文(主证)
    
    改前(无注入):
    ```
    KUSHAN_DRESS cid=10 rtype=interior tier=4 source=world by=世界默认 qa=l1
    text=内室(家内/内院)(隐秘(深宫禁锢):蒙眼睛·勒嘴(封口)·双手在后(背缚 + 腕链)·双手合十被反绑)(依 世界默认)
    ```
    
    改后(注入 L1 主人规矩 tier=5):
    ```
    KUSHAN_DRESS cid=10 rtype=interior tier=5 source=owner by=本场所主人规矩 qa=l1
    text=内室(家内/内院)(顶点(图腾):完全禁锢组合:蒙眼 + 勒嘴 + 反绑 · 完整徽章:乳环 + 肚脐红宝石 + 双金链 + 束腰带)(依 本场所主人规矩)
    ```
    
    ⇒ **规则链层「随规则变」成立**:tier 4→5、source world→owner、by 与依据行、装束文本全部随注入改变。
    
    ## 未达部分(如实记,不遮掩)
    
    
    ### 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/;幂等)
    
  • 版本 1.0.411 开发日志

    构建 1.0.411(code 411)· 2026-10-04 21:39:58 · sha256 176c290fa101f6ad…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 21:35:11 | 本包:kushan-1.0.411.apk(1.0.411 / code 411,sha256 176c290fa101f6ad…)
    
    ## 最近开发任务证据(evidence/*/readme.md,新→旧,取 10 份)
    
    ### TASK-ART-ROSTER  (2026-10-04 20:49:49)
    
    # 口径说明 · 323 人 NPC 相片槽位排产表
    
    生成时间:2026-10-04 20:49:49 | 仓库:`/mnt/data2/home_czdcc/kushan_main`
    
    本目录交付件:
    
    | 文件 | 用途 |
    |---|---|
    | `roster.md` | 人读排产表,按优先级分三节列出全部 323 人 |
    | `roster.csv` | 机器可读版,UTF-8 带表头,一 NPC 一行 |
    | `readme.md` | 本文件,口径说明 |
    | `_roster_data.json` | 生成中间件(全量行 + 汇总),供下游程序消费 |
    
    ## 1. 任务口径
    
    - 画风取 **甲案**:沿用犍陀罗写实油画(不换画风、不重炼风格)。
    - 老图 **646 张不重出**;本表只排「缺失槽位」的新增出图。
    - 覆盖全库 **323** 名 NPC(`characters.type='npc'`)。
    - **甲案的代价**(须知悉):老图沿用,与「本作自定画风」新线**不同源**,将来短片/场景图接起来会有风格落差;好处是零重出成本、已认过的脸不变、老图整份留档可回退。
    
    ## 2. 数据真源(全部只读;生成脚本不含任何硬编码数值)
    
    | 口径 | 真源 |
    |---|---|
    | 每人槽位/档位 | `data/npc_photo_slots.json`(`character_rank.tier` 落档结果,323 行) |
    | 槽位与张数规则 | `data/npc_performance.json` → `photos.count_by_tier`(low/mid/high = 2/3/5) |
    | 身份档位落档表 | `data/npc_rank_map.json`(title → tier 1–10) |
    | 装扮档位映射 | `data/params.json` → 键 `dress.tier_from_status` / `dress.max_tier` |
    | 归属房间/聚落、身份 | `kushan` 库:`characters` / `rooms` / `locations` |
    | 剧情挂靠 | `kushan` 库:`quest_chains.entry_npc_id` / `quest_templates.giver_id`(`active=1`) |
    | 现有老图 | `/srv/fileshare/kushan_photos/`(对外前缀 `/kushan_photos/`) |
    | 逐人出图 prompt | `data/npc_prompts_full.json`(323 条;出图时拼 `[风格块] + [本人 prompt] + [负向禁性表]`) |
    
    取库凭据一律走仓内唯一通道 `bash tools/query_kushan.sh "<SQL>"`——脚本**不连库、不内嵌口令**。
    
    ## 3. 槽位与张数规则(按身份档 → 2/3/5 张)
    
    | 带 | 身份档位 | 每人槽位 | 张数 | 已有 | 缺口/人 |
    |---|---|---|---|---|---|
    | low | 1–3 | avatar, full | 2 | 2 | 0 |
    
    ### TASK-D13  (2026-10-04 20:39:58)
    
    # TASK-D13 · 装扮规则链「随规则变」取证
    
    判据(68 号 D-13):同一房间换主人规则后,立绘装扮随之改变 | 改前/改后两张并排截图。
    
    ## 复跑命令(原始命令,可重放)
    
    渲染入口:`--render-panel npccard:<cid> --render-output <绝对路径>.png`。
    坑一:`--headless` 直跑 `save_png` 返回 **err=-1**(不出图),必须 `xvfb-run`。
    坑二:注入 JSON 的 mode 键必须是 `dress_tier.gd` 的 `MODE_INNER` 值 **`inner`**(不是 `interior`),否则静默回落世界默认。
    
    ```bash
    export HOME=/home/czdcc
    export KUSHAN_QA_CHAIN=l1          # 走 L1 主语链;改前留空
    export KUSHAN_QA_OWNER_JSON='{"inner":{"xiangfei_tier":5}}'   # 改后;改前不设
    export KUSHAN_DRESS_DUMP=1
    G="/mnt/data2/home_czdcc/贵霜帝国/godot/Godot_v4.7.2-stable_linux.x86_64"
    xvfb-run -a "$G" --path /home/czdcc/kushan_main -- \
      --render-panel npccard:10 --render-output /home/czdcc/kushan_main/evidence/TASK-D13/card_cid10_after.png
    ```
    
    同 cid=10(房间 6,rtype=interior)、同一张卡、同一次渲染入口,只改「场所主人规矩」注入。
    
    ## 自报原文(主证)
    
    改前(无注入):
    ```
    KUSHAN_DRESS cid=10 rtype=interior tier=4 source=world by=世界默认 qa=l1
    text=内室(家内/内院)(隐秘(深宫禁锢):蒙眼睛·勒嘴(封口)·双手在后(背缚 + 腕链)·双手合十被反绑)(依 世界默认)
    ```
    
    改后(注入 L1 主人规矩 tier=5):
    ```
    KUSHAN_DRESS cid=10 rtype=interior tier=5 source=owner by=本场所主人规矩 qa=l1
    text=内室(家内/内院)(顶点(图腾):完全禁锢组合:蒙眼 + 勒嘴 + 反绑 · 完整徽章:乳环 + 肚脐红宝石 + 双金链 + 束腰带)(依 本场所主人规矩)
    ```
    
    ⇒ **规则链层「随规则变」成立**:tier 4→5、source world→owner、by 与依据行、装束文本全部随注入改变。
    
    ## 未达部分(如实记,不遮掩)
    
    
    ### 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/;幂等)
    
  • 版本 1.0.410 开发日志

    构建 1.0.410(code 410)· 2026-10-04 18:26:02 · sha256 0b3c35dd536235af…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 18:22:00 | 本包:kushan-1.0.410.apk(1.0.410 / code 410,sha256 0b3c35dd536235af…)
    
    ## 最近开发任务证据(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.409 开发日志

    构建 1.0.409(code 409)· 2026-10-04 18:16:24 · sha256 8c297469910b48a1…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 18:12:23 | 本包:kushan-1.0.409.apk(1.0.409 / code 409,sha256 8c297469910b48a1…)
    
    ## 最近开发任务证据(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.408 开发日志

    构建 1.0.408(code 408)· 2026-10-04 07:04:26 · sha256 f8f1d552bae5046c…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 07:00:28 | 本包:kushan-1.0.408.apk(1.0.408 / code 408,sha256 f8f1d552bae5046c…)
    
    ## 最近开发任务证据(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.407 开发日志

    构建 1.0.407(code 407)· 2026-10-04 06:47:47 · sha256 498f5ba7d9925e1a…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 06:43:31 | 本包:kushan-1.0.407.apk(1.0.407 / code 407,sha256 498f5ba7d9925e1a…)
    
    ## 最近开发任务证据(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.406 开发日志

    构建 1.0.406(code 406)· 2026-10-04 06:30:19 · sha256 a38c8bb92cbd7be9…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 06:26:16 | 本包:kushan-1.0.406.apk(1.0.406 / code 406,sha256 a38c8bb92cbd7be9…)
    
    ## 最近开发任务证据(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.405 开发日志

    构建 1.0.405(code 405)· 2026-10-04 06:18:47 · sha256 c2a5443c2580e3c2…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 06:14:34 | 本包:kushan-1.0.405.apk(1.0.405 / code 405,sha256 c2a5443c2580e3c2…)
    
    ## 最近开发任务证据(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.404 开发日志

    构建 1.0.404(code 404)· 2026-10-04 06:01:28 · sha256 750507678dc1075a…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 05:57:20 | 本包:kushan-1.0.404.apk(1.0.404 / code 404,sha256 750507678dc1075a…)
    
    ## 最近开发任务证据(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.403 开发日志

    构建 1.0.403(code 403)· 2026-10-04 05:23:07 · sha256 12864d88b1cbc862…

    下载:公网 · Tailscale · 局域网

    开发日志(本轮摘要)

    # 贵霜帝国 · 内网开发版 · 本轮开发记录
    
    生成时间:2026-10-04 05:18:57 | 本包:kushan-1.0.403.apk(1.0.403 / code 403,sha256 12864d88b1cbc862…)
    
    ## 最近开发任务证据(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`(默认云机/公网前门)+**退役机拒发闸** |