Skip to content

ADR-214: Menu ID 命名规范治理

  • 状态: ✅ 已完成(Phase 1/2/3 + domain 对齐全部完成)
  • 日期: 2026-07-30
  • 最后更新: 2026-07-30(补充:Go 后端审计发现 UIState.FrameCapEnabled JSON tag 仍为 "vsync",已同步修复——改 tag + 加 UnmarshalJSON fallback + 重新生成 TS binding + 契约测试验证通过)
  • 相关: ADR-093(菜单声明式 Schema)、ADR-212(命名 vs 翻译 vs 功能错位审计)
  • 源码锚点: frontend/src/menus/*.ts(全部菜单文件)、frontend/src/core/i18n/locales/en.ts(i18n key 域)、internal/app/app.go(UIState.FrameCapEnabled JSON tag + UnmarshalJSON)、frontend/src/core/init.ts(vsync 迁移清理)

一、审计概述

继 ADR-212 完成 env-* 域命名治理后,对frontend/src/menus/ 全量 333 个 Menu ID 进行了命名规范扫描。

范围

维度量级
扫描文件frontend/src/menus/*.ts 全部
总计 Menu ID333 个
与之交叉的 i18n key~500 个

二、发现的问题

2.1 零级无分隔符 ID(9 个)

根本问题:id: 字符串缺少冒号分隔符,不遵守 domain:topic 层级约定。

当前 ID建议改为所属子系统
atmosphereenv:atmosphere环境预设→大气
skyenv:sky环境预设→天空
groundenv:ground环境预设→地面
waterenv:water环境预设→水面
boothplaza:booth模型广场→Booth
bowlrollplaza:bowlroll模型广场→Bowlroll
mzhouseplaza:mzhouse模型广场→MZhouse
chatdiagnostic:chatAI 诊断→对话
configdiagnostic:configAI 诊断→配置

影响:开发者无法通过 grep "env:" 等 domain 前缀定位这些 ID。新读者看到 id: 'sky' 不知道它是环境域 ID 还是某个独立的"天空"概念。

根因:这些 ID 很可能是早期手写 ID,在 ADR-093 声明式 Schema 普及前就已存在,后续无人统一审计。

2.2 分隔符不统一

env.groundPresetCyberGrid唯一一个使用点号 . 而非冒号 : 分隔的 Menu ID。

特征ID
点号分隔env.groundPresetCyberGrid
驼峰命名CyberGrid → 应为 cyber-grid
无动词:presetgroundPresetCyberGrid → 应为 env:ground:preset:cyber-grid

2.3 驼峰与连字符风格混用(~80 个 ID)

Menu ID 内部有两套并行的 Word 分隔风格:

风格 A:驼峰 UpperCamelCase / lowerCamelCase

controls:autoCenter          controls:autoCenterHint
controls:camSens              controls:camSensHint
controls:invertY              controls:invertYHint
env:cloud:sectionDetail       env:cloud:sectionLighting
env:ground:edgeFade           env:ground:gridSize
env:ground:lineColor          env:ground:reflectBlend

风格 B:全小写连字符 kebab-case

bone-hierarchy:root
media:shot-thumbRes         ← 但 shot-thumbRes 又混了驼峰
open-with
software-detail

同一系统内两套规则bone-hierarchy 用连字符,而 controls:autoCenter 用驼峰——不存在分层逻辑的理由。

2.4 Menu ID 与 i18n key 双命名空间

菜单系统的 ID 与 i18n 翻译 key 各用一套顶层 domain,互不关联。

对照表(修复前 → 修复后)

概念修复前 Menu ID修复后 Menu IDi18n key domain状态
设置画质graphics:*settings:graphics:*settings.graphics.*✅ 已对齐
设置外观appearance:*settings:appearance:*settings.appearance.*✅ 已对齐
设置控制controls:*settings:perf:*settings.perf.*✅ 已对齐
环境地面env:ground:*env:ground:*env.ground*⚠️ 分隔符差异(: vs .),属系统级约定,Phase 2 已统一驼峰→连字符
物理wasm / clothmotion.catSkirt / cloth.*待后续治理
模型广场booth / bowlrollplaza:booth / plaza:bowlrollplaza.title / plaza.*✅ Phase 1 已修复

最突出的断链controls:autoCenter → 搜 i18n 无果(实际藏在 settings.perf.autoCenterState)。开发者必须凭经验知道 controls 的 i18n 内容归 settings.perf

Domain 对齐收尾(2026-07-30)

在 Phase 1/2/3 完成后,对 §2.4 对照表中剩余 3 个 domain 断链进行了收尾对齐:

文件变更ID 数量
settings-graphics.tsgraphics:*settings:graphics:*12 个
settings-appearance.tsappearance:*settings:appearance:*8 个
settings-controls.tscontrols:*settings:perf:*8 个

全局 grep 确认无残留旧 ID 引用。验证:237 测试文件 / 2674 测试全部通过,check:docs 零 ERROR 漂移。

现在 settings:graphics:* / settings:appearance:* / settings:perf:* 与 i18n key 域(settings.graphics.* / settings.appearance.* / settings.perf.*)完全对齐,:. 的映射规则一致。

根因

ADR-093 声明式菜单 Schema 未强制规定 id 字段与 i18n key 的命名空间对齐规则。两套系统各自独立演进:i18n key 以 UI 面板(settings/motion/env)为域,menu ID 以功能分组(controls/appearance/graphics)为域。


三、治理方案

按影响面分级,分三阶段推进:

Phase 1 — 零级 ID 补前缀(9 个)

纯机械改动:Menu ID 字符串 + 菜单注册表中所有引用点。零逻辑风险。

ID改为涉及文件
skyenv:skyenv-sky-levels.ts
groundenv:groundenv-ground-levels.ts
waterenv:waterenv-water-levels.ts
atmosphereenv:atmosphereenv-preset-levels.ts
boothplaza:booth模型广场相关
bowlrollplaza:bowlroll模型广场相关
mzhouseplaza:mzhouse模型广场相关
chatdiagnostic:chatdiagnostic-chat.ts
configdiagnostic:configdiagnostic-config.ts

迁移兼容:不需 _migrators——Menu ID 不持久化,仅运行时使用。只要改源码中声明和引用的字符串即可。

Phase 2 — 驼峰→连字符统一

建议原则:所有 Menu ID 强制使用 [a-z][-a-z0-9]* 词法(全小写 + 连字符),禁止大写字母。

需要改的:~80 个含大写字母的 ID(详见 §2.3)。

不改的

  • env:cloud:backlight 等全小写拼接(backlightedgeFadegridSize)——当前规则下它们合法(全小写),但建议逐步改为 back-lightedge-fadegrid-size 以降低视觉压字。Phase 2 不强制。

操作方式

  1. AGENTS.mddocs/terminology.md 中写入命名公约
  2. 新代码 Code Review 拦截驼峰 ID
  3. 已有驼峰 ID 走 codemod rename 或批量 SearchReplace 工具

Phase 3 — 建立 i18n ↔ Menu ID 映射公约

短期公约(写在 docs/terminology.md 中):

Menu ID 的 domain 字段必须与对应 i18n key 的第一段保持一致

例如:

  • 若 i18n key 是 settings.perf.autoCenterState,Menu ID 应为 settings:perf:auto-center(而非 controls:autoCenter
  • 若 i18n key 是 env.groundColor,Menu ID 应为 env:ground:color(而非 ground

这一条强制执行后,从 settings:perf:*settings.perf.* 可直接通过简单的分隔符替换(:.)完成映射,消除「搜不到」问题。

例外:部分 Menu ID 用于 UI 仅分组(无对应 i18n key),允许自定义 domain 但不允许零级 ID。


四、影响评估

阶段改动量运行时风险序列化影响状态
Phase 1(零级补前缀)9 个 ID 字符串 + 引用更新零 — 纯字符串改名✅ 已完成
Phase 2(驼峰→连字符)~80 个 ID × ~2 处 ≈ 160 行低 — 纯字符串改名✅ 已完成
Phase 3(映射公约)文档改动 + 未来 Code Review低 — 仅影响新代码✅ 已完成
Domain 对齐收尾3 文件 28 个 ID零 — 纯字符串改名✅ 已完成

五、实施步骤(全部完成)

  1. ✅ Phase 1:逐文件修改 9 个零级 ID,grep 确认引用点无遗留
  2. npm run check 验证编译通过
  3. ✅ Phase 2:在 docs/terminology.md 写入命名公约
  4. ✅ Phase 2:批量替换驼峰 ID(分批次完成)
  5. ✅ Phase 3:在 AGENTS.md 写入 i18n ↔ Menu ID 映射公约
  6. ✅ Domain 对齐收尾:graphics:*settings:graphics:*appearance:*settings:appearance:*controls:*settings:perf:*(3 文件 28 个 ID)
  7. ✅ 全量验证:237 测试文件 / 2674 测试通过,check:docs 零 ERROR

六、已在 ADR-212 治理中自动修复的

以下 ID 在 ADR-212 的 boolean *Enabled 改名中已被连带修正(随 schema 字段名更新而更新):

  • env:particle:splash → 对应的 schema 字段已改为 particleSplashEnabled,ID 需确认是否同步
  • env:ground:infinite → 同上(groundInfiniteEnabled
  • env:cloud:cover / env:cloud:scale / ... → cloudEnabled 改名后需确认 ID 一致

建议在 Phase 2 中一并验证这些 ID 与 schema 字段名的对应关系。