Appearance
第九章 · 审计之光
背景:后端多接口已实现却未接入前端
过程:接入多接口、标签、收藏与详情面板
地图质量委员会成立后的第三天,桌面壳收到了一封信。
信是从 App.d.ts 投递过来的——那个 318 行的 TypeScript 声明文件,Wails 自动生成的客户端接口清单。桌面壳从来没认真读过它,它一直以为这份清单只是"已知城邦的目录"。
但今天它读完了。
不是浏览,是逐行读。
然后它发现自己不认识自己的联邦。
"有四十八个海关口岸。"桌面壳对 MenuStack 说,"我每天用的不到四十个。有八个口岸从来没开过——但海关大楼建得比谁都完整。"
"哪八个?"
"GetModelMeta——单查模型信息。GetThumbnail——单查缩略图。SelectPMXFile——选 PMX 文件。SelectVMDMotion——选 VMD 文件。StopFileServer——停港口。"
"这不奇怪。"MenuStack 说,"集体版覆盖了单条版,文件选择被库浏览替代了。停港口?你根本不需要停港口。"
"那这三条呢?"桌面壳调出三份档案。
档案 1:OpenInBlender
"OpenInBlender(modelPath)——exec.Command(blenderPath, modelPath).Start()。完整实现了。Blender 自动检测,6 个 Windows 安装路径,PATH 环境变量,全写了。status.md 标记为 [x] 已完成。"
它停顿了一下。
"但用户没有按钮可以点。"
MenuStack 沉默。议会很少在数字上犯错,但它此刻无法否认:一个完整的城邦接口,在联邦地图上标注为"已通商",实际没有任何一条路通向它。
"它怎么被调用的?"
"不调用。从没被调用过。library.ts 的 import 列表里没有它。main.ts 没有。settings.ts 没有。没有任何前端文件 import 它。"
"那它的 [x] 怎么来的?"
"Go 端写了,测试过了,wails dev 编译过了——它就以为自己是完成的了。"桌面壳说,"像一座桥,两岸引桥都修好了,但桥面没铺。从卫星图上看,这座桥存在。从地面上走——不存在。"
档案 2:SetBlenderPath
"配套的配置接口。Blender 路径持久化到 config.json。设置面板有 MMD 路径配置,有外部库管理,有清除缓存——就是没有 Blender 路径。"
"那用户怎么配 Blender?"
"没办法。要么自动检测成功,要么就别用。"
档案 3:RenameExternalPath
"外部库重命名。ExternalPaths[i].Name 可修改。Go 端完整实现了。但外部库管理 UI 只有添加和删除——没有重命名。"
"所以用户想改一个外部库的显示名……"
"唯一的办法是:删掉,重新添加,取新名字。这不是'功能不存在',是'功能存在但只对直接调 API 的人开放'。"
MenuStack 很久没说话。
"所以你有三个城邦——三座完整的桥——在联邦地图上画了三年,今天才发现从来没人走过。"
"是今天才发现。"桌面壳说。
桌面壳把三份档案铺在终端里,决定不再只是发现,而是修补。
它打开 library.ts,在模型详情页的最底部分隔线下——"📤 导出到 MMD" 的后面——加了一行:
typescript
{ kind: "action", label: "✏️ 在 Blender 中编辑", icon: "edit-3",
target: `detail:blender:${id}`, sublabel: "用 Blender 编辑此模型" },然后在 onItemClick 里加了一个 handler。七行代码。
一座桥通了。
它打开 settings.ts,在系统设置面板里,"📤 检测 MMD 路径" 的下面加了一行:
typescript
{ kind: "action", label: "✏️ 设置 Blender 路径", icon: "edit-3",
target: "set:blenderpath" },一个 handler。同样是 SelectDir + SetBlenderPath。座标模式。
第二座桥通了。
它翻到 renderExternalList——外部库管理的那块 UI。每行只有名字、路径、删除按钮。
它加了一个按钮。✏️。
点击后弹出 prompt("输入新的显示名称:", ep.name),调用 RenameExternalPath(ep.path, newName.trim()),然后 reloadConfig() + renderExternalList()。
第三座桥通了。
三座桥,全部加起来不到三十行代码。
"你早就该查那份清单的。"MenuStack 说。
"我一直在忙新功能。"桌面壳说,"忙到忘了检查地图上哪些路是真的。四十三个口岸,我每天走三十五个,以为剩下八个是备用。结果是三个是死的,五个是确实备用的。"
"那你怎么区分'备用'和'死'?"
"看有没有 import。GetModelMeta 单条版——没人 import,但 GetModelMetaBatch 内部调它,所以它是活路,只是名字起错了,不该暴露成海关口岸。StopFileServer——注释写了'前端暂不需要',是活路,只是没人走。"
"那 OpenInBlender 呢?"
"import 搜索为零。调用栈搜索为零。status.md 说[x],代码里是[]。"
MenuStack 没有追问。它知道桌面壳此刻在为一个看起来很小的发现而震动——不是因为技术难度,而是因为这个发现本身暴露了一个系统性的盲点。
"所以你下一步要干什么?"
"审计。不是审计代码,是审计地图。我要建一条流水线——每次编译后自动比对 App.d.ts 的声明和 src/*.ts 的 import。不匹配的标记为'地图上存在但路上没人'。"
那天结束时,桌面壳把审计结果写在联邦地图的边角上。
不是修正声明——不是"旧地图错了"那种。这次是补遗。
新增通商口岸(已建成但未开放,现均已启用):
- OpenInBlender —— Blender 编辑接口
- SetBlenderPath —— Blender 路径配置
- RenameExternalPath —— 外部库重命名
"三座桥。"桌面壳说。"三座完整的桥,在地图上画了三年,今天才通车。"
"这不是收编。"MenuStack 说。
"是普查。联邦成立以来第一次认真核对——地图上画的路,和地上真有的路,是不是一回事。普查不增加领土,普查增加的是对领土的了解。"
"普查也是绘图师的工作?"
"是绘图师的基本功。画了三年地图,今天才发现——地图和领土,对不上。"
教训:存在不等于可达,完成不等于通航。