奇物批T6b+T7+缺陷修:refresh入池(用户裁B案——CURIO_KINDS扩第七类/heal_rare 5→3挤占refresh_rare=2/总量98锚不变/match表两行/兑付=_attune_refresh_x增量不进加算区+registry pool_architecture多级缓存总池-渠道子集语义+契约10按裁更新);T7 charge缺陷登记(3件<4档二不可达——白名单4只登记不硬补,registry charge_defect);autoplay门票拿到即开分支(缺分支=节点停点悬空选路卡死——MC timeout形态批内实测,n20复现1/2空终局修后与基线逐位一致);任务书T6b裁决回写(冒烟782/0)

This commit is contained in:
DKChan committed 2026-10-05 20:58:34 +08:00
1 parent 95b66f0d60
commit ccd95c8215
7 files changed
+84 -3

No files matched your search

@@ -0,0 +1,61 @@
# 出口报告:迭代 15 卡② 奇物词族对齐与渠道分离批(2026-10-05)
> 任务书 = `design/research/任务书-奇物词族对齐与渠道分离批-2026-10-05.md`(T0 差异回写+T6b 裁决回写在册)。
> 设计事实源 = `design/gdd/systems/冒险循环/奇物.md` v2.7。worktree = `g-plan2-curio-wordfamily`,分支 `curio-wordfamily-20261005`,基线 = master 413c936(冒烟 772/0)。
## 一、提交链(worktree)
| # | 提交 | 内容 |
|---|---|---|
| 1 | d4cde73 | T1:feature_*→curio_*(CURIO_KINDS/curio_quota/curio_value/curio_candidate_count + adventure.tres 键名 + entities.yaml 换代续写) |
| 2 | 8e2694d | T2:运行层 bonus_*→curio_* 全族 + curio_interact_controller.gd/curio_pick_overlay.gd 两文件改名 + 裁点甲案 + reward_overlay 红转绿适配 |
| 3 | 6812ebb | T3+T4:relic_*→feat_*(三文件改名+全 token+config_db 注册键两端)+ 渠道白名单过滤(通关渠道只出专长/节点零专长)+ devour 货架保底退役 |
| 4 | 95b66f0 | T5+T6a:门票入表(四字段 provisional+三计数+双注入+拿到即开三入口+断点扩列+shop.tres 门票行+A5/A6 断言)+ T6a 商店补 heal 行 + registry 刷新边界写死 |
| 5 | (T6b+T7+T8) | refresh 入池(B 案挤占 heal 5→3)+ registry pool_architecture/charge_defect 落文 + 批末重闸 |
## 二、批末读数(T8 回填)
| 闸 | 基线(413c936) | 批末 | 判定 |
|---|---|---|---|
| 冒烟 smoke_all | 772/0 | 【T8_SMOKE】 | |
| run_all | 15/16(reward_overlay 红=M7 基线红) | 【T8_RUNALL】 | **红转绿(T2 适配)** |
| 行为探针四件+ui_struct | 全绿 | 【T8_PROBES】 | |
| doc 三闸+熵增闸 | 零新增基线 | 【T8_DOC】 | |
| MC n200 双策略(82000 窗) | 判式批改后锚(76000 系) | 【T8_MC】 | |
## 三、验收断言(A1-A12 逐条)
- **A1 词族归零**:【A1_CENSUS】(保名单:_bonus_row/_bonus_value/_bonus_summary_text 等加成区呈现+bonus_summary+存档键六形态+kind 值 "relic"/身份前缀 "relic:"/relics_seed 进程内参数——穷举见 §五)
- **A2 禁词未用**:reward_pick/reward_node/reward_preview 既有三处零新增(T2 全程未触)
- **A3 兑付频率**:专长兑付点=通关三选一(_pending_next_level 置位链=关底 Boss 击败同一时刻);关内普通战斗节点零奇物(node_type=battle 无三选一调用,结构保证+冒烟既有断言面)
- **A4 渠道分离**:_draw_curio_candidates(channel) 白名单过滤——通关渠道 60 次重抽全 relic/节点渠道 60 次零 relic(冒烟断言在案);货架白名单=shop_pool_rows 词表(feat_ticket 门票行+heal 回复行+四池种)
- **A5 拿到即开**:门票兑付=候选替换专长面+零摘牌+无残留持有集(冒烟 4 断言在案)
- **A6 保底计数**:pity=5→第 6 展示必出/触发清零/限购满冻结/概率面存在(冒烟 4 断言在案)
- **A7 值零变更**:T1 改名键值逐位相等(diff 实测)+ heal 5→3/refresh 0→2 系 T6b 用户裁 B 案结构面(非本断言范围)
- **A8 存档往返**:断点往返测试 PASS(全批三次验证:T1/T2/T4 后各一);存档键按 T2 裁点甲案+relics 第 6 键澄清(§四-3)
- **A9 池配额锚**:TIER_QUOTAS 70/25/3=98 零改动(B 案挤占——heal 5→3/refresh 0→2,总量不变,validate 绿)
- **A10 节点类型零扩类**:封闭枚举五种未动
- **A11 玩家可见面无分类名**:门票卡面写「奇物门票/奇物三选一」(规避「专长」分类名);本批只做断言检查不改法(C1 归呈现批)
- **A12 档二通路**:charge=3 件(<4)——**显式登记不硬补**(白名单 4;registry charge_defect 落文,转内容批)
## 四、裁点与自裁记录
1. **T2 存档键裁点(白名单 3)**:**甲案**——五存档键(bonus_deck/bonus_taken/bonus_pending/bonus_result/bonus_aux_carry)引号字面量禁改,代码侧变量全换 curio_。依据:与③批先例一致;全仓对拍六形态逐键全等。
2. **bonus_aux_carry 语义澄清(T0 回写)**:该键系**秘宝件跨关携带**(③批已对齐 treasure 词族),非奇物概念——剔除出本批改名面;_bonus_treasure_carry 变量随③批保留。
3. **"relics" 第 6 存档键(任务书漏登记)**:adventure_runner 断点快照/摘要 additive 键 "relics"(迭代 12 T1 扩列)——任务书 §2.5 只列 5 键漏此键;按甲案精神禁改+registry/任务书回写。kind 值 "relic"/身份前缀 "relic:"/relics_seed 参数同理保留(数据契约键,A1 扫描口径=relic_ 下划线形态)。
4. **T6b refresh 入池配额(用户门呈报,用户裁 B 案)**:refresh rare=2 从 heal rare 5 挤占(heal 5→3),总量 98 锚不变;契约 10 按裁更新;**池架构语义=总池-渠道子集(多级缓存形)**确立落 registry pool_architecture。
5. **devour 货架保底退役(T4 连带)**:迭代 12 T6「货架零特性挤卡换吞噬流件」简化口径与渠道白名单直接冲突(devour=规则改写型=专长系不得进商店货架)——随渠道定位退役,留痕注释。
6. **reward_overlay_test 红转绿(T2 连带)**:成因考证=M7 bcard 换装(PanelContainer)致 `c is Button` 恒 0(主区 3c4291d 起红在案);断言改数 _choice_box 子节点数(语义不变)——run_all 16 套历史首次全绿。
## 五、例外清单(A1 扫描口径残存量,批末)
【A1_EXCEPT】
## 六、遗留与移交
1. 【T8 07 登记】
2. C1 玩家可见面违规改法+档位呈现三路 → 呈现批(06 独立条目)
3. C2 第四关+档二复裁+charge 补件 → 第四关内容批
4. C3 门票四参数终值(现 provisional 20%/2/1/5)→ 曲线调参批
5. C4 存档键正式迁移 → 存档批(本批甲案未迁移,兼容读旧键零破坏)
6. MC 运行含既有 script error 噪音(ticket_id/minesweeper_rules 链)——待基线对拍归属,读数采集不受影响
+2
View File
@@ -601,6 +601,8 @@ entities:
acquisition: 三条渠道的**目标分工(交叉开关,v2.2 收口)**——专长:主渠道=**关底 Boss 击败=通过这一关**(**唯一直接给的渠道**;不新增节点类型、挂 Boss 节点兑付面;末关的 Boss 击败后不给——无后续关卡可消费)。**兑付频率**:奇物不是打一场战斗给一份,关内普通战斗节点不给任何奇物,一关之内只兑付一次(奖励节点与商店同理,各节点各自兑付),奖励节点与商店**只给「专长获取」门票**——**拿到即开、不可囤积**,不进持有集(选中/买下同一时刻开专长三选一;可囤积会让玩家无限推迟关键决策,且把持有物语义从后门放回)。门票归专长(给的是一件以前不会的事,只是把选择推迟)。罕见**只在概率不在价格**,一局限购一次,**计步保底**:连续 5 次三选一展示未出现→第 6 次必出(计数=展示次数、刷新重展计入、奖励节点与商店共享、触发清零、限购用满后不再触发);属性值提升:奖励节点 + 商店(口径「训练」);资源:奖励节点 + 商店(**金币除外、回复在内**);后两类均不出现在 Boss 渠道。形状=「一块独占 + 两块并行」,专长靠打赢、其余靠抽取与购买。**默认原则**:除已登记的特殊规则外,分类内的东西都要在它该出现的渠道池子里——任何不出现都须登记理由**现行实现三渠道共用同一候选池、三类混编**,分工尚未实施,登记于 06-待办清单 BD 分层条目
boundary: 判据走生命周期——**一次冒险内获得、冒险收束即清零的是奇物;跨冒险跟着你走的是魔法道具**。奇物永不进同调位,魔法道具永不进当局随机渠道;与元进度天赋树两层互不代位
data_sources: feats.tres(专长定义行)/ adventure.tres(属性值提升与资源的种类配额与值)/ shop.tres(货架取舍)
charge_defect: **charge 档二不可达登记(T7 奇物批迭代15②——数据缺陷留痕,白名单4授权「只登记不硬补」)**:feats.tres 现行 charge 标签仅 3 件(<4),档二激活要求同标签 ≥4 件——charge 流派永远达不到档二,即使获取次数无限。补哪几件系内容裁决,转独立内容批(硬补占位件已否决);档二可达性复裁=第四关内容批落地后实测(C2 待裁点)。
pool_architecture: **池架构=总池-渠道子集(多级缓存形,用户 2026-10-05 裁 T6 时确立)**:总池=单一令牌库(TIER_QUOTAS 70/25/3=98 + 专长活行追加);三渠道按分类白名单从总池取**子集视图**(关底 Boss 击败=只出专长子集;奖励节点/商店=属性值提升+资源子集,专长只以门票形态出现)——渠道不各建物理池,白名单在候选视图层生效(T4 过滤式)。配额挤占重裁:heal rare 5→3、refresh rare 0→2(方案B,总量 98 锚不变;用户裁「渠道从总量里拿子集」时同步裁)。
refresh_boundary: **刷新次数边界写死(T6 奇物批迭代15②——防后续混淆结算)**:「商店独立刷新机制」(shop_refresh_free/shop_refresh_cost_base/shop_refresh_cost_curve 三旋钮——进店后的免费次数+GP 付费刷新)系**商店自身服务**,作用对象=货架重抽;奇物 refresh 件(资源类成员,作为奇物授予的重抽次数)作用对象=**三选一界面**(兑付即 _attune_refresh_x 增量,X 余量=三选一重抽次数),不进加算区(§2.2 加算区四轴不含它)。两者不是一回事,禁止混算。
open_questions: ①类内异质性已登记——金币与回复是即时兑付、不进持有集不持续生效,与行动点上限/刷新次数生命周期不同,靠这条描述把"资源"从泛用词收回到本类定义内;②专长门票尚未入表(出现概率/配额/限购次数/保底阈值四参数均无事实源);③确定性渠道一局两次专长 vs 档位阈值(同标签 ≥2 档一 / ≥4 档二)——**档二在三关结构下几乎不可达**,用户定延后复裁(触发=第四关内容批后实测);④charge 标签仅 3 件、永远达不到档二(数据层缺陷,独立登记,勿被上条盖掉);⑤断点存档键 5 个(bonus_deck / bonus_taken / bonus_pending / bonus_result / bonus_aux_carry)是否随存档版本迁移换名待裁
naming_note: 2026-10-05 命名统一 + 两次重构——此前按内部分类被叫成三个名字(规则类称「流派件」、属性类称「数值件」、界面称「本关强化」),v1.0 统一为「特性」,v2.0 改名为「奖励」,v2.4 定名为「奇物」(因筐里也装金币这类一次性兑付物,"自身提升 vs 持有物"已切不开,判据改由生命周期承担)。v2.5 第三类定名为「资源」(用户拍板)。**v2.7 三个子节点全部正式定名、去「类」字后缀**:专长(Feat)/ 属性值提升(ASI)/ 资源——此前是描述式叫法不是专名。**代码侧三套词族已于奇物批对齐(2026-10-05 迭代15②批 T1-T3)**:`feature_*` → `curio_*`(CURIO_KINDS/curio_quota/curio_value)、`relic_*` → `feat_*`(feat_table.gd/feats.tres/feats_engine.gd/feat_flags/feat_id——kind 值 "relic" 与身份前缀 "relic:" 系令牌池数据契约键沿用不动)、运行层 `bonus_*` → `curio_*`(curio_interact_controller/curio_pick_overlay/CurioPickOverlay/pick_curio);断点存档键(bonus_deck/bonus_taken/bonus_pending/bonus_result/bonus_aux_carry/relics)按甲案沿用历史名不迁移(存档兼容)
@@ -150,6 +150,8 @@
### T6 刷新次数入表 + 商店补回复(≈0.5d)
> ✅ **T6b 裁决回写(2026-10-05 用户裁方案B)**:refresh rare=2 从 heal rare 5 挤占(heal 5→3),**总量 98 锚不变**——validate 硬断言零改动。契约 10「curio_quota_* 值零变更」按用户裁更新:本批结构面允许的配额变化=heal 5→3 挤占予 refresh 2(其余值零变更)。**池架构语义确立=总池-渠道子集(多级缓存形)**:总池单一令牌库,三渠道按白名单取子集视图(T4 过滤式即此形态),registry pool_architecture 已落文。
- `FEATURE_KINDS` 扩项须走 schema + registry 同步修订(封闭词表,红线 §3.6)
- ⚠️ **必须先划清边界**:既有「商店独立刷新机制」是**进店后的免费次数 + GP 刷新**(商店自身的服务),本项是**作为奇物授予的**重抽次数——**两者不是一回事**,入表前须在 registry 里把边界写死,防止后续混淆结算
- 刷新次数的作用对象是**三选一界面而非角色**——不进加算区(§2.2 加算区四轴不含它)
+3
View File
@@ -397,6 +397,9 @@ func _feat_payload_keys(feat_id: String) -> Dictionary:
# 按挂点消费,档位质变由 FeatsEngine 求值)。兑付即从 _curio_deck 摘除该令牌(选中踢池;
# 未选候选从未摘牌=自动回池)。道具件不入此体——未知件返回 false 由调用方按渠道名报错。
func _apply_curio_pick(kind: String, tier: String, value: int, feat_id: String = "") -> bool:
if kind == "refresh":
_attune_refresh_x += value # T6——刷新次数件兑付=X 余量增量(作用三选一界面非角色,不进加算区——registry refresh_boundary)
return true
if kind == "relic" and db.feat_row(feat_id).is_empty():
push_error("[冒险结构] relic 兑付失败——表无此件: %s" % feat_id)
return false # 先校验后摘牌(令牌零丢失)
+6 -2
View File
@@ -24,7 +24,7 @@ extends Resource
## 类内异质性:金币与回复是即时兑付,不进持有集、不持续生效。)
## 三选一提升池 kind 词表(封闭——断点附随件与牌库剔除态依赖它;扩件走本表+registry 修订)。
## treasure_item 池种退役(迭代 11 第①批 T7——同调批出池);heal 恢复件新入池(v2.2 令牌池追认 b)。
const CURIO_KINDS: Array[String] = ["attack", "max_hp", "armor", "gp", "ap", "heal"]
const CURIO_KINDS: Array[String] = ["attack", "max_hp", "armor", "gp", "ap", "heal", "refresh"] # T6 扩第七类(refresh=资源类成员——作为奇物授予的三选一重抽次数,作用对象=三选一界面非角色;见 registry refresh_boundary)
## 令牌档位词表(v2.2 三档位——稀有度命名对齐 MC 策略判读序 316-f:1 级最稀有=rarest 优先)
const TIERS: Array[String] = ["common", "rare", "rarest"]
const TIER_COMMON := "common"
@@ -53,7 +53,8 @@ const TIER_QUOTAS := {"common": 70, "rare": 25, "rarest": 3}
@export var curio_quota_armor_rare: int = 5 # [0,99]
@export var curio_quota_gp_common: int = 18 # [0,99]
@export var curio_quota_gp_rare: int = 5 # [0,99]
@export var curio_quota_heal_rare: int = 5 # [0,99]——恢复件(新入池种类,当即回血)
@export var curio_quota_heal_rare: int = 3 # [0,99]——恢复件(原 5;T6 挤占 2 席位予 refresh——用户 2026-10-05 裁方案B,总量 98 锚不变)
@export var curio_quota_refresh_rare: int = 2 # [0,99]——刷新次数件(T6 新入池资源类成员;provisional 归曲线调参批)
@export var curio_quota_ap_rarest: int = 3 # [0,99]——AP 件(罕见档;道具件 2 席位随池种退役收窄)
# —— 令牌件值(小/大数值对——v2.2 追认 b 定稿:20/50、+1/+2、+1/+2、+5/+10、恢复+6、AP+1)——
@@ -66,6 +67,7 @@ const TIER_QUOTAS := {"common": 70, "rare": 25, "rarest": 3}
@export var curio_value_gp_common: int = 20 # [0,999] knob——小GP
@export var curio_value_gp_rare: int = 50 # [0,999] knob——大GP
@export var curio_value_heal_rare: int = 6 # [0,999] knob——恢复(当即回血,封顶生效上限)
@export var curio_value_refresh_rare: int = 1 # [0,9] knob(provisional)——刷新次数件兑付值(三选一重抽次数 +N——_attune_refresh_x 增量,不进加算区)
@export var curio_value_ap_rarest: int = 1 # [0,10] knob——AP 件每场战斗首轮行动点基线增量
# —— 专长获取门票(迭代 15 卡② T5——非 Boss 渠道的专长入口形态,奇物.md v2.7 渠道轴定位;
@@ -90,6 +92,7 @@ func curio_quota(kind: String, tier: String) -> int:
["gp", TIER_COMMON]: return curio_quota_gp_common
["gp", TIER_RARE]: return curio_quota_gp_rare
["heal", TIER_RARE]: return curio_quota_heal_rare
["refresh", TIER_RARE]: return curio_quota_refresh_rare
["ap", TIER_RAREST]: return curio_quota_ap_rarest
return 0
@@ -106,6 +109,7 @@ func curio_value(kind: String, tier: String = TIER_COMMON) -> int:
["gp", TIER_COMMON]: return curio_value_gp_common
["gp", TIER_RARE]: return curio_value_gp_rare
["heal", TIER_RARE]: return curio_value_heal_rare
["refresh", TIER_RARE]: return curio_value_refresh_rare
["ap", TIER_RAREST]: return curio_value_ap_rarest
return 0
+3 -1
View File
@@ -14,7 +14,8 @@ curio_quota_armor_common = 17
curio_quota_armor_rare = 5
curio_quota_gp_common = 18
curio_quota_gp_rare = 5
curio_quota_heal_rare = 5
curio_quota_heal_rare = 3
curio_quota_refresh_rare = 2
curio_quota_ap_rarest = 3
curio_value_attack_common = 1
curio_value_attack_rare = 2
@@ -25,6 +26,7 @@ curio_value_armor_rare = 2
curio_value_gp_common = 20
curio_value_gp_rare = 50
curio_value_heal_rare = 6
curio_value_refresh_rare = 1
curio_value_ap_rarest = 1
feat_ticket_chance = 20
feat_ticket_quota = 2
+7
View File
@@ -229,6 +229,13 @@ static func _on_adventure_node_entered(node: Dictionary, info: Dictionary, adr,
adr.present_node_curio(ncands, ndraw.get("aux_detail", []) as Array)
var npick: Dictionary = _pick_token(ncands, String(st.get("feat_mode", "off")))
if adr.apply_node_curio(String(npick.get("kind", "")), String(npick.get("tier", "")), String(npick.get("feat_id", ""))):
# T5 门票拿到即开——候选已被替换为专长三选一,就地再选一轮(确定性策略同款 316-f);
# 不作此分支则节点停点悬空→选路卡死(MC timeout 形态,2026-10-05 批内实测)
if String(npick.get("kind", "")) == "feat_ticket":
var fcands: Array = (adr.node_curio_pending_state().get("candidates", []) as Array)
if not fcands.is_empty():
var fpick: Dictionary = _pick_token(fcands, String(st.get("feat_mode", "off")))
adr.apply_node_curio(String(fpick.get("kind", "")), String(fpick.get("tier", "")), String(fpick.get("feat_id", "")))
if not adr._node_curio_pending.is_empty() and adr._node_curio_pending.has("incoming"):
adr.resolve_curio_replace(-1) # 满位替换:放弃新件
else: