← 返回博客

2026年Clash Verge Rev扩展配置与扩展脚本实战:全局/订阅两级覆写、规则前置与高倍率节点剔除

📌 一分钟总结

订阅一更新,手改的规则就没了。用扩展配置与扩展脚本把改动固化下来:七段执行链路、合并规则、被应用接管的字段、三个实战脚本,附两个用 mihomo 内核跑出来的加载失败案例。

订阅里的东西大多不是你写的:节点名是机场起的,规则是模板带的,DNS 是面板生成的。你每次下载新订阅,自己手动改的那几行——加一条直连规则、把某个组换成自动测速、把 DNS 换成自己的 DoH——都会被打回原形。于是很多人养成一个坏习惯:每次更新完订阅,再手动改一遍。改三次还能忍,改三个月就放弃了。

Clash Verge Rev 对这个问题的官方答案是扩展:一层独立于订阅原文的配置,每次订阅更新完自动重新叠加。它不是新功能,但从 v1.7.x 起改过名字、改过入口,v2.5.5 起还改了一条合并规则,网上一大半教程还停在旧版说法上——照着旧文配置,出现「写了没生效」「一保存就报错」也就不奇怪。

本文只讲扩展这一层:它怎么执行、哪些字段能改哪些改了会被丢掉、几组能直接抄的实战配置,以及我在这台机器上用 mihomo 内核实测出来的两个「一定会炸」的引用错误。订阅本身是机场面板生成的——像自由猫这类后台,节点名、分组结构、模板都由服务商决定,你能做的只是在其上叠加;而节点名恰恰是后文脚本筛选的唯一原料。

一、先分清你要改的是哪一层

「让订阅变成我想要的样子」有三条完全不同的路线,很多教程把它们混着讲,结果读者配了一半发现对不上。

路线改动发生在哪优点代价
服务端合成(Sub-Store 一类)订阅链接上游,合成出一份新链接再给客户端多设备共用一份结果,换客户端不用重配多一个服务要维护,链路多一跳
自建侧统一订阅把自己的 VPS 节点和机场节点先在面板侧合并节点来源统一,适合自建 + 机场混用只解决「节点来源」,不解决客户端行为
客户端扩展Clash Verge Rev 内部,订阅下载之后零额外服务,改的是本机最终生效的配置只对装了 Verge 的这台设备生效

前两条路线的完整搭建方式分别在这两篇里:订阅转换与 Sub-Store 完全指南讲服务端合成,自建节点统一订阅化讲把 VPS 节点并进机场订阅。本文是第三条路线。

判断标准很简单:如果问题出在「节点集合不对」(少了节点、格式不对、几个机场要合成一份),用前两条;如果节点集合没问题,只是「客户端跑起来的行为不对」(规则顺序、DNS、策略组、节点筛选),用扩展。把「少了三个节点」这种问题拿扩展去修,是修不好的——扩展只能改配置字段,变不出节点。

二、名词先对齐:v1.7 起叫「扩展配置」和「扩展脚本」,执行链路是七段

旧教程里的 Merge 配置、Script 配置,在 v1.7.x 起分别改名为扩展配置(YAML,负责覆写与合并)和扩展脚本(JavaScript,负责灵活调整)。同时 prepend / append 这类「往列表前面塞几条」的功能被移到了订阅右键菜单的可视化编辑器里(编辑规则 → prepend),不再靠手写扩展实现。看到「Merge 配置」这个词,就知道是旧版教程写的。

比改名更重要的是执行顺序。扩展不是「覆盖订阅」,而是一条链,同一份配置被逐段改写,后执行的覆盖前面写的:

订阅原文
  → 应用设置(设置页里的选项)
  → 全局扩展配置
  → 全局扩展脚本
  → 订阅扩展配置
  → 订阅扩展脚本
  → 应用设置回写(接管字段在最后写回)

两个作用范围的区别值得单独记住:全局扩展对几乎所有订阅都生效,适合放「所有订阅都该这样」的项(开 DNS、开 tcp-concurrent);订阅扩展只对某一张配置卡片生效,适合放那一家机场的专属修正。两者同时生效,订阅扩展在后面,所以它能盖掉全局扩展的同一个字段。

这张链路图能直接回答三个常见疑问:为什么我在全局扩展里写的字段被订阅扩展盖掉了(后者在后);为什么我在扩展里改了 mode 却没用(应用设置在最后回写);为什么两个扩展卡片都写了 nameserver-policy,结果只剩一份(后面那份整体替换了前面那份,见下一节)。

三、合并规则:列表整体替换,嵌套对象逐项合并,dns 和 hosts 整体替换

这是最容易踩的一节,也是 v2.5.5 改过的地方。扩展配置只改写「你写出来的字段」,没写的字段保持订阅原样;但写出来的字段按类型走四类不同规则:

字段类型处理方式典型字段
列表整体替换,不是追加rules、dns.nameserver、proxy-groups
普通值直接替换tcp-concurrent、find-process-mode、unified-delay
其他嵌套对象逐项合并,只替换写出的子字段tun、sniffer
dns 下写出的字段、顶层 hosts整体替换(v2.5.5 起),nameserver-policy、fallback-filter 这类表也一样dns.nameserver-policy、dns.fake-ip-filter、hosts

最容易误判的是 rules。很多人想「我只要在最前面加一条直连规则」,于是在扩展配置里写:

rules:
  - DOMAIN-SUFFIX,example.com,DIRECT

结果是订阅里那几百条规则全没了,只剩这一条,其余流量按 MATCH 兜底走。因为 rules 是列表,列表是整体替换。想在规则列表前面插入,有两条正路:用订阅右键菜单里的「编辑规则 → prepend」(v1.7.x 的官方做法),或者用扩展脚本把新旧数组合并——第六节有可抄的写法。

第二容易误判的是 dns。看这个例子:全局扩展配置里写了 geosite:cn 的解析策略,订阅扩展配置里又写了 +.example.com 的策略。你以为两条都在,实际最终生效的只有后者一条——因为订阅扩展在链路后面,而 dns 下写出的字段是整体替换,不是逐条追加。要让两条并存,只能把 geosite:cn 也写进订阅扩展那份,或者把订阅专属的那条改到订阅扩展脚本里逐条追加(脚本是链路的最后一段,能真正做到「加一条」)。

反过来说,tun 和 sniffer 这类嵌套对象是逐项合并的:你在全局扩展里只写 tun: {mtu: 1400},订阅里 tun 的其他子字段(enable、stack、device)不会被清空。这个差异记住一句话就够了:列表和 dns 是「换」,嵌套对象是「补」。

四、写了却不生效:这些字段被应用接管了

第二类「没生效」跟合并规则无关,而是这些字段压根不由扩展决定。设置页里的选项优先级最高,扩展写进去的值会在链路末尾被丢弃,应用还会弹提示、并在该扩展卡片的日志里记一条。文档列出的清单:

范围被接管的字段
顶层external-controller、external-controller-cors、secret、mixed-port、socks-port、port、redir-port、tproxy-port、mode、allow-lan、log-level、ipv6、unified-delay
TUN 相关tun.enable,以及在 TUN 设置对话框里保存过的 stack、device、auto-route、route-exclude-address、auto-redirect、auto-detect-interface、dns-hijack、strict-route、mtu
DNS 相关dns.ipv6——仅当「DNS 覆写」开启且覆写页面启用了 IPv6 时才被接管

所以「我在扩展里把 mode 改成 global,怎么还是规则模式」「端口改了没反应」这类问题不是合并规则错,而是改错了地方——这些项去设置页改。TUN 的 stack、mtu、dns-hijack 同理,走 TUN 设置对话框,写进扩展等于白写。

还有一个容易忽略的细节:DNS 覆写本身只在扩展之前写入。开启「DNS 覆写」时,覆写页面里填了值的 dns 字段和 hosts 会替换订阅里的对应字段;关闭时(包括因为订阅自带 DNS 策略而自动关闭)应用不改动 dns。但无论哪种情况,扩展里写出的 dns 字段照常生效——唯一的例外是 dns.ipv6。

五、实战一:三个订阅的统一覆写

场景很常见:手上有三份订阅,A 开了 DNS 但没开 ipv6,B 把 tcp-concurrent 关了、DNS 也没开 ipv6,C 直接 dns.enable: false,进程匹配模式还是 strict。你想让三份都开 DNS、都开 tcp-concurrent,A 的进程匹配改成 always,除 C 以外都开 DNS 的 ipv6。这类「多数订阅共有的要求」放全局扩展,个别订阅的特殊要求放订阅扩展——这正是两级设计的意义。

全局扩展配置只写这几个字段:

dns:
  enable: true
  ipv6: true
tcp-concurrent: true

订阅 A 的扩展配置补一条差异项:

find-process-mode: always

订阅 C 的扩展配置把 ipv6 单独关掉:

dns:
  ipv6: false

这里能看出「逐项合并」的价值:C 那份只写了 dns.ipv6,dns.enable 不会被清掉,仍然继承全局扩展里的 true。如果 dns 也按「列表整体替换」的逻辑处理,这段配置会把 C 的 dns 整块抹掉。

验证方式有三层,从便宜到贵:第一层,保存后在扩展卡片的日志里确认没有被「接管字段」提示(有提示说明你写到了应用管辖的字段上);第二层,确认配置卡片的状态是已启用而非报错;第三层,把合并后的关键字段抄成一份独立 YAML,用 mihomo 自带的校验器过一遍语法与引用(第三节的错误就是这一层抓出来的)。第三层对写脚本的人尤其重要,因为脚本拼接出来的配置最容易出现「引用了不存在的策略组」。

顺带说一个和节点来源有关的前提:这类统一覆写假定三份订阅的节点都是标准 Clash 订阅。如果你手上某家只给通用订阅,节点压根进不来,这不是扩展能解决的——多数后台(瑶瑶领先这类通常就同时给通用和 Clash 两个入口)都要取 Clash 那个入口,后面所有的覆写才有意义。

六、实战二:扩展脚本做三件扩展配置做不到的事

扩展配置是静态的「换字段」,它在两件事上无能为力:往列表里插入(而不是替换)、按节点名做条件筛选。这两件事交给扩展脚本;脚本还多一件扩展配置根本做不到的能力——按订阅分别处理(第三件)。脚本语言是 JavaScript,执行器是 boa_engine,入口固定为 main,参数是配置对象,必须返回修改后的同一个对象。

第一件:规则前置。把几条自己的规则塞到订阅规则的最前面,其余的往后接:

const prependRule = [
  "DOMAIN-SUFFIX,baidu.com,DIRECT",
  "DOMAIN-SUFFIX,example.com,自动选择",
];

function main(config) {
  const oldrules = config["rules"];
  config["rules"] = prependRule.concat(oldrules);
  return config;
}

这段是官方文档的写法,但它有个前提没写在示例旁边:规则里点名的策略组必须真的存在。我用 mihomo v1.19.5 校验了一份这样写、但不存在「自动选择」组的配置,内核直接拒绝加载:

$ mihomo -t -d . -f ./config.yaml
level=error msg="rules[0] [DOMAIN-SUFFIX,clashverge.dev,自动选择] error: proxy [自动选择] not found"
configuration file ./config.yaml test failed
# 退出码 1

同一份配置把第一条规则改成指向已存在的组,校验通过、退出码 0。所以在 prepend 里写策略组名字之前,先去订阅里确认那个组叫什么——机场模板里常见的是「手动选择」「自动选择」「PROXY」,但也有人用「节点选择」「Proxy」这种写法,大小写和中文都可能不一样。

第二件:剔除广告位和倍率提示节点。机场常把「官网地址」「剩余流量」「到期时间」「x0.5 倍率」这类信息塞成节点,它们混在策略组里会影响自动测速的选择结果——测速组不会去连它们,但手动组里排在前面很碍事。脚本里按名字过滤就行:

function main(config) {
  const junk = /(官网|剩余|到期|倍率|订阅|流量|群组|TG)/i;
  const proxies = config["proxies"] || [];
  config["proxies"] = proxies.filter((p) => !junk.test(p["name"] || ""));
  return config;
}

节点名是筛选的唯一依据。把线路类型写进节点名是常见做法,主打 IEPL 专线的机场(比如SS-ID)尤其如此,这类名字可以直接当 filter 关键词用,比在手动组里一个个点省事;如果哪家只按「地区+序号」命名,那就只能按地区筛。反过来说,如果你想要的判断依赖节点名里压根没有的信息(在线人数、真实带宽、是否原生 IP),filter 也帮不了你——那些只能自己测。

这里有一个必炸的坑,我实测过。如果订阅的策略组是用显式 proxies: [节点A, 节点B] 列举出来的,你把节点删掉而组里的引用还在,内核加载直接失败:

$ mihomo -t -d . -f ./config.yaml
level=error msg="proxy group[0]: 手动选择: 'B-新加坡02' not found"
configuration file ./config.yaml test failed
# 退出码 1

注意报错只点了第一个找不到的名字,实际可能有一串。修法不是「再把引用也过滤一遍」(组结构千变万化,删不干净),而是让策略组自己挂载节点:用 include-all: true 加一条 filter 正则,由组自己去筛,节点被删掉时组里自然就没了,不会留下悬空引用。同一份节点集合下,这两种写法我都跑了一遍:

proxy-groups:
  - name: 自动选择
    type: url-test
    include-all: true
    filter: "(?i)^(?!.*(官网|剩余|到期|倍率|订阅)).*$"
    url: "http://www.gstatic.com/generate_204"
    interval: 300

启动后查外部控制器的 /proxies/自动选择,返回的 all 字段里只有两个真实节点(A-香港01、B-新加坡02),带「官网地址-x0.5倍率」「剩余流量:12GB」的两个信息节点被排除了;同一份配置换成白名单写法 filter: "(?i)(香港|新加坡)",结果一致。这份配置的语法校验退出码 0,是能跑起来的。

所以正确顺序是:先用 filter 把组改成自动挂载,再让脚本删节点。反过来做,就是你每次更新订阅都要面对一次启动失败。

第三件:按订阅分别处理。v1.7.3 起 main 多了第二个参数,值是当前处理的配置文件名,于是同一段全局脚本可以只对某一份订阅生效:

function main(config, profileName) {
  if (profileName === "A") {
    config["dns"] = config["dns"] || {};
    config["dns"]["nameserver-policy"] = Object.assign(
      {},
      config["dns"]["nameserver-policy"] || {},
      { "+.example.com": "https://1.1.1.1/dns-query" }
    );
  }
  return config;
}

注意这里没有直接替换整张 nameserver-policy 表,而是用 Object.assign 合并——原因就是第三节说的「dns 下写出的字段整体替换」。用脚本时你可以精确到单个键,这也正是脚本比扩展配置更细的地方。

七、脚本的能力边界与排错顺序

脚本环境不是 Node,也不是浏览器。它是 boa_engine 里的一个受限 JS 作用域:没有网络 IO,没有文件 IO,拿不到 fetch、require、fs。可用的东西是标准内建——Object/Array/Map/JSON/Math/RegExp/Date/Promise/Reflect,编码函数 encodeURIComponent、decodeURIComponent,以及 console。这意味着两件事:别想用它去请求一个规则集地址(那是 rule-providers 的活),也别指望它能读本地文件做持久化。

还有一个边界值得说清:扩展改的是「配置」,改不了「订阅能不能下载」。订阅链接被墙、被重置、节点全丢属于另一类故障,处置流程在机场订阅链接应急手册里,别在扩展里找原因。另外,如果你需要的是「节点在多个设备上一致」,扩展天然做不到——它只管本机。做跨境多账号这类需要固定住宅 IP 出口的场景,选机场时看的是线路属性而非客户端配置,像仙路湾这类主打住宅 IP / 原生 IP 的方案,价值在出口归属,扩展层能帮你的只是把它固定进某个策略组、避免被自动测速换走。

排错建议按这个顺序走,命中率从高到低:

① 保存了吗。Verge 的编辑器有独立保存动作,改完不保存等于没改,这一条被漏掉的次数比想象中多得多。② 改的字段是不是被应用接管了(第四节清单),被接管的字段会写进日志,先看日志比猜快。③ 执行顺序对不对:全局写、订阅覆盖,同一字段以链路最后一份为准。④ 脚本有没有 return config:不返回就等于把配置置空,症状是应用后配置异常而不是报错,很隐蔽。⑤ 最后才怀疑语法,而且要用内核校验而不是肉眼——脚本拼出来的 YAML 对象最终要过 mihomo 的解析,把合并结果导出成文件跑一次 mihomo -t,比在界面里反复试快十倍。

脚本作用域里还暴露了 console,但别当成 Node 的 console 用——它写不出文件,也不做持久化。想确认「脚本到底跑没跑」,最直接的办法是在 main 第一行打一条,再配合应用的「导出日志」页看这次加载的记录;脚本每次应用配置都会重新执行,指望它记历史是记不住的。

八、八个高频坑

症状根因处理
扩展里写的 rules 生效后只剩自己那几条列表整体替换用「编辑规则 → prepend」或脚本 concat
两条 nameserver-policy 只剩一条dns 下字段整体替换,后者盖前者合并到同一份,或改到订阅扩展脚本里逐键追加
改 mode / 端口 / log-level 没反应被应用设置接管,链路末尾被丢弃去设置页改
脚本删节点后配置加载失败策略组显式列举了被删的节点改用 include-all + filter
prepend 的规则让内核拒绝加载规则指向的策略组不存在按订阅里的实际组名写,先 mihomo -t
脚本改完毫无变化没保存,或 main 没 return保存并确认返回值
能打开站点但部分域名解析异常、证书报错扩展改了 DNS 增强模式,和订阅的 fake-ip-filter 不匹配DNS 要么整套替换,要么别动
脚本给节点改名后启动失败策略组或 filter 里还是旧名字改名与引用一起改,或改用 filter 选

九、一次完整的排错:订阅更新后所有流量都走直连

这个症状很典型:更新完订阅,测速是通的,节点也在,但浏览器打不开任何境外站点;连接列表里全是同一条 MATCH 命中,策略是 DIRECT。原因通常不在订阅本身,而在这条链路的某一段被改坏了。按写入顺序倒着查,五步能覆盖九成情况。

第一步,确认 rules 还剩几条。打开配置看一眼生效配置里的规则条数。如果你在扩展配置里写过 rules 字段——哪怕只写了一条——列表就是整体替换,订阅里那几百条全没了,剩下的流量按 MATCH 兜底。这是第三节那个规则的实际后果,也是这个症状最常见的原因。

第二步,确认规则指向的策略组还在。规则没丢,但机场模板这次更新把组名改了(比如「自动选择」变成「节点选择」),mihomo 会拒绝加载整份配置。这一类的特征是「配置加载失败」而不是静默回退,日志里会明确写出 proxy [...] not found。

第三步,确认 mode 不是 direct。设置页里的模式优先级高于扩展和脚本,而且会在链路末尾回写——脚本里把 mode 设成 rule,也压不过设置页的直连模式。

第四步,确认订阅本身给的不是直连。部分机场模板会带一个「全球直连」的默认选择组,节点齐全但默认策略是 DIRECT。这种情况改扩展没用,去策略组里手动选一次就好,下次更新前记得它会被重置。

第五步,确认 DNS 侧没有两层打架。症状是「能打开但很慢、个别站点证书报错」。fake-ip 模式下,如果扩展把 dns.enhanced-mode 换成了 redir-host,而订阅里的 fake-ip-filter 还是按 fake-ip 配的,解析会从代理链路漏到本机去,表现就是同一域名在不同客户端上结果不一样。第三、四节说的「dns 下写出的字段整体替换」,正是这类故障的源头:只替换一半比不替换更糟。

这套顺序背后是一句更要紧的话:同一份配置有六个写入点——订阅原文、应用设置、全局扩展配置、全局扩展脚本、订阅扩展配置、订阅扩展脚本,只有最后写入的那次生效。排错时先问「这个字段最后是谁写的」,比问「哪里坏了」命中率高得多。

十、什么时候不该用扩展

扩展是「最后一公里」工具,它有明确的能力天花板。以下四种情况该换工具而不是继续在扩展里折腾:

需要在多台设备上得到同一份结果。扩展只作用于装了 Verge 的这一台。手机、电视盒子、软路由上的 OpenClash 都不认这份扩展,于是你会陷入「每台设备各配一遍」的循环。这种情况该在订阅上游合成一份,或者把规则做成远程 rule-provider(软路由侧的规则集运维思路见OpenClash 规则集运维,思路通用,客户端侧同样适用)。

需要的是节点本身集合的变更。扩展变不出节点,也改不了节点协议。少节点、格式不对、需要把自建和机场合成一份——这些是订阅层的事。

订阅模板本身已经够用。如果一家机场的模板本来就带好了分流和 DNS,你只是想换两三个域名走直连,用右键菜单里的规则可视化编辑比写扩展省事得多,也少一个以后会忘记的配置层。不建议一上手就写全局扩展脚本——它是最难排查的一层,出问题时症状往往是「配置不对劲」而不是报错。

需要分发给多个人。扩展是单人单机的产物:写在谁的机器上就只对谁生效,而且没有版本管理。要让团队或家人用同一套配置,正确做法是产出一份固定链接的合成订阅,让他们导入同一份——上游改一次,所有人下次更新就同步。把扩展截图发群里让人照抄,是最容易抄出事故的分发方式,抄错一个缩进就能让内核拒绝启动。

至于「该选哪家机场」这个问题,扩展帮不上任何忙:线路质量、出口归属、计费口径都由服务商决定。客户端配置的完整基础操作(订阅导入、策略组、TUN)在Clash Verge Rev 从入门到精通里,本文默认你已经能把订阅导进去、能开 TUN,只讨论叠加在它上面的这一层。

十一、把扩展当代码来管:三条约定

扩展层一旦用起来,半年后回头看会变成一堆没人记得缘由的 dns: 和 rules:。三条成本很低的约定能省下大量排查时间。

第一,一个扩展卡片只解决一类问题。「DNS 相关」「规则前置」「节点筛选」分成三张卡片,而不是把十几行塞进一个全局扩展。好处是出问题能一张一张关掉二分定位——这是排障里最有效的手段,而混在一张卡片里的配置没有这个开关。

第二,改之前先把当前生效配置导出一份。扩展改坏了不会有报错,只会「行为变了」。留一份能回退的基线,比事后靠记忆重写快得多。

第三,每次改完都过一遍内核校验。把改动涉及的关键字段拼成一份最小配置,跑 mihomo -t,退出码非 0 就别应用。本文里那两个「配置加载失败」的例子全是这一步抓出来的,界面上点应用反而看不出所以然——你只会看到一直转圈或者悄悄回退到上一个可用配置。

十二、常见问题

Q:扩展配置和扩展脚本,我该先学哪个?先配置后脚本。扩展配置能覆盖八成需求(开 DNS、开 tcp-concurrent、改 find-process-mode、逐项合并 tun),而且它是声明式的、出错容易看出来;脚本强在插入和条件筛选,但一旦写错,症状是配置异常而不是明确报错。

Q:为什么我的旧教程里叫 Merge,现在找不到这个入口?v1.7.x 改名了:Merge 配置 → 扩展配置,Script 配置 → 扩展脚本,prepend/append 挪到了订阅右键菜单的可视化编辑器。找不着入口不是版本坏了,是文档版本对不上。

Q:全局扩展和订阅扩展都写了同一个字段,听谁的?听订阅扩展的。链路是全局配置 → 全局脚本 → 订阅配置 → 订阅脚本,后者覆盖前者。想两边都保留,就别写同一个字段(dns 尤其注意,它是整体替换)。

Q:脚本能读取网络上的规则集吗?不能。脚本作用域没有网络 IO 和文件 IO。需要远程规则集用 rule-providers,那是 mihomo 原生能力,扩展配置里写 rule-providers 字段就行。

Q:改了扩展,节点延迟数字变了,是不是扩展影响了速度?大概率不是。扩展改的是配置字段,不碰线路;延迟数字变化通常来自测量时点、节点负载和是否被自动测速重新选过。要比较,固定节点、固定时间窗、同一测试方式各跑三次看离散度,单次数字没有意义。

Q:升级 Verge 版本后扩展失效,怎么排查?先看该版本的变更说明有没有动合并规则或改名(v2.5.5 就改过 dns/hosts 的替换语义),再确认被接管的字段清单有没有变化——清单变化时,原来能写的字段可能变成被接管、然后静默失效。这两步之后再看自己的 YAML 有没有语法问题。

Q:要不要把扩展当成配置备份?不要。扩展只记录「差异」,订阅一换、字段一改名,差异就可能失效。真正的备份是把合并后的完整配置导出一份存起来,换机器时先恢复它,再重新挂扩展。

Q:能不能在扩展里直接加几个节点?格式上可以,实际别这么干。proxies 是列表,你在扩展里写 proxies 不是在「追加」,而是把订阅的全部节点整体换掉——只剩你写的那几个。节点该由订阅提供,要合并多个来源用 proxy-providers,或者在上游合成。

Q:脚本给节点改名要注意什么?改名会连带打断两类引用:策略组里的显式列举,以及 filter 正则。第六节那个「删节点留下悬空引用」的坑,改名时一模一样——你把「香港01」改成「HK-01」,组里还写着旧名字,内核照样拒绝加载。要改名就一次性改完并把引用一起处理,或者干脆不改,靠 filter 选。

推荐阅读