test(plugindev): 模板接线守卫区分「漏接线」与「刻意保留的兼容面」

TestProcTemplate_CoversAllCoreMethods 红了:它要求模板出现内核提供的**每一个**
method id,而注入标志位落地后模板不再发 "io.injectTextNoMem"。

这不是漏接线,是刻意的向后兼容面:

- **旧模板确实发过它**(可复查:ba49dfd 之前的 templates/proc_main.go.tmpl 里,
  InjectTextNoMemory 拼的就是 "io.injectTextNoMem"),所以内核必须继续接受
  那时编出的插件二进制;内核侧的注释也写明「旧 RPC 语义就是『不进记忆』」。
- 当前模板改成走 "io.injectText" + `InjectOptions{NoMemory: true}`,两条路径
  语义等价,没有理由再发旧 id。

若把「内核有、模板就必须发」当不变量,这条守卫会常驻误报——常驻误报的守卫
迟早被习惯性忽略,那时**真**漏接线就没人看见了。故:

- 从 required 移出该 id,改为显式的 `deprecated` 表(每条写出保留原因);
- 加**反向保护**:allowlist 里的 id 一旦重新出现在模板里就报错,提示该条目已过期,
  避免这个表退化成「永久豁免」的垃圾抽屉。

实测:模板接线测试由红转绿;把 id 临时塞回模板,反向保护如期报出
「条目已过期,请从 deprecated 移除」,恢复后再次全绿。
This commit is contained in:
JianFeeeee
2026-09-12 09:33:00 +08:00
parent d893bfa76f
commit e839eb8220

View File

@ -92,8 +92,9 @@ func TestProcTemplate_CoversAllCoreMethods(t *testing.T) {
required := []string{
// 注册面
"tool.register", "stage.register", "output.register", "api.register", "input.register",
// IO 注入
"io.injectText", "io.injectInterrupt", "io.injectTextNoMem", "io.injectInputSync",
// IO 注入io.injectTextNoMem 见下方 deprecated内核保留为兼容旧二进制
// 当前模板改走 io.injectText + NoMemory 标志位,不再发那个 id
"io.injectText", "io.injectInterrupt", "io.injectInputSync",
"io.setToolBlocks",
// 多模态注入1.1.0 新增)。漏接线的后果是插件调 InjectInputMedia 静默无效果:
// 模板不发这个 RPC内核也就永远收不到而两边都不报错。
@ -131,6 +132,28 @@ func TestProcTemplate_CoversAllCoreMethods(t *testing.T) {
t.Errorf("模板缺少 core method %q内核已提供插件侧未接线", m)
}
}
// 内核保留、但**当前模板不再发送**的 method id。
//
// 它们不是「公开接口新增却忘记接线」,而是刻意的向后兼容面:
// 内核必须继续接受用旧模板编出的插件二进制发来的 id而当前模板没有理由再发。
//
// 可复查的判据ba49dfd 之前的模板里 InjectTextNoMemory 发的就是
// "io.injectTextNoMem";注入标志位落地后它改走 "io.injectText" + NoMemory。
//
// 为何要单独列而不是直接从 required 删掉:这条守卫的价值在于「新接口必须接线」,
// 而把「内核有、模板就必须发」当不变量,会让它常驻误报——常驻误报的守卫迟早
// 被人习惯性忽略,那时真漏接线也就没人看见了。
deprecated := map[string]string{
"io.injectTextNoMem": "旧模板经此表达「不进记忆」;现由 io.injectText + NoMemory 表达",
}
// 反向保护allowlist 条目一旦又出现在模板里,说明它已过期,必须删掉,
// 否则这里会悄悄变成「永久豁免」的垃圾抽屉。
for m, why := range deprecated {
if strings.Contains(src, `"`+m+`"`) {
t.Errorf("deprecated 里的 %q 又出现在模板里(%s——条目已过期请从 deprecated 移除", m, why)
}
}
}
// 模板必须处理内核发来的全部调用(含无法 JSON 序列化的 Cleaner 回调)。