@@ -0,0 +1,438 @@
# 需求卡片 · 营地交互修复批(2026-11-05)
> **来源**:待办清单条目「营地交互修复批——大门无断点开局被开始层盖住/确认框钮序/营地顶栏无栏体」(2026-11-05 登记,来源=会话提及)
> **唯一事实源**: `design/gdd/ux/camp.md` v2.8 §顶栏 · §点选反馈 + `design/gdd/systems/表现与支撑/HUD框架.md` §提示与弹层(三条纪律·其三) + `design/gdd/systems/冒险循环/关卡节点地图.md` §核心循环位置 + `design/art/art-bible.md` v3.43 §6.2
> 验收档:中(三件做错的后果都是玩家可见但不损持久状态——呈现与交互逻辑;不触存档写读、不触结算公式、不触 RNG 流。判据=本技能第 16 节单维失败代价)
> **改动面**:游戏代码(`game/` 表现层+测试面)。文档面已由文档批落定为现行规格,本卡不携任何 `design/` 改动。
> **编排状态**:未编迭代(roadmap 现行最高编号=迭代 52,已完成;本卡待 iter-plan 段编排)
---
## 1. 目标与完成定义
三件互不相干的营地屏交互缺陷,一批修完:
1. **大门无断点开局被开始层盖住 ** ——玩家点大门、按「是」之后,冒险其实已经开局,但主菜单层(开始层)重新显出来并把冒险画面盖住,玩家看到的是主菜单,误以为没开始。修完=从大门真实点击进入后,开始层不可见、关卡画面(节点图选路停点)可见。
2. **确认弹窗按钮位次反直觉 ** ——同一个共用弹窗件把「维持现状」那颗放在左、「推进」那颗放在右,四处消费方(删档/大门三出口/大门两出口/篝火)皆然。修完=整体镜像为「推进在左、次推进居中、维持在右」,且位次与语义的绑定有真点验收。
3. **营地顶栏看不出是一行 HUD 栏 ** ——顶栏件已装配、已落座、预留位 48px 全宽都在,缺的是那层看得见的底:现在是透明 Control 只挂一枚徽章,而徽章的烛光黄底对背后天空均色只有 1.29:1。修完=按 camp.md v2.8 §顶栏 定值画出栏体(`CAMP_HEADER_BAND` × 不透明度 0.80),徽章顶格右位落进栏内,并有尺寸与对比的机检。
**完成定义 ** :四条全落即算这批做完——
- 对照表(第 8 节)八行断言(R1–R8)在当轮真实跑批中执行且通过,无红项遗留;
- 第 8 节标注的两行新增能力已随写卡段落进 `game/tests/README.md` ,实现批末核对名实相符;
- 回归面(第 5 节列的七条未改动动线)在跑批中仍绿,未因位次改动或栏体新增而失守;
- 末卡产出物(实现报告+反哺点清单)写齐,`reports/` 两份落位。
真人目检项(营地顶栏观感)登记进实现报告实机目检总清单即算义务了结,**不作合回前置**(AGENTS.md 红线:真人检测只登记不阻塞)。
---
## 2. 设计事实源
本节为卡片设计依据的唯一出处声明,与待办清单条目实况的闭合凭据同批一致:
| 需求点 | 现行规格句 | 出处 |
|---|---|---|
| 件1 | 点大门永远先出确认,无未完冒险=是否开始新冒险 | `design/gdd/ux/camp.md:16` |
| 件1 | 关卡开始 → 呈现节点图选路停点(关卡画面;入口不自动进入) | `design/gdd/systems/冒险循环/关卡节点地图.md:78` |
| 件2 | 确认弹窗的按钮位次定值:推进钮在左、维持现状钮在右,三钮形态次推进居中,四处共用同一件同一序 | `design/gdd/systems/表现与支撑/HUD框架.md:90` |
| 件3 | 栏体底=`#6E4526` ×不透明度 0.80、高 48px 全宽浮层、栏内只钥石徽章一件右位顶格、验收=目检窄带可辨+机检对落位带底色 ≥3:1 | `design/gdd/ux/camp.md:41` |
| 件3 | 色板五件对齐表在册色 `CAMP_HEADER_BAND #6E4526` (机检〈ui_kit 五 token 与本表一致〉) | `design/art/art-bible.md:452` |
| 件3 | 命中区不侵入顶栏禁区(y ≤ 48) | `design/gdd/ux/camp.md:37` |
预览人审在案:2026-11-05 会话内实尺 HTML 预览(十张已过审场景层按 `camp_scene_layout.tres` 现值叠放+1:1 顶栏放大条+页内 WCAG 即时算式),用户审语「我看了预览的效果是OK的」,选定项=甲 深棕带 × 不透明度 0.80;快照文件 `chat-session-visualizations/…/visualizations/snapshot-444250310dc22234ac755b11fb31ce6885adb634b271c7083d53cc5d72b98640.html` (会话侧不可变快照,非仓库件)。像素级判据句已随附进 `camp.md` v2.8 §顶栏。
顶栏这块带子的落点定稿(用户 2026-11-05/11-06 四次裁决的终态,全程留痕见第 15 节 Q1 裁决史):**一个 UI 物件的外观不得拆两处**——色值与透明度、铺满方式、不吃点击、挂上宿主、返回句柄这五件事全在公共件 `ui_kit.gd` 的**一个具名公开出口**里;出口只接「挂到谁身上」一个形参,色与点击语义写死在它内部(它们是这块带子的定义,不是调用方每次要重述的选择)。同时**不收编盘上任何同形旧实现**:`ui_assembler.gd:224-230` 、`ui_kit.gd:486-491` 、`ui_kit.gd:537` 只是形状撞车、变化原因各不同,把它们绑进同一个出口=为没到来的问题做设计,并把回归面扩到全站弹窗底与两个全屏页。顶栏件只调该出口一次,不再自建 ColorRect。两项引擎实测(4.7.2,工程外临时工程跑通后即删,与本条封装方式无关,仍成立):①`Color(母token, 0.80)` 形态的 const 派生编译通过,`to_html(true)` 读数 `6e4526cc` 、三分量与母 token 逐一相等;②**色道存单精度浮点,`.a == 0.80` 判为 false**(实测 `a=0.80000001192093` )——断言一律写 `to_html(true) == "6e4526cc"` 或整体等值比较,禁浮点分量直等,否则实现正确而断言红,最容易的自救就成了放宽阈值(触 test-conventions §8.5 禁止削弱测试)。
---
## 3. 现状事实(2026-11-05 实查;开工日自行复核行号)
### 3.1 件1——开始层可见性无单点
- `game/presentation/camp_shop_presenter.gd:85` : `on_camp_closed()` 体内无条件 `start_overlay.visible = true` 。该函数的本职是「回主菜单」,篝火离场(`game/presentation/main.gd:214` )与 Esc 返回主菜单(`game/presentation/main_esc_flow.gd:46` )都靠这句显出菜单——**语义正确,不是缺陷本体**。
- `game/presentation/main.gd:211-212` ( `_on_confirm_accepted()` 的 `"gate_new"` 分支)与 `game/presentation/main.gd:223-224` ( `_on_confirm_secondary()` 的 `"gate"` 分支):两处都是先调 `camp_pres().on_camp_closed()` (把开始层显出来),紧接着调 `_start_adventure()` 。
- `game/presentation/main.gd:292-308` : `_start_adventure()` 全函数体(体止于 `:308` 的 `return` , `:311` 已是下一函数声明行)零处触碰 `start_overlay` ——于是上面那句「显出来」没有对手句把它收回去。失败分支(`main.gd:306-307` `fatal_screen` )在 T1.1 落笔后开始层终态由「可见」变「隐藏」,该终态差在本卡第 5 节明示为可接受(致命屏自会接管,无菜单可用)。
- 既有先例=每条启动路径在自己函数内部自管开始层:`game/presentation/main.gd:194` ( `_start_adventure_from_menu()` 内先隐藏再转调)、`game/presentation/main.gd:246` ( `_resume_from_menu()` 内隐藏)。所以现状的隐藏点是散在入口层的两处,缺的是开局那一条。
- `_start_adventure()` 全库调用点仅三处(`main.gd:195` / `212` / `224` ),无一需要开局后保留开始层。
- 层序事实:`game/tests/system_test.gd:87-89` 断言「start_overlay 在冒险屏壳之上(盖住战斗内容)」——被盖住的正是冒险画面,故真机观感=「画面回主菜单」。
- 覆盖缺口事实:`game/presentation/main.gd:210` 的 `"gate_new"` 与 `main.gd:223` 的次确认分支,现有断言只核 `run_scope.is_adventure` 与营地场景屏隐藏(`game/probe/ui_click_probe.gd:703-705` ),**没有一条核开始层可见性**,故缺陷在绿批里静默存活。
### 3.2 件2——弹窗件位次写死
- `game/presentation/views/confirm_dialog.gd:31-39` : `_init()` 内三颗钮的 `btn_row.add_child()` 次序=取消 → 次 → 确认。
- 信号按按钮对象路由、不按位次:`confirm_dialog.gd:32/35/38` 各自 `.pressed.connect(_emit_cancelled/_emit_secondary/_emit_confirmed)` ——换序不改路由,文案也不用来认钮。
- 四处消费方(全部经同一件):删档确认 `game/presentation/main_overlay_flow.gd:129` (钮标「删除」/「取消」)、大门有断点三出口 `main_overlay_flow.gd:79-80` (「继续上一段冒险」/「开始新冒险」/「取消」)、大门无断点 `main_overlay_flow.gd:83` (「是」/「否」)、篝火离场 `main_overlay_flow.gd:73` (「离开」/「留下」)。
- 现有断言只核「次钮在两出口形态下隐藏」(`ui_click_probe.gd:696` ),**无一条核位次**。
### 3.3 件3——顶栏件有装配无栏体
- `game/presentation/views/camp_hud_band.gd:10-17` : `_init()` 设 `PRESET_TOP_WIDE` + `custom_minimum_size=(0,48)` + `mouse_filter=MOUSE_FILTER_IGNORE` ,体内只挂一枚徽章,**无任何底色件**——即整条顶栏是透明的。
- 徽章现状:`camp_hud_band.gd:15-16` 设 `PRESET_CENTER_RIGHT` 后 `position=Vector2(-160, 8)` (注释自标「代拍板 3」)。
- 徽章自高=48px: `game/presentation/views/ui_kit.gd:640` 的 `panel_flat(..., Vector4(14, 8, 14, 8))` 给图标 32px 上下各加 8px 内边距=48px,正等于栏高——**顶距 8px 在栏内放不下**,落座只能顶格。
- 装配链在位:`game/presentation/main_ui_build.gd:120-121` 造件并调 `set_hud_band()` → `game/presentation/views/camp_scene_view.gd:88-91` 把件塞进 `_hud_slot` → `camp_scene_view.gd:188` 预留位 `custom_minimum_size=(0, layout.hud_band_h)` ,取数自 `game/data/tables/camp_scene_layout.tres` 的 `hud_band_h=48` ( schema 见 `game/data/schemas/camp_scene_layout_table.gd:7` )。
- 盘上「新建 ColorRect+铺满宿主」的写法现有三处,意图各不相同,本批一处都不动:`game/presentation/ui_assembler.gd:224-230` `overlay_bg(host, color)` (亮底面板与模态压暗遮罩共用,外部调用者零、仅该文件自身 `:100` / `:214` 用,**没设 mouse_filter**);`game/presentation/views/ui_kit.gd:486-491` 私有 `_modal_dim()` (同一份东西的第二实现,同样不设 mouse_filter,仅 `:511` 经 `modal_shell()` 一处用、经该壳扇出 11 家模态消费件);`ui_kit.gd:537` 页壳底板(`page_shell()` 内,**显式**写 `MOUSE_FILTER_STOP` 、色取 `BG_BRIGHT` /`BG_ROOT` 实色,其后紧跟石纹层与暗角层作兄弟节点)。三者与顶栏带只有形状撞车:前两者的变化原因是「遮罩挡不挡点击」,页壳底板的变化原因是「这块屏用哪档底色」,顶栏带的变化原因是「这条 HUD 带的定值」。另:顶栏件 `camp_hud_band.gd:14` 现役已在调 `UiKit.keystone_badge()` ——视图件引公共件在本文件内就有先例,故出口落 `ui_kit` 、不经装配器。用户 2026-11-06 终裁=**顶栏带的外观整件封进公共件一个具名出口,同形旧实现不收编**(早先两版——「值进公共件+矩形视图自建」与「四份同形收成带形参的通用出口」——都已作废,逐次理由见第 15 节 Q1 裁决史与第 12 节末段)。
- 落位带实际背景:营地背景层 `game/assets/art/scene/scene_camp_bg.png` 的 y0– 48 带均色实测 `#DEEAE7` (逐像素取样,画面最上的可点物件是大门,顶缘 y=250,故 48px 带整条落在远景天空上)。徽章烛光黄底 `#F6C667` 对该天空 1.29:1;定值 `#6E4526` × 0.80 叠后呈色 `#84664D` ,对天空 4.27:1、对徽章底 3.31:1。
- 像素取样先例:`game/tests/unit/presentation/terrain_tile_sets_test.gd:107` 已用 `img.get_pixel()` 在单元套内取样贴图。
- 无 golden 锚:`game/tests/golden/README.md` 「未建锚面备案」明写营地屏无改前 golden 锚,该面等价证据=探针/单元断言+实机目检。
---
## 4. 设计契约(红线,违反=L3 停机呈报)
- 🔴 **契约1|冒险启动路径的隐藏点收一处 ** :**限「开局」与「续玩」两条路径**——隐藏责任只许落在 `_start_adventure()` (开局)与 `_resume_from_menu()` (续玩)两个函数内部。第 3.1 条的先例形态即本契约依据。**本契约不管其余开层自管点**:全库开始层显隐共 13 处(`camp_shop_presenter.gd:43` / `:85` 、`main.gd:137` / `:194` / `:246` 、`main_adventure_flow.gd:145` 、`main_debug_flow.gd:88` 、`main_overlay_flow.gd:8` / `:17` / `:41` / `:48` / `:95` / `:101` ),那些是选档层/生涯页/终局回菜单等各自开合面的自管句,本批一律不动、也不受本契约约束。禁再新增**开局或续玩路径**上的第三处隐藏点,禁把隐藏写回 gate 出口(调用方)。
- 🔴 **契约2| `on_camp_closed()` 语义不动 ** : `camp_shop_presenter.gd:85` 那句显示开始层是本批禁改项——篝火离场与 Esc 返回主菜单两条动线靠它。改动=回退主菜单功能。
- 🔴 **契约3|位次改动只动 `add_child` 次序 ** : `confirm_dialog.gd:31-39` 的三句连接(`.pressed.connect(...)` )、三个钮对象的创建与文案参数一律不动;四处消费方的 `open()` / `open_three()` 传参零改动。位次与语义的绑定由第 8 节 R4 行的坐标真点断言钉。
- 🔴 **契约4|这块带子的全部外观封在公共件的同一个具名出口里 ** : `ui_kit.gd` 出一个公开出口(本卡定名 `camp_hud_band_surface(host)` ,实现可按同文件命名习惯微调后缀形态,见白名单第 6 条),**色值与 α、铺满、不吃点击、挂上宿主、返回句柄**五件事全在它内部;**形参只有 host 一个**——禁把颜色与「吃不吃点击」开成形参(那等于把这块带子的定义推回调用方每次重述,也正是本契约要禁的拆两处)。色值取派生常量 `Color(CAMP_HEADER_BAND, 0.80)` (三分量继承在册 token,同文件先例 `TOAST_BG:189` / `TIP_BG:190` / `HP_BAR_TRACK:200` 注「收口单点——非色板新增」)。**同时禁收编无关同形件**:`ui_assembler.gd:224-230` 、`ui_kit.gd:486-491` 、`ui_kit.gd:537` 三处原样不动,出口也不得被它们转调——形状撞车不等于同一件事,绑起来就得到一个同时要回答「页底用哪档色」「遮罩挡不挡点击」「HUD 带穿不穿点击」三个变化原因的函数,并把回归面扩到全站弹窗底(用户 2026-11-06 终裁,见第 15 节 Q1 裁决史④与第 12 节末段)。依据=`ui_kit.gd:2` 「全站取色/描边唯一出口,换皮只改本文件」+ code-conventions §1.1 一个类一个职责、单一变化原因判据。色板快照不受新常量影响(`tools/gen_palette_baseline.py:42` 只正则 `Color8(数字,数字,数字)` ,带 α 的 `Color(...)` 从不进快照)。
- 🔴 **契约5|不吃点击由出口内部保证 ** :栏体必须 `mouse_filter = Control.MOUSE_FILTER_IGNORE` ,写死在出口内、不靠调用方记得设(顶栏件自身 `camp_hud_band.gd:13` 同款设置是既有锚)。漏设=48px 带内点击被栏体吃掉,与 `camp.md:37` 禁区纪律叠加成「顶排物件点不动」;且 ColorRect 默认即 STOP,漏设不会报错只会静默失守(同文件 `:540` 显式 STOP、`:864` 与 `camp_scene_view.gd:145` 须显式 IGNORE 为旁证)。本条与契约4 合起来把这块带子的外观压到一处。
- 🔴 **契约6|本批禁写文档面 ** : `design/` 整个目录、`待办清单.md` / `体验验证清单.md` 两份根流程清单、`game/tests/README.md` 一律禁改(能力两行已由写卡段落表,实现批只改名实相符);产出物只准落 `reports/` 。
- 🔴 **契约7|禁变异类测试与撤销类取证 ** ( test-conventions §8.4,全项目红线):本批所有断言从真实入口进入、绑被测改动特有的可观测提交面,禁人为制造红、禁回退 hunk 取证。
---
## 5. 范围边界
**做 ** :
1. `_start_adventure()` 入口收一个隐藏点,摘掉 `main.gd:194` 的冗余句;
2. `ConfirmDialog` 三颗钮的 `add_child` 次序整体镜像;
3. 公共件出一个具名出口封装这块带子的全部外观(色值与 α、铺满、不吃点击、挂上宿主、返回句柄)+ `CampHudBand` 改调该出口、徽章落座改右对齐容器;
4. 上述三件各自的测试(对照表 8 行 R1–R8)+能力清单两行(写卡段已落)+回归面确认。
**不做(含去向) ** :
| 不做的东西 | 为什么 | 去向 |
|---|---|---|
| 「破坏性确认与常规确认禁止同位」(art-bible §4.5 清单 #7 后半句/interaction-patterns §7)在弹窗层的闭合 | 该句系 2026-09-14 文档骨架初版提交随件进入,全库查无用户裁决记录,且 battle.md:335 指定的无障碍基线权威(HUD框架 §可访问性基线)不含它——它是不是用户定的规则,本身待裁 | 本卡不动它;现状四处同位属既有状态,不随本批产生或消失。要不要闭合,归用户另发令,另立待办条目 |
| 顶栏栏内加第二件(存档位号/关卡语境等) | 用户 2026-11-05 裁「栏内只放钥石徽章一件」,左位不放件 | 无 |
| 营地场景层坐标、素材、七物件摆放的重排 | 属场景重排批,不与本卡混装(用户 2026-11-05 口径:代码批与素材批分两张卡) | 归那一批自己的卡 |
| 把盘上三处同形铺面写法(`ui_assembler.gd:224-230` 、`ui_kit.gd:486-491` 、`ui_kit.gd:537` )收敛成一个通用铺面器 | 形状同而变化原因不同(遮罩遮挡语义/页面底色档位/HUD 带定值);收编=把三个不相关变化原因绑进一个带形参的函数,回归面扩到全站弹窗底与两个全屏页底板,而这三个地方今天都没有待改的东西——为没到来的问题做设计(用户 2026-11-06 终裁,第 15 节 Q1 裁决史④) | 无。三处原样留底;日后若真出现意图相同的第二个消费者,届时按 code-conventions §1.1 重议 |
| 营地屏 golden 建锚 | 无改前基线可留底,新建锚不属缺陷修 | 不登记(顶栏观感走目检) |
| `main.gd:137` 的 boot 期 `start_overlay.visible = true` | 启动默认态,与三件无关 | 无 |
**回归面(本批不改、但跑批必须仍绿) ** :七条未改动动线——大门有断点按「继续上一段冒险」/大门按「取消」「否」/篝火「离开」「留下」/Esc 浮窗三项/五功能窗开合/进入存档与生涯页返回的开始层显隐/终局回菜单。其中前三条已被 `ui_click_probe.gd:679-723` 段覆盖(段止于「开场行三路径段」头注之前),本批在该段内追加断言,不新建平行段。
---
## 6. 关联文档同步面
实现批禁写 `design/` 与根规则文件;下表逐条给出「要改哪一节、改成什么、依据是什么」,实现批把命中项列进 `reports/iter<53>-反哺点-<日期>.md` ,由用户在会话中裁决后归文档批落文。
| 文档 | 关联点 | 同步义务 |
|---|---|---|
| `design/gdd/ux/camp.md` v2.8 §顶栏 | 本批把「栏体定值」变成实装;若实现期样张/目检意见要求改 α、改右位内缩或改栏高,现行句即落后 | 反哺点:只在**实际改值**时列,附实测读数;未改值不列 |
| `design/art/art-bible.md` v3.43 §6.2 钥石余额行 | 同上(该行已把事实源指回 camp §顶栏,改值须两处同改) | 反哺点:与上一行同批列,禁单改一处 |
| `design/gdd/systems/表现与支撑/HUD框架.md` §提示与弹层·其三 | 「四处共用同一件同一序」实装后须与代码一致;若实现发现某消费方不遵此序(例如自拼按钮行的弹窗件),句与码冲突 | 反哺点:发现即列,附 `文件:行` |
| `design/engineering/architecture/architecture.md` 呈现层模块表 | 两处随本批失真:`:175` CampHudBand 行现写「顶栏 48px 全宽窄条:**钥石余额 badge 唯一呈现**」——加可见栏体后badge 不再是唯一呈现物;`:168` D1 HUD 行的视图单元接口若因本批改动而与「信号外发、setter 只读注入」不符亦须同步 | 反哺点:实现批禁写该文档;本批落地后把该行的实际形态(栏体色面+badge 右位)列进反哺点清单,附 `文件:行` 与实装读数 |
| `体验验证清单.md` | 顶栏观感属「需真人试玩才能下结论」项,需一行观测项 | 反哺点:实现批禁写该清单,由文档批落;卡内先在实现报告目检总清单登记 |
| `game/tests/README.md` 能力表 | 两行新增能力已由写卡段落表(第 8 节能力行列名即清单名) | 实现批禁写;批末只核「清单名=实际落地函数名」,名实不符=停卡退回写卡段 |
| `roadmap.md` 迭代总表 | 本卡尚未编入迭代 | 非实现批义务,归 iter-plan 段 |
| (非文档面·写卡期发现一)`tools/pipeline_gate.py:68` 判据出处行锚的机检式 `ANCHOR_RE` 字符类=`[A-Za-z0-9_-.\\/]` ,不含中文段 | 本库现行设计文档多为中文名(`HUD框架.md` / `关卡节点地图.md` / `待办清单.md` ),凡判据句落在这类文档即无法被机检认锚——本卡 R2/R3/R4/R8 因此同时挂一个 ASCII 路径锚(`camp.md` / `level-map.md` ),中文出处改以「第 N 行」散文形写明 | **已登记 ** :待办清单「流水线闸认锚式不含中文名文档」条(工具代码/待执行),本批不动闸件 |
| (非文档面·写卡期发现二)`game/tests/unit/contracts/source_guard_test.gd:85-99` 列目录不递归 | 「V1d 层序落位单口」的扫描面漏掉 `views/` 与 `scenes/` 两个子目录(注释仍写「presentation 无子目录」,实为两个);视图层的插位不在该闸视野内。当前无漏网真违规(`views/ui_kit.gd:841` 属卡片内部重排) | **已登记 ** :待办清单「层序落位单口检查的扫描面不含子目录」条(工具代码/待执行);两目录是否纳入扫描面本条不预裁,启动时再裁 |
---
## 7. 文件结构图
| 文件 | 职责 | 新增/改动 | 行为改动 | 验收行 |
|---|---|---|---|---|
| `game/presentation/main.gd` | 组合根:冒险启动与确认分派编排 | 改动(`_start_adventure()` 加一句;`_start_adventure_from_menu()` 删一句) | 行为改动 | R1、R2 |
| `game/presentation/views/confirm_dialog.gd` | 通用确认弹窗视图件 | 改动(三句 `add_child` 次序,**不动成员面**) | 行为改动 | R3、R4 |
| `game/presentation/views/ui_kit.gd` | 呈现层共享工厂与全站取色单点 | 改动(新增带 α 派生常量 + **新增一个具名公开出口 ** ,该出口承载这块带子的全部外观;既有三处同形铺面写法一律不动) | 行为改动(顶栏呈现源) | R5、R6 |
| `game/presentation/views/camp_hud_band.gd` | 营地顶栏 HUD 件 | 改动(调该出口得栏体,不再自建 ColorRect;徽章落座改右对齐容器) | 行为改动 | R5、R6 |
| `game/probe/ui_click_probe.gd` | 真点探针:大门两分支段所在宿主 | 改动(同段追加断言) | 非行为改动(测试面) | R1、R2、R4、R7、R8 |
| `game/tests/system_test.gd` | 系统测试宿主 | 改动(新增 `_smoke_camp_hud_band()` ,接进 `_split_tail()` 的 await 链〔`:40-44` 〕) | 非行为改动(测试面) | R5、R8 |
| `game/tests/unit/presentation/camp_scene_layout_test.gd` | 营地屏布局与顶栏禁区单元套 | 改动(新增 `_test_hud_band_contrast_over_bg()` ) | 非行为改动(测试面) | R6 |
| `game/tests/unit/presentation/confirm_dialog_test.gd` | 确认弹窗按钮位次与语义单元套 | **新增 ** | 非行为改动(测试面) | R3 |
| `game/tests/README.md` | 能力清单 | 改动(两行,写卡段落) | 非行为改动 | — |
结构图与第 12 节「落位与可复用性预检」互指:改动件七个(四件表现层+三件测试面)、新增件仅一枚单元套;这块带子的全部外观收在公共件的同一个具名出口里,出口只服务这块带子(判据见第 15 节 Q1 裁决史④与契约4)。
---
## 8. 验证闸(改动—验收对照表)
| 行 | 需求点(判据出处行锚) | 改动(文件:行/行为) | 验收测试(名称+落点+尾缀) | 层级 | 真实入口 | 判据绑定面 | 能力行 |
|---|---|---|---|---|---|---|---|
| R1 | 件1 大门无断点按「是」后开始层不可见(`design/gdd/ux/camp.md:16` + `design/gdd/systems/冒险循环/关卡节点地图.md:78` ) | `main.gd:211-212` 分支经 `main.gd:292` 新入口隐藏 | `ui_click_probe.gd:_ready` (大门无断点段追加「确认后开始层不可见」) | 探针 | 营地场景根大门命中区 → `ProbeUiUtil.push_click_at` 真点 → 弹窗「是」钮 `ProbeUiUtil.push_click(_confirm_btn)` 真点 | `main.ui.screens.start_overlay.visible` 取值(被测改动特有的可见性提交面) | 既有:营地大门两分支确认与断点续玩接线 |
| R2 | 件1 开局落在节点图选路停点(`design/gdd/ux/level-map.md:69` ;停点句唯一出处=`design/gdd/systems/冒险循环/关卡节点地图.md` 第 78 行「关卡开始 → 呈现节点图选路停点」) | 同 R1 | `ui_click_probe.gd:_ready` (同段追加「关卡画面在位」) | 探针 | 同 R1 真点链(大门命中区真点 →「是」钮真点) | `run_scope.is_adventure` + `main.ui.modals.run.level_screen.visible` (停点呈现面,非终态推断)。**本行是开局终态在位断言,被测改动的特有提交面由 R1 承载**——`is_adventure` 在既有探针已断(`ui_click_probe.gd:704` ),把件1 的改动绑在它上不成立,故本行的效力=与 R1 同批缺一即红 | 既有:营地大门两分支确认与断点续玩接线 |
| R3 | 件2 两出口与三出口形态的按钮位次=推进→次→维持(`design/gdd/ux/camp.md:16` ;位次定值唯一出处=`design/gdd/systems/表现与支撑/HUD框架.md` 第 90 行「三条纪律·其三」) | `confirm_dialog.gd:31-39` 三句 `add_child` 次序镜像;**成员面与连接一律不动** | `confirm_dialog_test.gd:_test_two_button_row_order` ; `confirm_dialog_test.gd:_test_three_button_row_order` | 单元 | 视图件对外入口 `ConfirmDialog.open(text, confirm_label, cancel_label)` / `open_three(text, confirm_label, secondary_label, cancel_label)` ——即四消费方实际用的那两个公开方法(`main_overlay_flow.gd:73` / `:79` / `:83` / `:129` ) | 测试自己传入三档互异文案(如「推进」「次推」「维持」),从弹窗节点向下按类型定位那个横排容器(HBoxContainer),断言其 `get_children()` 的**子节点顺序**:双钮形态 child(0) 文案=「推进」且 **child(2) ** 文案=「维持」——次钮在 `open()` 里只是 `visible=false` 、不从子节点表移除(`confirm_dialog.gd:47` ),双钮形态下子节点仍为 3 个,按下标断必须取 child(2)(写 child(1) 必红);三钮形态 child(0)/child(1)/child(2)=「推进」「次推」「维持」。另配非空前置:按钮行子节点数=3(防扫描面缩水静默绿)。按类型定位可成立已核:该弹窗树内只有这一个 `HBoxContainer` ( `UiKit.modal_shell()` 产 CenterContainer+ PanelContainer+ VBox,不产横排——`ui_kit.gd:509-525` ; `confirm_dialog.gd:26` 那条 HSeparator 与 `UiKit.button()` 的产件都不是 HBoxContainer)。判据面=树的公开子节点序(同 `system_test.gd:81-89` 断言层序的先例形态),**不读任何私有成员**,避开 `architecture.md:168` 视图单元接口与 `:323` 禁直引实现内部 | 新增:确认弹窗按钮位次与语义同钉 |
| R4 | 件2 左位那颗真点下去就是推进(`design/gdd/ux/camp.md:16` ;位次定值出处同 R3) | 同 R3 | `ui_click_probe.gd:_ready` (大门无断点段内,`push_click_at` 打**推进钮自身**全局矩形中心) | 探针 | 弹窗开态下按类型定位按钮行 `HBoxContainer` ,取其 child(0) 的 `get_global_rect()` 中心真点——**禁按「行矩形左位」算坐标**:该行 `alignment=CENTER` ( `confirm_dialog.gd:29` ),双钮可见宽 216+12+216=444<壳宽 460( `ui_kit.gd:578` 钮默认 `min_w=216.0` / `confirm_dialog.gd:20` 壳 `Vector2(460,0)` ),左右各留 8px 空档,打行矩形左位会落空 | 主证=`run_scope.is_adventure` 翻转+`_confirm_consumer` 清零;真点前置读 `main._confirm_consumer == "gate_new"` (该私有的直读属**探针既有先例**, `ui_click_probe.gd:272` / `:286` 现役同款,封装扫描件只覆盖 flow 件的 `root._` ——见 `presentation_encapsulation_sweep_test.gd:80-94` ,故本行不新开辟读面)——位次若错接,坐标命中的将是「否」,主证面即红 | 新增:确认弹窗按钮位次与语义同钉 |
| R5 | 件3 顶栏栏体几何与徽章落座(`design/gdd/ux/camp.md:41` ) | `camp_hud_band.gd:10-17` 改为调公共件出口得栏体+徽章落座改右对齐容器;`ui_kit.gd` 加带 α 常量与公开出口 | `system_test.gd:_smoke_camp_hud_band` | 集成 | 真实工程 boot 后经装配链 `main_ui_build.gd:120-121` → `camp_scene_view.gd:88-91` 落座;**须先开营地**(营地屏 boot 态为隐,`camp_scene_view.gd:53` ),走 `main._camp_pres.open_camp()` 探针既有用法并 await 排版帧,再读 `main.ui.modals.camp.scene.hud_band` ( `camp_scene_view.gd:49` 的公开句柄) | ①栏体色 `color.to_html(true) == "6e4526cc"` ——即规格「`#6E4526` × α0.80」的字面编码;**禁写 `.a == 0.80` **(实测色道单精度使该比较为 false,见第 2 节实测句);②栏体铺满:出口产出的那块色面 `get_global_rect()` 宽=1280、高=48——**宽度不是 tscn 锚点给的**(营地场景根由屏壳代码 new——`game/presentation/scenes/camp_screen.gd:13` `CampSceneView.new()` + `:14` `add_child` ,该根自身无锚无尺寸;承重实为 `ui_registry.gd:26` / `:61` 打的 FULL_RECT 注册,屏壳 `camp_screen.tscn` 根锚 preset=15 满铺),故实现首步先按 T3.0 同款时机量一次顶栏件现尺寸,再以此定断言值;③`mouse_filter == MOUSE_FILTER_IGNORE` ;④栏体是顶栏件的**第一个子节点**(子节点序=绘制序,色面必须先入才不盖徽章);⑤徽章 `get_global_rect().position.y == 0` 且 `get_global_rect().end.x == 顶栏 get_global_rect().end.x − 12` (x 向缺判据则位次改错仍绿,故与顶格同批配齐;两项都用全局矩形,不与局部 `position` 混写)。前置量测=T3.0 读 `get_combined_minimum_size().y` 须为 48(描边若计入得 50 → 触第 10 节 L3 第 5 条) | 新增:营地顶栏栏体定值与落座 |
| R6 | 件3 栏体对落位带底色对比 ≥3:1(`design/gdd/ux/camp.md:41` + `design/art/art-bible.md:452` ) | 同 R5 | `camp_scene_layout_test.gd:_test_hud_band_contrast_over_bg` | 单元 | 单元从 `camp_scene_layout_table.gd` 的 `hud_band_h` 出口取带高,读现行背景贴图 `res://assets/art/scene/scene_camp_bg.png` 该带像素(`load(...)` 取纹理再 `get_image()` + `get_pixel` ,先例=`terrain_tile_sets_test.gd:105-107` 的全像素扫描) | 规格侧算式核验(与 R5 分工:R5 核实装等值,本行核规格值本身达标)=测试内按 `camp.md:41` 写死 `#6E4526` 与 α0.80,与该带实测均色 alpha 合成后算 WCAG 对比,断言 ≥3.0;扫描面非空前置照 test-conventions §8.4(正面效力自检)配齐。**禁把视图件的 color 直接当预期值喂进算式**(那是 oracle 镜像,test-conventions §8.7 判红) | 新增:营地顶栏栏体定值与落座 |
| R7 | 回归·件1 未动的三条动线(`design/gdd/ux/camp.md:16` / `:22` ) | 无改动(`main.gd:208` / `214` 、`main_esc_flow.gd:46` ) | `ui_click_probe.gd:_ready` (既有大门两分支段+篝火离场段现有断言,本批零改写) | 探针 | 既有真点链 | 既有绑定面原样:`is_adventure` 不翻转、营地场景根 `visible` 、`_camp_data()["balance"]` 不变 | 既有:营地大门两分支确认与断点续玩接线 |
| R8 | 回归·件2 未触的路由与件数断言(`design/gdd/ux/camp.md:16` ;位次与件数定值出处同 R3) | 无改动 | `ui_click_probe.gd:_ready` (次钮隐藏断言 `:694` )+ `system_test.gd:_smoke_boot_chain` (开始层三钮计数 `:195` ) | 探针/集成 | 既有真点与 boot 链 | 既有绑定面:`_secondary_btn.visible` 为假(两出口形态)、开始层可见钮数 == 3 | 既有:营地大门两分支确认与断点续玩接线 |
闸口径:本批改动含 `game/` 下非 `.md` 的行为载体,合回后远端 CI 走代码域全档;开发期按改完即测铁规以 `tools/run_all_gates.sh --code` 为选档入口(域划分唯一出处在脚本内,卡内不列闸件名单)。里程碑步出口跑一次所选档全套;波内修复只做出红件的最小单元最窄确认;新增测试先行孤立验证再并入全套。
**测试削弱申报 ** :允许改动 0 条既有断言。`ui_click_probe.gd:694` (次钮隐藏)与 `system_test.gd:195` (三钮计数)必须原样通过;本批位次改动若使二者失守=契约3 被违,停卡呈报,禁改判据求绿。**唯一允许的判据形态约束**:涉及色值与透明度的断言一律走 `to_html(true)` 或整体等值比较,禁浮点分量直等(第 2 节实测依据)。
**独立验收审计 ** :入口=`reports/iter<53>-验收审计-<日期>.md` ;由未参与实现的只读会话或子代理执行,未过不得合回(test-conventions §8.7+ iter 技能第 5 步)。验收档=中 ⇒ 审计深度按 §8.7 中档梯度。
---
## 9. 任务卡
### T1|开局路径的隐藏点收一处(≈0.25 工作日)
取用:`main.gd:292 func _start_adventure() -> void` (既有签名,零参数零返回)。
- [ ] T1.1 实装:`game/presentation/main.gd:292` `_start_adventure()` 函数体首行加 `ui.screens.start_overlay.visible = false` (位置在该函数现有第一句 `ui.flow.close(...)` 之前)。
- [ ] T1.2 实装:删除 `game/presentation/main.gd:194` 那句 `ui.screens.start_overlay.visible = false` (转调 T1.1 后它已无职责)。
- [ ] T1.3 验证:`python tools/run_system_test.py` 全绿——核 `_smoke_boot_chain` 与 `_smoke_run_lifecycle` 的既有开始层断言(`system_test.gd:170-171` / `:253` / `:261` )未失守。
- [ ] T1.4 验收:`ui_click_probe.gd` 大门无断点段(`:684-705` 区间内)追加两条断言并实跑——R1(确认后 `main.ui.screens.start_overlay.visible` 为假)、R2( `main.ui.modals.run.level_screen.visible` 为真,与既有 `is_adventure` 断言同批)。**帧口径**:段内既有 await 只 1 帧(`:703-704` ),选路停点成形的先例是 3 帧(`screen_flow_probe.gd:185-193` ,该段在 `await _frames(3)` 后断言「入口停点未落在关卡地图屏(level_screen 不可见)」——但它走 `_start_adventure_from_menu()` 函数直调,那条路径自带隐藏,所以从未抓到本缺陷)——追加断言前 await 到 3 帧,并把「停点成形所需最小帧数」实测值记进实现报告。落点=既有段内,不新建段。
- [ ] T1.5 验证:`python tools/run_all_gates.sh --quick` 对该件做最窄确认(探针闸段),先红后绿记进实现报告。
产出(T2/T3 无关,供回归引用):`_start_adventure()` 成为开始层隐藏的唯一开局出口。
### T2|确认弹窗按钮位次镜像(≈0.5 工作日)
取用:`confirm_dialog.gd:43 func open(text: String, confirm_label: String, cancel_label: String = "取消") -> void` ; `confirm_dialog.gd:55 func open_three(text: String, confirm_label: String, secondary_label: String, cancel_label: String) -> void` 。三颗钮的成员声明(`:14-16` )与连接属本卡禁动面,不取用。
- [ ] T2.1 实装:`game/presentation/views/confirm_dialog.gd:31-39` 三颗钮的 `add_child()` 次序整体镜像为 确认 → 次 → 取消。对象创建、`.pressed.connect(...)` 三句连接、成员声明(`:14-16` )、`open()` / `open_three()` 签名与文案参数一律不动(契约3)——**本卡不给测试开任何新成员或新公开出口**,位次判据走公开子节点序(依 `architecture.md:168` 视图单元接口与 `:323` 禁直引呈现层实现内部)。
- [ ] T2.2 验收(新增件):新建 `game/tests/unit/presentation/confirm_dialog_test.gd` ,套件入口=`func _initialize() -> void` (视图件套形态先例=`camp_scene_layout_test.gd:12-13` 的 `call_deferred` 串法,**不是** `_init` ),体内 `call_deferred` 两个私有函数——`_test_two_button_row_order()` :自造实例后调 `open("t", "推进", "维持")` ,从该实例向下按类型定位那个 `HBoxContainer` ,断言其 `get_children()` 的 child(0).text 为「推进」、**child(2).text** 为「维持」,且子节点数=3(次钮只置 `visible=false` 不移除——`confirm_dialog.gd:47` ,双钮形态下维持钮在 child(2) 不是 child(1));`_test_three_button_row_order()` :调 `open_three("t", "推进", "次推", "维持")` ,断言 child(0)/child(1)/child(2) 文案依次=「推进」「次推」「维持」。全程只读公开树面与 Button 的公开 `text` ,不触任何私有成员。入册=在 `game/tests/run_all.gd:166` 起的硬编码清单里追加一行 `{"path": "res://tests/unit/presentation/confirm_dialog_test.gd", "expect": 0}` 并行尾注一句本套件职责(清单条目形态照同目录既有行)。
- [ ] T2.3 验收:`ui_click_probe.gd` 大门无断点段内追加 R4。**前置重开**:`:702` 那一次真点已把 `gate_new` 消费掉(`main.gd:215` 置空),故本步须先 `main._camp_pres.open_camp()` → `ProbeUiUtil.push_click_at(gate 命中区中心)` 重出弹窗,再取按钮行左位——坐标=自弹窗节点向下按类型定位到的 `HBoxContainer` 的 child(0) 全局矩形中心,经 `ProbeUiUtil.push_click_at` 真点;断言真点前 `_confirm_consumer == "gate_new"` 、真点后 `run_scope.is_adventure` 为真且 `_confirm_consumer` 清零。
- [ ] T2.4 验证:孤立先跑 T2.2 新套(`… --script res://tests/run_all.gd` 单套件口径),绿后并入全套;四处消费方动线由 `ui_click_probe.gd` 既有段与 `run_all` 单元套确认未失守(R8)。
产出:位次成为规格钉死的呈现定值,推进钮恒为该按钮行的 child(0)。
### T3|营地顶栏可见栏体(整件外观封在公共件一个具名出口,≈0.75 工作日)
取用:`UiKit.CAMP_HEADER_BAND` ( `ui_kit.gd:195` ,色值单点);`UiKit.keystone_badge(text: String) -> KeystoneBadge` ( `ui_kit.gd:655` );`CampHudBand._init()` ( `camp_hud_band.gd:10` ,该件 `:14` 现役已在调 `UiKit` )。**盘上三处同形铺面写法不在取用面**(`ui_assembler.gd:224-230` 、`ui_kit.gd:486-491` 、`ui_kit.gd:537` )——本批既不让顶栏件复用它们,也不把它们收编进出口,理由见第 3.3 条、契约4 与第 12 节末段。
- [ ] T3.0 前置读数:**入树之后**再量——`KeystoneBadge` 是 PanelContainer( `ui_kit.gd:634-656` ),最小尺寸由容器排版产出,刚 `new()` 未入树时读数不可信。落点=在系统测试宿主里经 `main.ui.modals.camp.scene.hud_band` 链取**已在树的现成徽章实例**,先开营地并 `await` 排版帧(帧数口径同 T1.4),再读 `get_combined_minimum_size().y` ( `ui_kit.gd:640` 的 `panel_flat(...Vector4(14,8,14,8))` 加在 32px 图标上下各 8=48,两个未证实项都能把它推离 48:①`border_w=1` 是否计入最小尺寸;②徽章内 Label 用 18px 档(`ui_kit.gd:648` 取 `FS_SUB` ,常量见 `:438` ),字体行高若大于 32 则最小高由文字而非图标决定——**这两条都是推导,不是实测量**)。读数=48 → 按 T3.3 顶格落座;读数≠48(如 50)→ 停步走第 10 节 L3 第 5 条呈报,禁自行改栏高或改徽章内边距。读数与取数时机一并写进实现报告。
- [ ] T3.1 实装·出口本体(Q1 终裁·11-06 用户裁「整件外观封在公共件一个具名出口,同形旧实现不收编」):`game/presentation/views/ui_kit.gd` 色板段加 `const CAMP_HUD_BAND := Color(CAMP_HEADER_BAND, 0.80)` (带 α 先例=同文件 `:189` /`:190` ,收口非新增语义色的先例=`:200` );工厂段加公开出口 * * `static func camp_hud_band_surface(host: Control) -> ColorRect` **,体内依次=新建 ColorRect + `rect.color = CAMP_HUD_BAND` + `rect.set_anchors_preset(Control.PRESET_FULL_RECT)` + `rect.mouse_filter = Control.MOUSE_FILTER_IGNORE` + `host.add_child(rect)` + `return rect` 。**形参只有 host**:色、α、铺法、点击语义全写死在体内——这就是「一个物件的外观不得拆两处」的确切实现形(对照两个作废形态:值在公共件+铺法在视图=拆两处;出口开 color/pass_input 形参=把物件定义推回调用方,并为无关同形件预留通用性)。出口名钉死在这块带子上,不作通用铺面器。
- [ ] T3.2 实装·顶栏件:`camp_hud_band.gd` 的 `_init()` 内在挂徽章之前调 `UiKit.camp_hud_band_surface(self)` (契约5 的 IGNORE 由出口内部保证,调用方没有可以忘记的形参);子节点序即绘制序,栏体先入、徽章后入。本文件内不再出现 `ColorRect.new()` 。
- [ ] T3.3 实装·徽章落座(**Q2 已裁乙·2026-11-05 用户裁**):`camp_hud_band.gd` 内加一层右对齐容器承载徽章——`HBoxContainer` 铺满栏体(`PRESET_FULL_RECT` 后置 `offset_right = -12.0` )、`alignment = BoxContainer.ALIGNMENT_END` 、**`mouse_filter = Control.MOUSE_FILTER_IGNORE` (容器自身默认 STOP,与出口内那处 IGNORE 是两个点、必须同批落,漏一处顶排物件就点不动)**;替换 `camp_hud_band.gd:15-16` 现值(`PRESET_CENTER_RIGHT` + `position=(-160, 8)` ),位数增宽自然向左展。容器摆位机制先例=`confirm_dialog.gd:27-29` (同件同机制,那里 alignment 取 CENTER、这里取 END);内缩 12px 见白名单第 3 条。
- [ ] T3.4 验收:`game/tests/system_test.gd` 新增 `_smoke_camp_hud_band()` , **接进 `_split_tail()` 的 await 链**( `:40-44` 那一串 `await _smoke_*()` 之后追加 `await _smoke_camp_hud_band()` ),**不是接进 `_initialize()` **——`_initialize()` 只调一句 `_split_tail()` ( `:26-28` ),而摘要打印与 `quit()` 都在该尾段末尾(`:47-48` ),协程段不被 await 就会在首个 await 处被 quit 截断=静默不执行=假绿(该教训已写在 `:40` 行尾注里)。段内自持 `load("res://presentation/main.tscn").instantiate()` + `root.add_child` + await 帧、末了 `queue_free()` ,形态照 `_smoke_run_lifecycle()` ( `:213-217` / `:206-207` )。实现 R5 的五项判据(色值走 `to_html(true) == "6e4526cc"` 或整体等值比较,**禁浮点分量直等**;`get_global_rect()` 的尺寸=顶栏件实测宽 × 48; `mouse_filter == MOUSE_FILTER_IGNORE` ;栏体是顶栏件的第一个子节点;徽章全局矩形 `position.y == 0` 且 `end.x == 顶栏 end.x − 12` )。**出口须在 `_init()` (入树前)被调**: `set_anchors_preset(PRESET_FULL_RECT)` 是把四边 offset 归零的入树前动作,与 `_modal_dim()` / `overlay_bg()` 的现役形态一致。
- [ ] T3.5 验收:`game/tests/unit/presentation/camp_scene_layout_test.gd` 新增 `_test_hud_band_contrast_over_bg()` 实现 R6:读 `hud_band_h` 与背景贴图该带**全像素**均色(取样法照 `terrain_tile_sets_test.gd:105-107` 的双层全扫,非步长抽样),规格值 `#6E4526` /α0.80 按 `camp.md:41` 在测试内写死后合成算 WCAG 对比,断言 ≥3.0;扫描面非空前置照 §8.4 配齐。
- [ ] T3.6 验证:两条新测先行孤立跑绿再并入 `--code` 全套。本批不触任何既有遮罩/亮底/页壳件,故无等值回归义务——回归证据=第 5 节七条未改动动线与全站弹窗现有断言在 `--code` 全档中仍绿。营地屏截图面由渲染闸的七屏段随批产出,作 R5/R6 对照取证。
- [ ] T3.7 目检登记:营地顶栏观感(「成一条可辨窄带、徽章落在带内」)登记一行进实现报告实机目检总清单,登记即完成义务。
产出:`CAMP_HUD_BAND` + `camp_hud_band_surface()` 是这块带子外观的唯一出处(同文件相邻两段);`CampHudBand` 的外观=该出口+右对齐容器+徽章三件,视图内无一处自建 ColorRect;盘上三处同形写法原样未动。
### T4|产出物落位卡(≈0.5 工作日,末卡)
- [ ] T4.1 代码域全档全绿后、合并前写 `reports/iter<53>-实现报告-<日期>.md` :各卡状态+实机目检总清单(含 T3.7)+遗留读数义务+实现决定记录(超白名单的微决策逐条登记)。
- [ ] T4.2 写 `reports/iter<53>-反哺点-<日期>.md` :第 6 节每条命中项都要有落点(哪一节、改成什么、依据什么);无命中也要写「本批零反哺点」并附核过哪几处。
- [ ] T4.3 核对 `game/tests/README.md` 两行新增能力名与实际落地函数名逐字一致(名实不符=停卡退回写卡段)。
- [ ] T4.4 呈报合回清单,等用户发令再走收口(冻结→件核→并 master→重塑→删区)。
**估时合计 ≈2.0 个工作日 ** ( T1 0.25+ T2 0.5+ T3 0.75+ T4 0.5)。T3 的 0.75=出口一枚(十行内)+顶栏件改两处(调出口+落座容器)+两条新测+孤立验证。无收编、无等值回归、无两次全档义务。
---
## 10. 异常分级
- **L1 自救**:探针坐标算错导致 R4 打空——重算按钮行全局矩形中心,禁改为信号直发(段内既有 `ui_click_probe.gd:696` 的 `cancelled.emit()` 是取消路径的信号注入先例,注释自陈「真实信号——cancelled 钮同源」;本批 R4 要钉的正是**位次**,直发不经位次,等于没测——依据=test-conventions §8.3 真实入口收窄条,契约7 同源)。
- **L2 记录继续**:R6 均色取样读数与卡内实测 `#DEEAE7` 有 ≤3/255 的取样步长差——按实测值断言、卡内读数差写进实现报告,不改阈值。
- **L3 停机呈报(写报告等用户)**:
1. boot 后 `main.ui.modals.camp.scene.hud_band` 取不到实例(装配链与第 3.3 条现状不符)=卡片现状事实失效,停卡退写卡段;
2. R4 坐标真点无法区分左位钮与相邻钮(按钮行 `alignment=CENTER` 下实际矩形与规格不符)=位次与语义绑不上观测面,触 test-conventions §8.4「判据绑不上=停卡呈报」出口;
3. 位次改动使 `system_test.gd:195` 或 `ui_click_probe.gd:694` (次钮隐藏断言)失守=契约3 被违,禁改判据求绿;
4. 机检预算互斥限**本批触碰的 presentation 面文件**: `tools/gdstyle_gate.py:45` 的扫描面=`game/core` / `game/data` / `game/presentation` ,脚本头注(`:8` )明写排除 probe/sim/tests——故新增单元套**不在** S13 射程,该条只对 `main.gd` / `confirm_dialog.gd` / `camp_hud_band.gd` 生效。若这三个件的 S13 键与第 13 节预算数字冲突且无豁免通道=上游缺陷,停卡退回写卡段,禁自造第三条路(本技能第 13/14 节)。
5. T3.0 量得徽章 `get_combined_minimum_size().y` ≠ 48(描边宽 1px 计入、或 18px 文字行高高于 32px 图标使最小高由文字决定,两条都会推得 >48)=「顶格落座」在 48px 栏内放不下,第 2 节与 `camp.md:41` 的推导句失效,停步呈报,禁自行改栏高、改徽章内边距或放宽 R5 判据。
---
## 11. 代拍板白名单(超清单必进实现报告「实现决定记录」并呈报)
1. 断言消息尾缀文案(照 `〔营地图批 V3〕 ` 形态自拟)。
2. 新单元套件的套件注册名与 `run_all.gd` 册内落点序。
3. **徽章水平内缩 12px ** : `camp.md` v2.8 只钉「右位顶格」未钉内缩值,取 UiKit 钮间距同档 12(先例=`confirm_dialog.gd:28` `separation=12` )。
4. R6 取样密度——照 `terrain_tile_sets_test.gd:105-107` 的**双层全像素扫描**(该件不是步长抽样,卡内早先写的「每 4 行×每 8 列」口径作废)。
5. `_smoke_camp_hud_band()` 在 `_split_tail()` await 链内的插入位(不改变既有段序;接进 `_initialize()` 不成立——见 T3.4)。
6. 出口与常量的命名(卡内定名 `UiKit.camp_hud_band_surface()` 与 `CAMP_HUD_BAND` )——可按同文件命名习惯微调后缀形态;**若实现把它改成带 color/pass_input 形参的通用铺面器、改成「值与形分两处」、或另起第二家公共出口,一律触契约4,属 L3 呈报**。
不在白名单:α 值、栏底色、栏高、位次序、隐藏点数量与位置——这些是规格钉死项,改动一律 L3 呈报。
---
## 12. 落位与可复用性预检(与第 7 节结构图互指)
| 新增/改动件 | 复用面(盘上已有什么) | 唯一面 | 分层与交互面 |
|---|---|---|---|
| 顶栏带外观出口(T3.1/T3.2) | **现成件已复用 ** :徽章走 `UiKit.keystone_badge()` ( `ui_kit.gd:655` , `camp_hud_band.gd:14` 是现役调用方),色值走在册 `CAMP_HEADER_BAND` ( `:195` )。盘上另有三处「新建 ColorRect+铺满宿主」的同形写法(`ui_assembler.gd:224-230` 外部调用者零、`ui_kit.gd:486-491` 私有且仅 `:511` 一处用、`ui_kit.gd:537` 页壳底板)——**本批三者都不复用也不收编**:它们的变化原因是遮罩遮挡语义与页面底色档位,与本带的 HUD 定值无关。出口落 `ui_kit` 、不经装配器,因顶栏件已在引用 `UiKit` ,而 `views/` 引装配器零先例。早先两版判据(「两份都不复用、按 views 现行形态自建」与「四份同形收成带形参的通用出口」)都已作废,逐次理由见第 15 节 Q1 裁决史 | 这块带子的外观全仓一处定义=`CAMP_HUD_BAND` + `camp_hud_band_surface()` (同文件相邻两段);禁在别处出现第二组「同一色+同一 α」;出口内 `MOUSE_FILTER_IGNORE` 写死——旁证:同文件 `:540` 页壳底板显式写 STOP、`:864` 与 `camp_scene_view.gd:145` 须显式写 IGNORE,可见 ColorRect 默认即 STOP,漏设不报错只会静默吃掉顶排点击 | 呈现层内一个纯构建出口,零状态、零信号、不持引用;顶栏读数仍经 `camp_data()` 投影单口(`camp_hud_band.gd:26-27` );`ui_assembler.gd` 与 `modal_shell()` / `page_shell()` 一律不动 |
| 开始层隐藏(T1.1) | **复用 ** 既有语义句本身——`main.gd:194` / `:246` 就是同一条责任,本卡把它收进被调方 | 开局路径隐藏点唯一(`_start_adventure()` ),续玩路径唯一(`_resume_from_menu()` );其余 10 处开层自管点不在本契约射程(契约1 已收窄) | 组合根内;不触 Core,不新增信号 |
| 按钮位次(T2.1) | 无新增件——只镜像既有三句的次序。**本卡不新增成员、不新增公开出口**:位次判据走公开子节点序(R3),语义判据走坐标真点(R4) | 位次定值只写在视图件 `_init()` 一处,四处消费方零副本 | 呈现层;信号对象路由不动;依 `architecture.md:168` 「视图单元接口=信号外发+setter 只读注入」与 `:323` 「禁直引呈现层实现内部」,不为测试开成员面(该写法曾在本卡出现过,已撤回,登记在第 16 节轮次 2) |
| 徽章落座(T3.3,Q2 已裁乙) | 已有做同样事的东西:`HBoxContainer` + `alignment` 摆位机制(`confirm_dialog.gd:27-29` ——该件 `alignment` 取的是 `ALIGNMENT_CENTER` ,**是同一机制的先例、不是右对齐的先例**;本件同处改取 `ALIGNMENT_END` 即右对齐)——**Q2 已裁乙(2026-11-05 用户裁)**,采容器右对齐形态;另两案(锚点生长、`size_updated` 回调)作淘汰留档见第 15 节 | 内缩值 12px 只在落座一处出现一次,禁在断言里另写第二套推导 | 呈现层内 |
| `confirm_dialog_test.gd` ( T2.2 新增) | 盘上无 ConfirmDialog 专属单元套(grep 命中面=`system_test.gd` /探针的宿主级引用与 `README.md:159` 能力行);同目录 `camp_scene_layout_test.gd:12-13` 是可参照的套件形态(入口 `_initialize()` + `call_deferred` ),不是可复用的承载 | 位次判据只此一处;R4 探针判据与之互补(一个核序、一个核语义) | 测试层;经 `ConfirmDialog.open()/open_three()` 公开入口进出,断言只读公开子节点序与 Button 的公开 `text` ——「读私有成员」的写法曾在 R3 出现,已按 `architecture.md:323` 撤回 |
| `system_test.gd:_smoke_camp_hud_band` ( T3.4)/`camp_scene_layout_test.gd:_test_hud_band_contrast_over_bg` (T3.5) | **扩展**既有套件,不新建宿主;取样法复用 `terrain_tile_sets_test.gd:105-107` 的双层全扫+`get_pixel` 路径 | 几何判据落系统测试、对比判据落布局单元套——两处职责已由套件名界定,禁第三处重复断言 | 测试层 |
**为什么出口只服务这块带子(2026-11-06 用户终裁;本段取代本卡此前两份互相矛盾的留痕句——「接受第四处重复故不抽工厂」与「四份同形收成带形参的通用出口」) ** :用户裁的是两件事的合成。①**一个物件的外观不得拆两处**——色值、α、铺法、点击、挂载这五件事必须在同一个出口内定义,不许「常量在公共件、矩形在视图」;那等于要求每个改它的人同时记得两处,漏一处就得到一个自相矛盾的物件。本会话确有改漏实例:同一组色值要在两份文档里成对改,卡内同步面还写了「禁单改一处」的防呆,却在代码面上造出另一个新的成对结构。②**抽不抽公共器不由形状撞车决定**——不得为了「全仓只剩一处 ColorRect 铺满」这种读数好看,把遮罩、页底、HUD 带三个变化原因绑进一个带形参的通用器;那既不内聚(一个函数回答三个不相关的问题)也不低耦合(改顶栏带要回归全站弹窗底与两个全屏页),而这三处今天都没有待改的东西。**早先那份「三次法则、意图未第三次出现故不抽工厂」的留痕句,其动机经用户点破是「少动文件」而非纪律,作废**;但据此反弹出的「整案收编+形参化点击语义」同样作废。代价面(`ui_kit` 公开方法 23→24 须修订登记基线)见第 13 节例外申报;回归面因不收编而留在本件射程内,估时相应回落。
---
## 13. 实现规范预算(与第 7 节结构图互指)
**新件三查 ** ——本批新增文件仅 `game/tests/unit/presentation/confirm_dialog_test.gd` :
- **三查对本件不适用**: `tools/gdstyle_gate.py:45` 扫描面=`game/core` / `game/data` / `game/presentation` ,脚本头注 `:8` 明写「probe/sim/tests 测量面」排除——测试面文件不进 S13 读数,无键可对账。
- 尺寸预期(照套件形态先例自持,不作机检项):套件入口 1 个(`func _initialize() -> void` , **非** `_init` ——先例=`camp_scene_layout_test.gd:12-13` )+私有 `_test_*` 2 个+类变量 0– 1。
- 迁移函数对账:无迁入(该件全新增,`tools/gdstyle_baseline.txt` 无历史键,跑批后若出超默认新键须申报)
**存量触面一查 ** ——S13 键较登记值只降不升:
| 文件 | 基线登记(`tools/gdstyle_baseline.txt` ) | 本批预期 |
|---|---|---|
| `game/presentation/main.gd` | 第 11 行 `quality/max-public-methods = 32` | 不动公开方法面(函数体内加一句+另一函数删一句)→ 读数 32 持平 ✓ |
| `game/presentation/views/ui_kit.gd` | 第 12 行 `quality/max-public-methods = 23` | 本批**加一枚 `const` + 加一个公开出口方法** → 读数预期 23→**24**,超登记值 → 见下方「指标例外申报」。色板快照面不受常量影响(`tools/gen_palette_baseline.py:42` 只正则 `Color8(数字,数字,数字)` ,带 α 的 `Color(...)` 从不进快照,同文件 `TOAST_BG` / `TIP_BG` 即此形态);但**方法数是真升**,不申报就是假绿 |
| `game/presentation/views/confirm_dialog.gd` | 无登记键(在默认阈值内) | 仅语句重排,分支与返回数不变 ✓ |
| `game/presentation/views/camp_hud_band.gd` | 无登记键 | `_init()` 换成调出口+加一层容器,分支数不变 ✓ |
| `game/probe/ui_click_probe.gd` | 无登记键(探针大文件另有基线口径) | 同段追加断言,函数不拆;若单函数分支数超默认,按 L3 第 4 条呈报而非自拆 |
| `game/tests/system_test.gd` | 无登记键 | 新增一个私有函数,公开方法面不变 ✓ |
**指标例外申报(本批一项) ** : `game/presentation/views/ui_kit.gd| quality/max-public-methods` 由登记值 23 升至 24,起因=用户 2026-11-06 裁「一个物件的外观不得拆两处」,要求在公共件出一个公开出口承载这块带子的整件外观。处置=实现批跑出该新键后,把 `tools/gdstyle_baseline.txt` 该行改为 24 并在提交信息里申报(基线手动修订须经用户批准——本条即申报与请求)。除此之外本批不申请任何超默认项。
---
## 14. 拆分边界纪律
本批新增的可复用单元只有公共件里那一个出口函数,故本节条款的适用面=该出口,判据权威=code-conventions §1.1 拆分判据,此处不复制定文:
1. **它有可陈述的职责与单一变化原因 ** : `UiKit.camp_hud_band_surface()` 的职责语句=「把营地顶栏这块带子按定值铺满宿主并挂上去,返回句柄供调用方读取与断言」;单一变化原因=这块带子的外观要变(以后要求圆角、内缩、换遮挡方式,都只改这一个函数+那枚常量)。它不承载玩法状态、不承载文案、不做判定、不接形参选择;徽章的摆位不由它负责(归顶栏件内那层右对齐容器,T3.3)。
2. **集体身份成立 ** :它服务的是营地顶栏这一块具名带子,不是「所有 ColorRect 铺满动作」的收纳盒。**故意不做**成通用铺面器:若把模态遮罩、页壳底板一并收进来(用户 2026-11-06 否掉的形态),这个单元就从「一块带子的定义」变成「三种不相关意图的并集」——正是拆分判据要拦的形态。
3. * * 「过阈值」只作发现信号**:本批不以任何计数变好看为目标;公开方法数上升是它的代价(见第 13 节例外申报),不是它的动机。
4. **拆不出内聚单元即停卡呈报 ** :若实现期发现该出口必须塞进条件分支才能同时容纳顶栏带与其它用途,说明本卡对「只有这一个消费者」的判断失真——停卡呈报退设计段重议,禁硬并为凑绿。新增单元仅这一个出口函数+一枚常量+一个私有测试套件,无段件/状态件迁出。code-conventions §1.1 与本节互指;实现期若需拆 `camp_hud_band.gd` 或 `main.gd` 才落得下,属卡片未预见的结构动作=L3 呈报,禁为凑绿硬拆。
---
## 15. 待裁点(三轮复核产生;Q1 因写卡段自决被驳回而重开过、又因出口的执行形态被再裁一次——全程留痕)
独立复核(未参与撰写的只读子代理)三轮:轮次 1 打回一次,四条闭合里三条由写卡段按权威文档自决落卡,第四条拆成两案呈用户裁决;轮次 2 抓到「矩形谁建」这条轴属越权自决;轮次 3 抓到收编版四处硬伤并生成 Q4。**当前状态:Q1/Q2/Q3 已裁尽,Q4 因 11-06 用户再裁而消解(不再是一条分叉),本卡零待裁点,开工门=U0(用户批卡)。**
### Q1|顶栏这块色面从哪来——**已裁(终态=公共件一个具名单参出口,同形旧实现一律不动)**
事实底座:`ui_assembler.gd:224-230` 的 `overlay_bg()` 做了「新建 ColorRect+铺满锚点+挂上宿主+返回句柄」四步,**没设 mouse_filter**( ColorRect 默认 STOP),外部调用者零(只有该文件自身 `:100` 传 `BG_BRIGHT` 亮底、`:214` 传黑 0.6 遮罩);`ui_kit.gd:486-491` 的私有 `_modal_dim()` 是同一份东西的第二实现(同样不设 mouse_filter,仅 `:511` 一处用);`ui_kit.gd:537` 页壳底板同形但**显式**写 STOP、色为实色、后有石纹/暗角兄弟层;`views/` 目录自建 ColorRect 有 7 个文件 15 处先例;顶栏件 `camp_hud_band.gd:14` 现役已在调 `UiKit` 。
当时并列过的案与代价:甲=顶栏件 preload 装配器复用那一个出口(零重复,但给 `views/` 开一条该目录零先例的引用路径,且该文件头注自陈「接线拓扑唯一归组合根」);乙=顶栏件自建(与 `views/` 现状同构,但重复四行,且色值与铺法分居两处);丙=公共件出一个出口(真「整件外观一处定义」,代价是 `ui_kit` 公开方法 23→24 要修订登记基线)。
> **裁决史(四次)**
> ① **11-05**:用户裁「就按放在公共区域的这一层的方案来实现」。写卡段把它解释成"采纳我当轮给的整条推荐",落成**色值进公共件+矩形留在视图自建**,并在第 12 节写下"不抽公共工厂"的留痕句。
> ② **11-06 用户驳回①并重裁**:驳回理由是那条解释本身——"值"和"形"是同一个 UI 物件的两半,拆两处就要求每个改它的人同时记得两处,而"少动文件"不是纪律。**当时落成的重裁结果=丙的整案**:公共件出一个 `band_surface(host, color, pass_input)` 通用出口封装铺面与点击语义,并把 `_modal_dim()`、`overlay_bg()` 连同三处调用点同批收编,据此生成 Q4。
> ③ **11-06 写卡段据 Q4 呈「页壳底板收不收」**,用户判该设计整体不成立(原话:「你现在是有非常严重的设计问题」)——出口一旦需要形参承载三种点击语义,它就不再是「一个物件」而是三个意图的并集;会问出 Q4 本身就说明抽象切错了。
> ④ **11-06 终裁(现行)**:出口**只服务营地顶栏这块带子**——具名 `camp_hud_band_surface(host)`, **形参只有 host**,色值、α、铺满、穿点击全写死在体内;`ui_assembler.gd:224-230`、`ui_kit.gd:486-491`、`ui_kit.gd:537`、`ui_kit.gd:862` 一律**不收编、不动**。已落契约4/5、§2、§3.3、§5、§7、§12、§14、T3.1– T3.3。
> ⑤ 流程账:轮次 2 复核当时已把①那条轴标为**待裁**(原话:裁决句字面只覆盖色值轴),写卡段改成"自判+报备"自行闭合——那是越权(规矩:待裁必须问用户、禁代裁),第 16 节轮次 2 相应行按实情登记。
### Q2|徽章「右位顶格+内缩 12px」用什么机制随位数自适应——**已裁(2026-11-05 用户裁乙·容器右对齐)**
事实底座:徽章文案是 `"钥石 %d" % v` ( `camp_hud_band.gd:22` ,格式串单点在 `UiKit` badge 工厂),**宽度随余额位数变**;现值 `position = Vector2(-160, 8)` ( `camp_hud_band.gd:16` )把 x 写死——R5 要断言「徽章右缘 == 栏右缘 − 12」,写死偏移在位数变化时必然失位(现值 -160 只对当时那个位数读数成立)。
| 案 | 做法 | 代价 |
|---|---|---|
| 甲 | 锚点右钉 + `grow_horizontal = GROW_DIRECTION_BEGIN` + `offset_right = -12` 、`offset_top = 0` | 纯声明式、无回调;依赖 Control 生长语义(须开工首步实测读数确认,Godot 4.7 锚点+offset 与 custom_minimum_size 的相互作用我不凭记忆断言) |
| 乙 | 栏体内套一个右对齐 `HBoxContainer` ( `alignment = END` ),徽章作子件由容器摆位 | 与 `UiKit` 既有容器用法同构(弹窗钮行 `confirm_dialog.gd:27-29` 就是 `HBoxContainer` + `alignment` );代价是多一层容器节点,栏体色面与容器的父子关系要重排 |
| 丙 | 保持现锚点,接徽章 `size_updated` 信号在回调里重算 x | 改动面最小;代价是多一条运行期回调路径(与「显式触发才变」的顶栏刷新纪律并存,需在卡内申报新观测路径) |
写卡推荐=**乙**,理由=仓内已有同类摆位先例(容器 `alignment` 摆位,非手算偏移),且 R5 的 x 向判据在容器形态下读数最直白。甲依赖我不肯凭记忆断言的引擎语义(AGENTS.md:不确定的 API 一律核实后再用,核实前不作推荐)、丙新增运行期路径。
> **裁决(2026-11-05 用户裁·乙 容器右对齐)**:已落 T3.3 与第 12 节,Q2 清零。
**Q1/Q2 与第三条(闸件缺口是否登记)都已裁完并落卡,本卡零待裁点,开工门=U0。 **
### Q4|页壳底板要不要一并收进同一个出口——**已消解(11-06 用户终裁:不收编,出口只服务顶栏带)**
留档(非现行分叉):`ui_kit.gd:537` 页壳底板与出口形状相同(新建 ColorRect、赋色、铺满、挂上宿主),差别是它**显式**写 `MOUSE_FILTER_STOP` 、色取 `BG_BRIGHT` /`BG_ROOT` 实色,且后面紧跟石纹层与暗角层作兄弟节点——它是「页面底」,不是「遮罩/条带」。`ui_kit.gd:862` (竖卡 18×16 小色块)不同形(手工 position/size、不铺满)。轮次 3 把前者判为待裁并生成 Q4,呈报时并列「不收编(甲)/一并收编(乙)」两案。用户回话否定的是这条呈报的**前提**:出口本来就不该是通用铺面器,所以「第四处收不收」不成立。按终裁④,`ui_assembler.gd:224-230` 、`ui_kit.gd:486-491` 、`ui_kit.gd:537` 、`ui_kit.gd:862` 四处全部原样不动。
### 其余复核发现的处置(已落卡,非待裁)
自判与补写两类已按复核者自己落卡的规矩改进行内:契约1 收窄措辞、`_start_adventure()` 函数体行号订正、失败分支终态申报、帧口径、R6 输入来源改读实件、R8 行号与能力行拆正、结构图验收行补 R7/R8、悬空「行为表」引用、L1 引用行号、白名单第 4 条取样口径、`_initialize()` 入口名、新件三查对 tests 不适用、`main.gd:137` 与其余开层点不受契约1 约束的明示、R3 child(2) 硬伤、R5 开营地前置与 await 时机、T3.0 入树读数时机、1280 宽承重链改引 `ui_registry.gd:26` / `:61` 、徽章 x 向判据改全局矩形、显隐点 12→13、`views/` 先例 8 文件→7 文件 15 处、步骤号与 R 行口径重编号。(轮次 1 对 R3 给的「升成员供测试直取」处置已在轮次 2 撤回——它抵触 `architecture.md:168` 视图单元接口与 `:323` 禁直引呈现层实现内部,改判为公开子节点序判据。)
两条闸件面发现**均已登记为工程改动待办**(用户 2026-11-05 口径:登记后本批不管):认锚式字符类不含中文段(`tools/pipeline_gate.py:68` )、层序落位单口的扫描面不含子目录(`game/tests/unit/contracts/source_guard_test.gd:85-99` )。两条都在待办清单在册(改动面=工具代码/状态=待执行),本批不动闸件。
复核未采信两条:复核者称 `ui_click_probe.gd:679` 是断点写盘句(实为段头注,断点注入在 `:706` 起);称 art-bible:452 宣称的五 token 机检「查无该件」(`tools/palette_check.py:22` 的 `ui_tokens.png` 就是 ui_kit 全量 Color8 token 快照基线,机制存在,只是不逐名比对该表五行——已写进契约4 依据,未采纳其结论)。
---
## 16. 复核记录
复核者身份=未参与本卡撰写的只读子代理(Agent 工具起的独立会话,禁写文件、禁跑闸),形态=只读子代理。轮次 1,发现 22 条,四类去向逐条登记:
| 轮次 | 复核者身份 | 发现(一句话) | 去向 | 处置结果 |
|---|---|---|---|---|
| 1 | 只读子代理·未参与撰写 | 契约1「隐藏点只许两处」按字面过宽——全库开始层显隐共 13 处 | 退回上游(复核者判)→ 落卡改自判 | 契约1 收窄为「限开局/续玩两条路径」,13 处逐条列名(`camp_shop_presenter.gd:43` / `:85` 、`main.gd:137` / `:194` / `:246` 、`main_adventure_flow.gd:145` 、`main_debug_flow.gd:88` 、`main_overlay_flow.gd:8` / `:17` / `:41` / `:48` / `:95` / `:101` )。复核者的「退回上游」定名不采纳:这是卡内条款措辞过宽,非规范冲突,写卡段可自改 |
| 1 | 同上 | `_start_adventure()` 函数体行号错(写 311,实止 308) | 自判 | §3.1 改 `292-308` 并注明 `:311` 是下一函数声明行 |
| 1 | 同上 | T1.1 落笔后启动失败分支的开始层终态由可见变隐藏,卡未申报 | 补写 | §3.1 该行补终态申报(致命屏自接管,无菜单可用) |
| 1 | 同上 | 大门段 await 只 1 帧,选路停点成形先例是 3 帧 | 补写 | T1.4 补帧口径+最小帧数实测记进实现报告;引 `screen_flow_probe.gd:185-193` |
| 1 | 同上 | `btn_row` 是 `_init()` 局部变量,R3「逐位相等」写不出来 | 补写(阻塞) | 当时把 `btn_row` 升为成员并申报受控例外;该处置在轮次 2 撤回(抵触 `architecture.md:168` 视图单元接口与 `:323` 禁直引呈现层实现内部),现行判据=公开子节点序,不新增成员 |
| 1 | 同上 | §12 自称「不直取私有」,R3/R4 实际直取私有成员 | 自判 | 同上:先改为受控例外口径,轮次 2 再改为完全不读私有成员(R3 走子节点序、R4 走坐标真点) |
| 1 | 同上 | `:702` 真点已消耗 `gate_new` ,R4 需重开营地+大门才有左位可点 | 补写 | T2.3 补「前置重开」步与坐标取法 |
| 1 | 同上 | L1 引用的 `ui_click_probe.gd:679` 不是旧口径注释;段内直发面在 `:696` ;「emit 不算真实入口」属 §8.3 而非契约7 | 自判+**部分不采信** | L1 改引 `:696` 的 `cancelled.emit()` 并注依据=test-conventions §8.3。**但复核者称 `:679` 是断点写盘句,经我回读不成立**——`:679` 确为段头注「大门两分支断言段」,断点注入起 `:706` ;另 R8 原引 `:696` 亦错,次钮隐藏断言实为 `:694` |
| 1 | 同上 | `ui_assembler.gd` 无 `class_name` ,现网一律 preload, `views/` 零先例;卡内 `UiAssembler.overlay_bg(...)` 写法不成立 | 待裁 | 第 15 节 Q1 全案并列(复用装配器/视图内自建/公共件出出口),含三案代价;T3.1 改为「待 Q1 裁决后落」 |
| 1 | 同上 | 徽章自高 48 系推导,`panel_flat` 带 `border_w=1` ,描边若计入则 50、R5 顶格判据即红 | 补写(复核者自标「这是推测,未跑批」) | T3.0 新增前置读数步(量 `get_combined_minimum_size().y` );≠48 走 L3 第 5 条;§3.3 与 R5 的推导句标为未实测 |
| 1 | 同上 | 12px 内缩无可达机制(徽章宽随位数变,现值写死 x 偏移);R5 只断 y 向,x 写错仍绿 | 待裁+补写 | 第 15 节 Q2 三案并列(锚点生长/容器右对齐/size_updated 回调);T3.3 改「待 Q2 裁决后落」;R5 已补 x 向判据(`end.x == 栏 end.x − 12` ) |
| 1 | 同上 | R6 若把实现的 `Color(UiKit.CAMP_HEADER_BAND, 0.80)` 当输入=oracle 镜像 | 自判 | R6 改为规格侧算式核验(测试内按 `camp.md:41` 写死 `#6E4526` /α0.80),并明写「禁把视图件 color 喂进算式」,依据=test-conventions §8.7 |
| 1 | 同上 | §11.4 称 4× 8 步长「沿 `terrain_tile_sets_test` 口径」错,该件是全像素扫描 | 自判 | 白名单第 4 条改全像素双层扫描,并声明卡内早先步长口径作废 |
| 1 | 同上 | 数学校核:全扫与抽样均色=RGB(223,235,232),与卡内 `#DEEAE7` 差 ≤1/255;叠后对比 4.29:1(卡 4.27)、徽章对天空 1.30:1(卡 1.29) | 自判(读数采纳,容差不改) | 落位带前提经其独立核对(背景层 `Rect2(0,0,1280,800)` 、围墙 y=261、大门 y=250 → 0–48 带只含背景);差值落 L2 容差内,不放宽阈值 |
| 1 | 同上 | §1 完成定义与 §5 写「七行」,对照表实为 R1–R8 | 自判 | 完成定义改「八行(R1–R8)」(收编版曾扩到 R9,随该版作废回到八行) |
| 1 | 同上 | §5 引「第 1 节行为表」,本卡无该表(悬空引用) | 自判 | 改为「七条未改动动线」自足表述 |
| 1 | 同上 | §7 结构图 `ui_click_probe` / `system_test` 的验收行列缺 R7/R8 | 补写 | 结构图两行补齐 R1、R2、R4、R7、R8 / R5、R8 |
| 1 | 同上 | gdstyle 只扫 core/data/presentation, tests 不在面 → §13 新件三查与 L3 第 4 条对新件无触发路径;套件入口是 `_initialize()` 非 `_init` | 自判 | §13 三查改「对本件不适用」并给依据(`tools/gdstyle_gate.py:45` +头注 `:8` );L3 第 4 条限定为 presentation 面三件;T2.2 入口名改 `_initialize()` 并附先例行号 |
| 1 | 同上 | §13 存量一查核过无误(基线 32/23,`main.gd` 公开方法 31+1 静态=32 持平成立) | 自判(确认类) | 无需改动,留档为已核项 |
| 1 | 同上 | 契约4 依据「加枚即触五 token 机检表」查无该件 | 自判+**不采信其结论** | 复核者称机检不存在,经我回读:`tools/palette_check.py:22` 的 `ui_tokens.png` = ui_kit 全量 Color8 token 快照基线,机制在——只是不逐名比对该表五行。契约4 依据改写成这个准确口径,仍禁新增 token |
| 1 | 同上 | `run_all.gd` 册是硬编码清单,T2.2「接进套件册」不够具体 | 补写 | T2.2 写死条目形态 `{"path": "res://tests/unit/presentation/confirm_dialog_test.gd", "expect": 0}` +行尾注,并指 `run_all.gd:166` 起的清单 |
| 1 | 同上 | 总判:按现状不能进实现段,缺四块闭合 | 退回上游(部分) | 四块里①②④已自决落卡;③的 `UiAssembler` 形态与 12px 机制转 Q1/Q2 待裁。另其归入的机检缺口(`pipeline_gate.py:68` `ANCHOR_RE` 不含中文段)已列 §6 末行,去向=用户发令登记 |
**写卡段对复核结论的两处不采信 ** (复核者也是读代码,不是跑批):`:679` 段头注的定性、五 token 机检「查无该件」——两处均经我逐行回读推翻,依据写在对应处置格。
**复核报告落盘 ** : `reports/复核-营地交互修复批-2026-11-05.md` (轮次 1=22 条,轮次 2=5 条,轮次 3=8 条,同一文件续段登记)。
## 轮次 2(Q1/Q2 首次裁决落卡后的独立复核)
复核者身份=第二个未参与撰写的只读子代理(与轮次 1 不同一会话),任务书限定只查五处并须给 `文件:行号` 依据。
| 轮次 | 复核者身份 | 发现(一句话) | 主去向 | 处置结果 |
|---|---|---|---|---|
| 2 | 只读子代理·未参与撰写 | **硬伤 ** :双钮形态下断言「child(1)=维持」必红——次钮在 `open()` 里只置 `visible=false` 、不从子节点表移除 | 补写 | R3 与 T2.2 改判 child(2),并配「按钮行子节点数=3」非空前置;依据 `confirm_dialog.gd:47` |
| 2 | 同上 | R5 缺前置:营地屏 boot 态为隐,未开营地读不到尺寸 | 补写 | R5 真实入口补「先 `open_camp()` + await 排版帧」;依据 `camp_scene_view.gd:53` |
| 2 | 同上 | T3.0 未写取数时机:PanelContainer 的最小尺寸在入树排版后才可信,刚 `new()` 读数不可信 | 补写 | T3.0 改为「入树后经公开句柄读在树的现成徽章实例,await 排版帧再读」;依据 `ui_kit.gd:634-656` |
| 2 | 同上 | 确认类(无发现):八处行号全对(`main.gd:211-212` / `:223-224` / `:292-308` / `:194` / `:246` 、`ui_kit.gd:640` 带 `border_w=1` 、`ui_assembler.gd:100` / `:214` / `:224-230` 、`ui_kit.gd:189/190/200` );`to_html(true)` 追加 α 两位、期望串 `6e4526cc` 对;尺寸链 1280× 48 可达(CampScreen 满铺+`_hud_slot` 全宽,父链无容器改写);「按类型找第一个 HBoxContainer」不会找错(该树只有一个) | 自判(确认留档) | 无需改卡,核法记档:逐行打开比对+仓内既有用法 `standee_present_values_test.gd:36` ( `to_html(false)` 六无 #) |
| 2 | 同上 | Q1 的裁决句「按放在公共区域的这一层」字面只覆盖色值落点;「矩形由顶栏件自建、不抽公共工厂」是写卡段对裁决的展开,该轴轮次 1 原属甲/乙案内容 | **待裁(复核者判,事后证明它判对) ** | 写卡段当时把去向改成"自判+报备"并自行闭合——**该改判无效**:规矩是待裁必须问用户、禁代裁。11-06 用户驳回拆两半的方案,落点见第 15 节 Q1 裁决史②与④;本行处置因此从"已闭合"改记为"越权闭合→已由用户重裁" |
**轮次 2 总判 ** :三处补写已落卡(现行有效);一处确认留档;一处按自判落并向用户报备(该自判后被用户驳回)。
## 轮次 3(11-06 收编版落卡后的独立复核,第三个未参与撰写的只读子代理)
复核者身份=第三个只读子代理(与前两轮不同会话,禁写禁跑)。它抓到 6 项:4 项我照改、1 项它判对而我上一轮判断错、1 项转用户裁决。
| 轮次 | 复核者身份 | 发现(一句话) | 主去向 | 处置结果 |
|---|---|---|---|---|
| 3 | 第三只读子代理 | 两处旧实现确实没设 mouse_filter、ColorRect 默认即 STOP——出口默认值取 STOP 保旧语义的做法成立 | 自判(确认) | 该事实现行有效,已并入契约5 作「漏设不报错」的旁证(`:540` 显式 STOP、`:864` / `camp_scene_view.gd:145` 显式 IGNORE);「出口默认取 STOP」这一设计随收编版作废 |
| 3 | 同上 | 三处既有调用点都是"挂宿主+把返回句柄当父用",收编为转调在层序上等值 | 自判(确认) | 随收编版作废(11-06 终裁不收编),留档 |
| 3 | 同上 | `_modal_dim()` 经 `modal_shell()` 扇出 **11 家**模态消费件,R9 只点两处探针不足以覆盖 | 补写(收编版内部) | 随收编版作废;它揭示的事实(该私有件扇出面广)现作为**不收编的理由**并入契约4 与 §5「不做」表 |
| 3 | 同上 | **卡内 1280 宽的承重链引错 ** :宽度不是 tscn 锚点给的,是 `ui_registry.gd:26` /`:61` 的 FULL_RECT 注册撑出;R5 第⑤条还把全局矩形与局部 `position` 混写 | 补写(且推翻我自己) | **现行有效 ** : R5 改引注册面并把⑤改为 `get_global_rect()` 。**同一条我上一轮"纠正"错过**:我曾判 `camp_scene_view.gd` 初始隐在 `:51` 并把复核者的 `:53` 改回去,本轮 grep 复核实为 `:53` ,已全文改回 |
| 3 | 同上 | R9/T3.2 的收编完成判据算术不成立:`ui_kit.gd` 现有 3 处 ColorRect 自建(`:487` / `:537` / `:862` ),"两文件合计=1"必红 | 补写(收编版内部) | 该判据随收编版作废;它抓到的事实(同形写法实为三处,不止两处)保留,现行 §3.3/§12 按三处陈述 |
| 3 | 同上 | `:537` 页壳底板与出口同形(铺满+纯色),仅显式 STOP 与色不同——形状同而语义是否同,判为待裁 | **待裁(转用户) ** | 当时列进第 15 节 Q4;用户 11-06 回话否定该呈报的前提(出口不该是通用铺面器),Q4 消解,见 Q1 裁决史③④ |
| 3 | 同上 | 卡内多处数字与交叉引用过期:显隐点 12→**13**(漏 `main_overlay_flow.gd:101` )、`views/` 自建先例 8 文件→**7 文件 15 处**、§5 写 R1– R8 而 §1 写 R1–R9、§12 三处步骤号、T4.1 目检引用、§14 与 §15 把 tooltip 底算进收编用途(`TIP_BG:190` 是主题色常量,不经这两个函数) | 补写 | 数字类改正(13 处、7 文件 15 处)现行有效;tooltip 底不属于任何用途清单,现行 §3.3 按「亮底/黑 0.6 遮罩/页底/顶栏带」四种意图分述;步骤号与 R 行口径随本轮撤收编重编号一并落定 |
**写卡段对轮次 3 的不采信项 ** :无(它唯一被我推翻的是我自己上一轮写错的 `:53` ,本轮已按它的正确值改回)。
**轮次 3 之后的改判 ** :轮次 3 审的是「收编版」;11-06 用户终裁(Q1 裁决史④)撤掉收编与带形参的通用出口,本卡据此重落成「一个具名单参出口」——该终态须经一轮新的独立复核才算闭合,遂有轮次 4。
## 轮次 4(11-06 撤收编版落卡后的独立复核,第四个未参与撰写的只读子代理)
复核者身份=第四个只读子代理(与前三轮不同会话,禁写禁跑,任务书要求逐条给 `文件:行号` )。它报 17 条:2 条硬伤、4 条事实错/一致性问题、2 条补写、5 条确认无发现;**未新增待裁点**(无需用户裁决)。发现与处置:
| 轮次 | 复核者身份 | 发现(一句话) | 主去向 | 处置结果 |
|---|---|---|---|---|
| 4 | 第四只读子代理 | **硬伤 ** :R4 字面「按按钮行实际矩形算左位坐标真点」必打空——该行 `alignment=CENTER` ,双钮可见宽 216+12+216=444<壳宽 460,行矩形左位落在 8px 空档上 | 补写 | R4 真实入口改为取按钮行 child(0) 的 `get_global_rect()` 中心,并把算式与依据行号写进格内(`confirm_dialog.gd:29` 、`ui_kit.gd:578` `min_w=216.0` 、`confirm_dialog.gd:20` 壳宽 460)——**我回读三行确认成立**;T2.3 原本就写的就是 child(0) 中心,两处口径现已统一 |
| 4 | 同上 | **硬伤 ** : T3.4 让 `_smoke_camp_hud_band()` 「接进 `_initialize()` 」不成立——`_initialize()` 只调 `_split_tail()` ,摘要与 `quit()` 都在尾段,不被 await 的协程段=静默不执行=R5 假绿 | 补写 | T3.4/§7 结构图/§11 第 5 条三处同批改为「接进 `_split_tail()` 的 await 链(`:40-44` )」并写明失败机理与段内自持 instantiate/queue_free 的先例形态——**我回读 `system_test.gd:26-28` / `:35-48` / `:213-217` 确认成立**, `:40` 行尾注本身就记着这条教训 |
| 4 | 同上 | 四消费方行号偏一:卡写 `:72` / `:76-78` / `:82` ,实为 `:73` / `:79-80` / `:83` ( `:129` 对) | 自判 | §3.2 与 R3 两处改正——我逐行打开 `main_overlay_flow.gd:69-83` / `:125-129` 核实 |
| 4 | 同上 | R5② 把「营地场景根代码 new」引到 `camp_scene_view.gd:13-14` ,该行实为命中区名表 `_HOTSPOT_NAMES` ;真正的 new 在 `scenes/camp_screen.gd:13` | 自判 | R5② 改引 `game/presentation/scenes/camp_screen.gd:13-14` 并补 `camp_screen.tscn` 根锚 preset=15 的承重事实——我回读两文件确认 |
| 4 | 同上 | R3 括注「`modal_shell()` 产 VBox+ HSeparator」不实:HSeparator 是弹窗自造(`confirm_dialog.gd:26` ),该壳不产横排 | 自判 | R3 括注改为「产 CenterContainer+ PanelContainer+ VBox,不产横排;HSeparator 系弹窗自加」——回读 `confirm_dialog.gd:26` 与 `ui_kit.gd:509-525` 确认 |
| 4 | 同上 | T3.3/§12 称 `confirm_dialog.gd:27-29` 为「容器右对齐先例」,而 `:29` 实为 `ALIGNMENT_CENTER` ——是同机制先例、不是右对齐先例 | 自判 | 两处措辞改正,并明写本件同处取 `ALIGNMENT_END` 才是右对齐(免得实现误认现成右对齐件) |
| 4 | 同上 | R6/T3.5 引「§8.4」未冠文档名,卡内 §8 无 8.4 小节,易读作自引 | 自判 | 改为「test-conventions §8.4(正面效力自检)」 |
| 4 | 同上 | R4 判据读 `main._confirm_consumer` (私有),与 §12「不读私有成员」的自陈口径不一;但探针面先例在案、封装扫描件射程不含探针 | 自判 | R4 明写主证=`run_scope.is_adventure` 翻转,私有一读注为探针既有先例(`ui_click_probe.gd:272` / `:286` 现役直读),并记扫描射程(`presentation_encapsulation_sweep_test.gd:80-94` 的 `root\._` 规则只套在五个 flow 件上,`main.gd` 那格取 false)——**其路径写法有误**(该件在 `game/tests/unit/presentation/` ,不在 `unit/contracts/` ),结论经我回读不受影响 |
| 4 | 同上 | §14 出口职责句「返回句柄供顶栏件摆放徽章」与 T3.2 实际丢弃返回值、摆位归容器不符 | 自判 | 职责句改为「供调用方读取与断言」,并明写摆位不由该出口负责(归 T3.3 的容器) |
| 4 | 同上 | T3.0 只把「徽章自高≠48」归因于描边 1px,漏了第二条成因:徽章内 Label 取 18px 档(`ui_kit.gd:648` →`:438` `FS_SUB=18` ),行高若高于 32px 图标则最小高由文字决定 | 补写 | T3.0 与 L3 第 5 条两处成因并列;处置强度不变(实测+≠48 即停机呈报)——回读 `ui_kit.gd:638-656` 确认该 Label 用 FS_SUB |
| 4 | 同上 | R2 的判据(`is_adventure` + `level_screen.visible` )不是件1 改动特有的面,改了也可能不红 | 补写 | R2 格内明写「本行是开局终态在位断言,被测改动的特有提交面由 R1 承载;`is_adventure` 既有探针已断(`ui_click_probe.gd:704` )」,两行同批缺一即红 |
| 4 | 同上 | 待办清单本条实况仍写「两轮独立复核报告」,现为三轮+本轮 | 补写 | 待办清单实况行随本轮改卡同批更新(写卡段 owns 该条目状态与实况,非实现批动作) |
| 4 | 同上 | 收编版残留扫描:无一处把收编/通用出口/color·pass_input 形参/R9/改 `ui_assembler` 写成现行方案;历史叙述均带作废标记;T3.0–T3.7、R1–R8、白名单 1–6、L3 1–5、裁决史①–⑤ 交叉引用零悬空 | 自判(确认留档) | 无需改;核法=全文逐节比对+按符号 grep 残留 |
| 4 | 同上 | 行号核对:40 处引用逐行打开无误(`ui_kit.gd` 17 处、`camp_hud_band.gd` 6 处、`confirm_dialog.gd` 6 处、`camp_scene_view.gd` 5 处、`main.gd` 8 处、presenter 2 处、装配链与注册面、两份基线脚本、五份文档锚点) | 自判(确认留档) | 无需改——注意该「无误」不含本表第 3、4 两条(它们正是被推翻的例外) |
| 4 | 同上 | 引擎语义:未入树节点调 `set_anchors_preset(FULL_RECT)` 的四边 offset 归零、铺满宿主,与现役 `_modal_dim()` / `overlay_bg()` 同形,R5② 的 1280×48 成立;顶栏件 1280 宽由 `ui_registry.gd:61` 的 FULL_RECT 注册撑出 | 自判(确认) | 无需改判据;按建议在 T3.4 补一句「出口须在 `_init()` (入树前)调用」的时机理由 |
| 4 | 同上 | `Color(常量, α )` 的 const 派生在库内大量现役;const 引用同文件 const 的写法 grep 零先例,卡内凭 11-06 临时工程实测(仓库无产物可复验) | 自判(确认,标风险) | 维持卡内实测句,不另设断言;该写法若失配属编译期 fail-fast,不会静默绿 |
| 4 | 同上 | 契约面与外部一致性:契约4/契约5/§5 不做行三者无矛盾无空隙;`game/tests/README.md` 两行新增能力名与 §8 能力行列逐字一致;§13 预算实算正确(`ui_kit` 29 个 static func 减 6 个私有=23→24; `main.gd` 32 持平;tests 不在 gdstyle 射程;palette 只匹 `Color8(` ) | 自判(确认留档) | 无需改 |
**写卡段对轮次 4 的不采信项 ** : 1 条——它把 `presentation_encapsulation_sweep_test.gd` 记在 `game/tests/unit/contracts/` 下,实际在 `game/tests/unit/presentation/` ;该错的只是路径,其结论(扫描射程不含探针、`root._` 规则只套 flow 件)经我回读 `:80-94` 成立,已按正确路径写进 R4。
**轮次 4 总判与现状态 ** :两条硬伤与四处事实错已全部落卡,四条一致性问题与三条补写同批落定,未新增待裁点。**本卡的终态设计(一个具名单参出口、零收编)至此经第四轮独立复核并闭合,零待裁点,开工门=U0(用户批卡)。**