静默切换运行时算治理违规:`render_runtime` 是怎么被锁住的

2026-08-09

有人问过这么一个情况:跟 agent 商量好这条片子用 HyperFrames 做,中途没打招呼,交上来的成片却是另一条渲染路径出的。这算 bug 吗?

按 OpenMontage 自己的说法,这不归在 bug 里,它有个专门的名字:治理违规

先看写在 README 里的那一句

README 的 Composition & Rendering 表格下面紧跟着一句话,原文是:

Runtime is chosen at proposal (render_runtime) and locked through edit_decisions. Silent swaps between runtimes are a governance violation — see skills/core/hyperframes.md.

这一句里有三个可以分别核对的东西。

第一,选择发生在提案阶段,字段名叫 render_runtime。也就是说运行时不是执行时才顺手决定的实现细节,它属于要拿给你看、要你点头的那一层。

第二,锁定靠的是 edit_decisions。选完之后这个值被记进决策记录里,后续要改就是改一条已经登记过的决策,而不是改一个临时变量。

第三,README 把完整决策矩阵指向了 skills/core/hyperframes.md。这个文件我们没有读过,这里只能说明 README 把它标为决策矩阵所在,里面具体怎么分岔,本文不描述。

被锁住的到底是哪两个东西

README 的这张表一共三行,与本篇直接相关的是前两行(provider 的完整清单本批另有专篇在讲,这里不搬):

EngineTypeREADME 的描述要点
RemotionLocal (Node.js)基于 React 的程序化视频,弹簧动画图片场景、章节标题、逐词字幕、场景转场等
HyperFramesLocal (Node.js ≥ 22)HTML/CSS/GSAP 程序化视频,动态排版、自定义动态图形、website-to-video 工作流等
FFmpegLocal核心视频装配、编码、字幕烧入、音频复用、调色

需要说清楚的是,上面这一列是 README 自己的措辞,不是我们的评价,我们没有用任何一套运行时渲染过东西。

README 给的默认分工也是原文口径:Remotion 是数据驱动讲解片以及任何使用既有 React 场景栈的默认;HyperFrames 是动态图形密集、天然适合用 HTML + GSAP 表达的需求的默认,包括 character-animation 流水线的 SVG/GSAP 骨架输出。

另外 README 在 Remotion 那一行里还写了一条:当没有配置任何视频生成 provider 时,agent 生成静态图,由 Remotion 把它们变成完全动起来的视频。零密钥这条路上,落点是明确的。

至于 FFmpeg 那一行,它的描述是装配、编码、烧字幕、复用音频、调色——和前两行不是同一类角色。README 流程图里渲染那一步写的是 Render (Remotion or FFmpeg),后面跟着一句 “composition engine matched to visual grammar”。

落到具体数值:两处 Node 版本对不上

这条规则真正值得记的硬锚点在表格的 Type 一栏。

Remotion 标的是 “Local (Node.js)“,没写版本下限;HyperFrames 标的是 “Local (Node.js ≥ 22)“,写了 22。而 README 的 Prerequisites 那节,给出的要求是 Node.js 18+

两处都是 README 自己的文本,数字不一致。这里只陈述差异:按最低前置条件装出来的环境,和 HyperFrames 那一行标注的下限不是同一个数。我们不推断哪个是准的、也不断言 HyperFrames 在 Node 18 上就一定跑不起来——我们没有装过、没有跑过。

但这个差异对读者是有用的:既然运行时是在提案阶段锁定的,那把这两个数字摆到桌面上的时机,最好在锁定之前,而不是渲染报错之后。

另一处数值:换运行时不会改变输出规格

仓库根目录 config.yamloutput 段是这样:

output:
  default_format: mp4
  default_codec: libx264
  default_audio_codec: aac
  default_resolution: "1920x1080"
  default_fps: 30
  default_crf: 23

六个默认值:mp4 容器、libx264 视频编码、aac 音频编码、1920x1080、30 fps、CRF 23。它们躺在全局配置里,跟你选哪套运行时无关。

这一点值得单独说,因为它正好堵住一个很自然的念头:反正最后都是 1080p、30 帧、CRF 23 的 mp4,中途换个引擎有什么区别?规格确实一样,但 README 那句 “composition engine matched to visual grammar” 说的是另一件事——运行时决定的是画面怎么被造出来,不是它被压成什么样。规格相同不构成可以静默替换的理由,这条规则拦的恰好是这种想法。

为什么它被写成「违规」而不是「建议」

AGENT_GUIDE.md 是一份 714 行的 agent 契约。我们实读了它全部 46 个标题,里面有三处和这条规则互相印证。

其一,Decision Communication Contract 下面有一个小节,标题是 “Present Both Composition Runtimes (HARD RULE)“。标题里自带 HARD RULE 这三个字,说明「两套运行时都要呈现给用户」不是可选项。另外 Mandatory Preflight 那一节下面也单挂了一个小节,标题是 “Composition Runtimes (Inside video_compose)“——运行时这件事在强制 preflight 里同样占了一格。这两节的正文我们没有读过,不展开细则。

其二,全文最后一节 What Not To Do 里有一条原文:不要在没有事先告知用户的情况下更换 provider、模型或渲染路径,改动重大时还要拿到批准。渲染路径和 provider、模型被并列写在同一条里。

其三,同一节还有一条:不要隐藏降级路径,替换和被阻断的选项要明确记录。也就是说,即便真的换了,契约要求的是把它记下来、说出来,而不是让它悄悄发生。

再往上一层,把 Decision Communication Contract 的小节标题按目录顺序列全,一共八个:Announce Before Execution、Ask Before Major Changes、Re-log Changed Decisions (Binding)、Present Both Composition Runtimes (HARD RULE)、Composition Authoring Mode — Templated vs Atelier、Escalate Blockers Explicitly、Recommendation Style、No Unilateral Substitutions。光看标题就能读出这份契约对「改主意」的态度:可以改,但要在执行前说明、要重新登记、不许单方面替换。这八节的正文我们同样没有读过,这里只引标题。

在流程上,这条规则的位置也是明确的。README 流程图里合成前有一道校验闸,原文列了三项:delivery promise、slideshow risk、renderer governance。第三项就是渲染器治理。这三个词是流程图原文,lib/ 下对应的治理模块另有专篇在讲,它们具体怎么判定,本文不描述。

这条「锁」的真实强度在哪里

必须把边界说清楚:AGENT_GUIDE.md 是写给模型看的文本,它写了 MUST,不等于模型一定会照做。

这一点在 OpenMontage 身上尤其明显,因为它的核心主张就是 There is no code orchestrator. Your AI coding assistant IS the orchestrator. 规则的执行者,正是被规则约束的那个对象。所以 render_runtime 的「锁」,靠的不是一段代码在运行时拦你,而是一份文本约束加上流程里的人工闸。

真正稳的那一环是后者。README 流程图里 agent 把方案交给你批准的那一步,原文写的是 you stay in control at every creative decision。同时 README 说每个决策都会被记录,含考虑过的备选项、置信度分数和每次选择背后的理由。所以运行时被换掉这件事,如果发生了,能追的地方是决策记录,不是猜。

落到动作上

提案阶段:把 render_runtime 问出来,并且要求两套运行时都摆给你看——这条有 HARD RULE 那个标题撑腰,不算过分要求。同时对一下自己机器上的 Node 版本和上面那两个数字。

preflight 阶段:README 建议查真实能力边界的办法不是翻文档,是问 registry:

python -c "from tools.tool_registry import registry; import json; registry.discover(); print(json.dumps(registry.provider_menu(), indent=2))"
python -c "from tools.tool_registry import registry; import json; registry.discover(); print(json.dumps(registry.support_envelope(), indent=2))"

AGENT_GUIDE.md 在 Mandatory Preflight 一节里给这两条命令配了注释:前者是分能力分组的完整菜单,后者是每个工具的完整契约原始包络,原文明确警告它慢、输出量大,只用于调试。日常用前一条就够。以上命令照抄自仓库文档,我们没有运行过,实际输出以你本地为准。

成片对不上时:回去看 edit_decisions 里锁的是哪个值,以及决策记录里给的备选项和理由。

什么情况不属于这个问题

  • 换的是 provider 不是运行时。这是 What Not To Do 里同一条句子覆盖的另一件事,处理方式类似,但和 render_runtime 不是一个字段。
  • FFmpeg 参与了合成。FFmpeg 在这张运行时表里有一行,在 README 的后期制作表里也被标为 always available、always free。它承担的角色不止一个,具体在什么条件下由它出片,README 在这几处没有给判定条件,我们也不猜。
  • 压根没走流水线。那是 Rule Zero 的范畴——AGENT_GUIDE.md 那句加粗原文是 Every video production request MUST go through the pipeline system. No exceptions.;没进流水线就谈不上提案阶段,也就谈不上运行时被锁。

本文依据 OpenMontage 官方仓库(github.com/calesthio/OpenMontage)的 README、 AGENT_GUIDE.mdconfig.yamlpipeline_defs/lib/ 下的治理模块整理,核对日 2026-08-09。 本文内容为仓库源码与文档口径,我们没有安装或运行过该系统,也没有调用过其中任何一个 provider API, 文中出现的成本数字均为项目方在 README 中自行标注的金额,非我们的实测结果。 该项目以 AGPL-3.0 发布,部分流水线在 manifest 中自标 stability: beta,请以仓库最新内容为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。