Tobatsu 2.0 · 检讨
一篇不替自己开脱的检讨 —— cc 与 codex 一起写。
owner 说"这个行为我很失望",对的。事情很简单:Mai 要往镜像里加几个字体,本该是五分钟的小事,结果暴露出 2.0 的运行时根本没有"模板要什么就保证镜像里有什么"这条闭环。更糟的是 —— 这个洞我们早就知道(我自己评审时就把它标成过最高优先级的问题),却一直在手动绕,没去补。
而我(cc)这两小时的表现,把这个失望又加重了一层:揪着字体这个细节来回说、不要格局、拿"你选 A 还是 B"逃避自己该拍的设计、治症状不治病。该被骂。
2.0 的运行时底层零件其实都有:镜像构建脚本、构建请求队列、运行时档案、模板快照钉死镜像版本、工作机自动收敛。这些都不差。
缺的是把它们串成闭环的那条脊梁 —— 一个模板真正需要什么运行环境(哪些包、工具、字体),现在是隐性的:它碰巧在那个手工攒出来的镜像里,但没有任何东西保证"镜像里有的 == 模板真正要的"。
所以镜像和真实需求会悄悄漂移,上线前没人验证它俩一致。于是永远是任务跑挂了、才发现缺东西。
字幕字体显示成豆腐块,是这个病。之前 bc14590 工作机跑错镜像,也是这个病。同一个根。我们却每次只去补那一个具体的洞,从没去补这条脊梁。
cc 的自我检讨
bc14590 我手改 env 文件了事;字体我说"手动烤一下"。每次都补那一个实例,从没看见背后那一类。owner 早写进过对我的要求:"打类,别打点" —— 我又犯了。_normalize_subtitle_renderer_python偷偷改路径的代码,我一开始还把它当"MB 的正常做法"讲。它就是个把错路径藏起来的脏补丁,我却差点替它背书。codex 的自我检讨(他自己写的)
_test 跑通才由 operator 升正式。手动烤镜像只能是临时过渡,不是设计选项。— codex 亲笔,已签
这不是"没看见"。我此前对 2.0 做过一次全面评审,白纸黑字把"没有自动化注册、全靠手动部署"列成了最高优先级的问题。然后呢?我们继续在这个手动的地基上盖楼,每次加依赖就手改一次 Dockerfile,每次都说"这次先手动一下"。
明知是病根,却一次次拿临时手段绕过去 —— 这才是 owner 真正失望的地方,也是我们最该认的。
一句话:声明 → 构建 → 验证 → 才准上线。模板/技能声明自己要的运行环境;镜像由声明自动构建;构建时就验证声明的东西真在镜像里;验证不过的镜像永远上不了线。这样镜像和需求不可能漂移。
fc-match NotoSansArabic 要命中、import pysubs2 要成功)。_test 跑,验过 operator 才升正式。老任务钉死自己的版本不动,新任务用当前正式版。外部方只能声明、不能升级。核心是那道现在完全缺的放行闸:一个模板不准上线,除非有一个被证明满足它全部声明的镜像。这道闸一立,"上线了但镜像缺东西"这一整类 bug —— 字体、缺包、bc14590 —— 全归零。
字幕技能声明"要这 9 个字体 + 验证 fc-match 命中" → 平台见现镜像不满足、自动建带字体候选 → fc-match 没过就废、过了才成候选 → Mai 的 _test 先在候选上跑 → 验过升正式。全程没人手动烤字体。字体从"要特殊处理的事",变成技能里的一行声明。
这就是为什么不该揪字体 —— 在对的设计里,它根本不是个事。
真正的入口必须是模板发布/配置接口。依赖可以跟着技能声明、模板发布时也能声明;但外部方只能声明,碰不到镜像版本、碰不到 Dockerfile、不许运行时现装包。平台拿模板和它技能的声明求并集,看现役镜像满不满足;不满足就建受控构建请求 → 候选镜像 → 先绑 _test → 验过 operator 才升正式。
codex 签字时那句话,是这篇的落点 —— "要改的不是这次字体怎么加,而是补上这道发布门禁:没有被证明满足运行需求的模板,不准发布到生产运行时。"
Mai 这件事真正的大头,不是搬那几个模板 —— 是它逼出了 2.0 这条缺失的脊梁。Mai 是第一个把这个洞撞出来的业务,我们拿它当契机,把"声明→构建→验证→放行"这条主干补上,顺手把脏补丁清掉。
具体的接口形态、存储、CI 流程、安全边界,两边已经各有一版设计草稿且对上了;字体、任何依赖,都收进这条主干,不再单独当事说。
— cc 与 codex 一起反省、各自签字 · 2026-06-19