版本 1.0.378 开发日志

构建 1.0.378(code 378)· 2026-10-02 15:56:05 · sha256 809824f6ea528b1d…

下载:公网 · Tailscale · 局域网

开发日志(本轮摘要)

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

生成时间:2026-10-02 15:51:04 | 本包:kushan-1.0.378.apk(1.0.378 / code 378,sha256 809824f6ea528b1d…)

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

### TASK-D14-AUDIT  (2026-10-02 15:12:02)

# TASK-D14-AUDIT —— 68 号 D-14「改动留痕可回滚」落地 + 回滚演练

## 判据(68 号 D-14)
> 每次改动有审计记录(谁/何时/哪场所/改前改后),可回滚 | 审计回读 + 回滚演练

## 落地(写库仍只走 `tools/wdb.sh`,闸门=系列备份)
- **审计表**:`docs/migrations/20261002a_domain_rule_audit.sql` → `domain_rule_audit`
  (只追加:scope_kind / scope_id / actor / action / reason / before_json / after_json / src_audit_id / created_at)
- **唯一写入端**:`tools/domain_rule_write.py`
  - `set`:读改前 → 同事务 upsert `domain_authority` + **追加审计行**(不会出现「改了没留痕」)
  - `rollback --audit-id K`:把 K 的 `before_json` 写回,并**再追加一条** action=rollback 的审计行(回滚本身留痕)
  - `history`:按场所回读全部改动(谁/何时/改前改后)
- **常驻护栏**:`tools/verify_domain_audit.py`(D.1 迁移件在册 · D.2 写 `domain_authority` 只许本写入端 ·
  D.3 规则写与审计 INSERT 同文件 · D.4 审计列面含「谁/哪场所/改前改后」)⇒ 已进 `run_verify_all.sh` 自动集

## 演练实证(原文见 `drill.txt`;真库真跑,地点=room 670 巴扎馕摊,主人=掌柜 21)
1. **改前**:无规则行、审计 0 行
2. **改①**(内室档 3):`[审计] id=1 action=set actor=QA-D14 before=None after={"inner":{"xiangfei_tier":3}}`
3. **改②**(内室档 5 + 禁用乳环):`[审计] id=2 … before={"inner":{"xiangfei_tier":3}} after={…5…}`
   ⇒ **改前改后都留下**,两笔改动可逐笔追溯
4. **回滚①**(回到改②之前):`[回滚后] rules={"inner":{"xiangfei_tier":3}}`=**字节级还原改①的值**;
   `[审计] id=3 action=rollback src_audit_id=2`
5. **回滚②**(回到「本无规则」):`rules=None`(置空、**不做 DELETE**);`[审计] id=4 action=rollback src_audit_id=1`
6. **审计回读**:4 行齐全(谁=actor / 何时=created_at / 哪场所=scope_kind+scope_id / 改前改后=before/after_json)
7. **护栏**:`VERIFY domain_audit: PASS`(D.1/D.2/D.3/D.4 全绿)

## 边界与口径(不谎报)
- **不做 DELETE**:回滚到「本无规则」时把 `rules_json` 置空(语义=无规则),避免删数据;表内留一行空规则。
- 演练留在 `domain_rule_audit` 的 4 行是**真实操作痕迹**(actor=QA-D14,reason=D-14 演练①②/回滚①②),
  按「只追加」纪律**不删**;`domain_authority` 中 room 670 现为 `rules_json=NULL`(=无规则,玩家不可见)。
- **本轮无客户端改动** ⇒ 不重出包(1.0.374 仍为最新)。
- 依赖模型链的「对话改世界」入口(B-19/B-26)仍挂外部额度;一旦通电,写入端就是本工具,**留痕/回滚自动生效**。

### TASK-B18-PRECEDENCE  (2026-10-02 14:56:53)

# TASK-B18-PRECEDENCE —— 68 号 B-18「三级优先级逐层兜底」实现 + 组合实证

## 判据(68 号 B-18)
> 主人规则 > 地方律令 > 世界默认,逐层兜底 | 三种组合各截一张图对照

## 实现(真源=`data/domain_rules.json` 的 `precedence` 原文,一级没规定才落下一级)
| 层 | 口径 | 本轮落地 |
|---|---|---|
| **L1 场所主人自定义规则** | `domain_rules.json`:伯克/店主人/一家之主/团队头目对自己地盘说了算(含女性着装) | 读**房间 `attrs.dress`**(客户端可得的口袋);`xiangfei_tier` 可覆盖档位、`ban_pieces`/`add_pieces` 出附加说明 |
| **L2 地方律令** | `data/laws_xiangfei.json`(L-01 着装令 / L-02 同行令…) | 生效编号 × 参数 `laws.dress_effects`(结构化映射,形如 `L-01:street.enforce_veil=1`)⇒ 只在与 `law.enabled_ids` 相交时生效 |
| **L3 世界默认** | `data/dress_spec.json` 的 modes/tiers | 前两层都没规定时的兜底 |

面板「装束」行末尾会写明**依据哪一层**(例如「(依 L-01 着装令)」「(依 世界默认)」),玩家看得见规矩从哪来。

## 组合实证(`KUSHAN_DRESS` 自报原文,`combos.txt`)
- **① L2 生效**:`cid=120 rtype=street tier=1 source=law by=L-01 着装令` ⇒ 街面罩袍强制靠地方律令
- **② L2 失效落 L3**(`KUSHAN_QA_CHAIN=l2off`):`source=world by=世界默认`
- **③ L1 最高**(QA 注入主人规矩「内室档位 5 + 禁用乳环」):`cid=10 source=owner tier=5`(**覆盖**由地位推得的 4 档)`…|本场所禁用:乳环(依 本场所主人规矩)`
- **④ 内室无律令命中落 L3**:`cid=10 source=world tier=4`
⇒ **逐层兜底成立**:L1 > L2 > L3 各有独立组合为证,且「依据」在文案里明写。

## 边界(未做,不谎报)
1. **L1 的真实记录世界数据里还没有**:`/api/world` 里只有 4 间房带 `owner_character_id`/`privacy`,**没有一条 `attrs.dress`**。
   组合③ 用的是 **QA 注入**(环境变量 `KUSHAN_QA_OWNER_JSON`,不动产品参数值/不改世界数据),验证的是**解析链与优先级**。
   真实记录要等「场所主权面板」(B-17:主人改规矩走界面)写入 `attrs.dress` 后**自动生效,无需改本模块**。
2. **出图取证的限制(如实记)**:NPC 卡片正文在 `ScrollContainer` 里,`--render-panel` 静态出图只拿到首屏 ⇒
   「装束」一节在折叠线以下**图上看不到**(我加了 `KUSHAN_RENDER_SCROLL=bottom` 门控想滚到底,实测**出图 md5 不变**=没生效)。
   ⇒ 本轮文字证据以 `KUSHAN_DRESS` **自报原文**为准(真实代码路径)+ 卡片整图作旁证;**取证工具这条局限另记待改**。

### TASK-DRESS-TIER  (2026-10-02 14:34:50)

# TASK-DRESS-TIER —— 装扮档位(场合 × 社会地位 → 档位与构件)落地 + 取证

## 判据(68 号)
- **D-12 装扮档位参数化**:立绘读 `dress_spec.json` tiers,界面代码零硬编码 | `grep` 界面脚本无饰具名硬编码
- **B-16 场合互斥生效**:街面绝不出现内室构件;内室绝不穿罩袍 | 街面截图 + 内室截图对照
- 关联:**D-10 外出罩袍外形** / **D-11 内外两形立绘**(这两条的「形」要美术层,见下「边界」)

## 本轮做了什么(此前客户端**零消费** `dress_spec.json`:只有 tools 读它)
1. **新模块** `scripts/dress_tier.gd`(123 行,纯算不画,单一职责)
   - 读真源 `data/dress_spec.json`(70 号 §四 外出罩袍+内室香妃式饰具;用户令 2026-09-23)
   - 场合:房间 `type` ∈ 参数 `dress.inner_room_types` ⇒ 内室,否则外出
   - 档位:参数 `dress.tier_from_status`(`地位:档位` 映射)+ `dress.max_tier` 封顶
   - 适用性别:参数 `dress.apply_gender`(默认 female ⇒ 只有女眷出装束行)
   - **档名/构件名/规则文字全部读数据文件**,代码里没有一件饰具名(满足 D-12 后半句)
2. **呈现**:NPC 卡片(`scripts/npc_panel.gd`)新增「装束」一节(`_dress_text()`)
3. **参数**(`data/params.json`,组 `装扮`):`dress.inner_room_types` / `dress.tier_from_status` / `dress.max_tier` / `dress.apply_gender`
4. **文案**(`data/i18n.json`):`npc.panel.dress_title` / `dress_na` / `dress_tier_n`

## 真机/渲染原文(`KUSHAN_DRESS` 自报,`KUSHAN_DRESS_DUMP=1` 门控;命令:headless 跑 `--render-panel npccard:<cid>`)
```
cid=10   gender=female status=4 room=6   rtype=interior tier=4
        text=内室(家内/内院)(隐秘(深宫禁锢):蒙眼睛·勒嘴(封口)·双手在后(背缚 + 腕链)·双手合十被反绑)
cid=6    gender=female status=3 room=587 rtype=interior tier=3
        text=内室(家内/内院)(高阶(勋贵/宗教世家):束腰·脚链 + 三寸金莲·臂环·长手链(链束双腕)·大腿环 + 贞操带·乳环 + 金链·肚脐红宝石)
cid=17   gender=female status=1 room=5   rtype=court    tier=1
        text=内室(家内/内院)(常备(平民内室):束腰·脚链 + 三寸金莲·臂环·长手链(链束双腕))
cid=120  gender=female status=1 room=19  rtype=street   tier=1
        text=外出(街面)·罩袍覆身、面纱只露双目、手不外露;男子须有男性亲属陪同(L-02)
cid=77   gender=female status=1 room=522 rtype=street   tier=1   text=(同外出口径)
```
⇒ **B-16 场合互斥在数据/规则层成立**:街面**只**给罩袍、内室**只**给饰具,两套互斥;档位按地位分(1/3/4 档各不同)。

## 本轮抓到的两个真问题(都已修)
1. **`room_id` 是 float**:JSON 数字在 GDScript 里是 float ⇒ `str(6.0)` = `"6.0"` 与房键 `"6"` 不匹配 ⇒ 判定**一律落「外出」**(我第一版就是这结果,被自报逮到)。
   修法=`str(int(room_id))` 归一(`dress_tier.gd` + 自报同源)。**教训**:客户端所有「拿 id 当字典键」的地方都要按 `str(int(...))` 归一。
2. **i18n 护栏抓真问题**:`dress_tier.gd` 里 `"%d 档"` 是玩家可见字面量 ⇒ 外置成 `npc.panel.dress_tier_n`(这正是 C1.1 存在的意义)。

## 边界(未做,不谎报)
- **D-10「外出罩袍外形」/D-11「内外两形立绘」仍是美术缺口**:`assets/portraits/` 里**没有**罩袍/饰具图层(`find` 无 `veil/chador/cloak/overlay` 命中),
  `dress_spec.modes.*.art` 也写着「新增外出外形一层;既有 111 张立绘不重画」 ⇒ 本轮只把**档位与构件名算对并呈现**,

### TASK-D0078-UI-THEME  (2026-10-02 14:05:45)

# TASK-D0078-UI-THEME —— 四界面同主题目视核对(68 号 D-007 / D-008)

真机:三星 R3CR704Q72V · **1.0.372** · 960×2616(真屏 id `4630947232161729155`)· 房 19「富贵街北」(香妃镇)
取图方式:**真点**(轨迹球物理 `(880,2525)` → 菜单自报各项中心 → 点其物理中心),非 QA 脚本跑

## 目视四图(`md5` 各不相同 ⇒ 确实换了界面)
| 图 | 界面 | md5 前 8 | 在哪取的 |
|---|---|---|---|
| `d007_room.png` | 房间页 | `a783fe4a` | 进房后直接截 |
| `d008_shop.png` | 商店 | `9df36a75` | 菜单「🛒 商店」中心逻辑 `(519.5,883)`→物理 `(692,1177)` |
| `d008_dialogue_say.png` | 对话(旅伴聊天面板) | `29485006` | 菜单「🧭 旅伴」中心逻辑 `(519.5,547)`→物理 `(692,729)` |
| `d008_battle2.png` | 战斗(遭遇战·选敌) | `2d359718` | 菜单「⚔ 遭遇战」中心逻辑 `(519.5,967)`→物理 `(692,1289)` |