From 8b50fb3738e3f48a5a81975f5e6ccb0f05b62caa Mon Sep 17 00:00:00 2001
From: KuGouGo <62388728+KuGouGo@users.noreply.github.com>
Date: Sun, 26 Jul 2026 19:54:30 +0800
Subject: [PATCH] Simplify documentation and local compatibility
---
CONTRIBUTING.md | 37 --------
README.md | 120 ++++++++-----------------
SECURITY.md | 41 ---------
THIRD_PARTY_NOTICES.md | 76 +++++-----------
docs/DEVELOPMENT.md | 104 +++++++--------------
docs/README.md | 25 ------
docs/STRUCTURE.md | 84 -----------------
docs/TROUBLESHOOTING.md | 86 ------------------
scripts/commands/guard-artifacts.sh | 4 +-
scripts/commands/publish-branches.sh | 13 +--
scripts/commands/select-build-scope.sh | 10 +--
scripts/lib/common.sh | 7 +-
12 files changed, 110 insertions(+), 497 deletions(-)
delete mode 100644 CONTRIBUTING.md
delete mode 100644 SECURITY.md
delete mode 100644 docs/README.md
delete mode 100644 docs/STRUCTURE.md
delete mode 100644 docs/TROUBLESHOOTING.md
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 0ba09719d..000000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# 贡献说明
-
-本仓库以个人使用为主,主要维护自定义规则并整合上游数据。提交规则时保持内容清晰、可生成即可,不设置复杂审批流程。
-
-## 自定义规则
-
-- 域名规则:`sources/custom/domain/*.list`
-- IP 规则:`sources/custom/ip/*.list`
-- 文件名使用小写字母、数字和连字符。
-- 规则类型和值保持规范格式,例如:
-
-```text
-DOMAIN,api.example.com
-DOMAIN-SUFFIX,example.com
-IP-CIDR,192.0.2.0/24
-IP-CIDR6,2001:db8::/32
-```
-
-不同文件可以有意重叠,以便分别绑定不同策略;同一文件内不应保留重复或被更宽规则覆盖的条目。使用首条命中的客户端时,细分规则应放在宽泛规则之前,例如先加载 `emby-cn`,再加载 `emby`。
-
-## 修改与验证
-
-日常修改可直接提交,也可通过 Pull Request 合并。建议至少运行:
-
-```bash
-make validate
-```
-
-需要预览自定义文本产物时运行:
-
-```bash
-make build-custom-text
-```
-
-涉及完整上游同步或二进制格式时,由 `main` 分支的发布工作流统一构建。不要提交 `.output/`、`.tmp/`、`.artifacts/`、`.bin/`、凭据或本机缓存。
-
-新增上游时,在 `config/upstreams.json` 中填写来源和健康阈值,并按实际情况更新第三方来源说明。仓库代码使用 MIT 许可证;上游数据仍遵循各自条款。
diff --git a/README.md b/README.md
index 033b937a7..1cbab666e 100644
--- a/README.md
+++ b/README.md
@@ -2,112 +2,70 @@
-
-
-本仓库用于个人维护自定义规则并整合上游数据,生成 Surge、Quantumult X、Egern、sing-box 与 mihomo 规则。`main` 保存源码、配置和工作流;可直接使用的文件位于对应平台分支。
+个人自用规则仓库:维护自定义规则,拉取并整合上游数据,自动生成多个客户端的规则文件。
-> [!IMPORTANT]
-> 客户端不要引用 `main`。规则名称和区域分类沿用上游定义,不构成准确性、完整性或适用性保证。第三方内容不因格式转换而自动适用本仓库的 MIT 许可,详见 [`NOTICE`](NOTICE) 与 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。
+> 客户端不要引用 `main`,请使用对应的产物分支。
-## 获取产物
+## 产物
-分支 URL 格式:
+| 客户端 | 分支 | 格式 |
+| --- | --- | --- |
+| Surge | [`surge`](https://github.com/KuGouGo/Rules/tree/surge) | `.list` |
+| Quantumult X | [`quanx`](https://github.com/KuGouGo/Rules/tree/quanx) | `.list` |
+| Egern | [`egern`](https://github.com/KuGouGo/Rules/tree/egern) | `.yaml` |
+| sing-box | [`sing-box`](https://github.com/KuGouGo/Rules/tree/sing-box) | `.srs` |
+| mihomo | [`mihomo`](https://github.com/KuGouGo/Rules/tree/mihomo) | `.mrs` |
+
+URL 格式:
```text
-https://raw.githubusercontent.com/KuGouGo/Rules/{branch}/{type}/{name}.{extension}
+https://raw.githubusercontent.com/KuGouGo/Rules/{branch}/{domain|ip}/{name}.{extension}
```
-| 客户端 | 分支 | domain / ip 扩展名 | 分支说明 |
-| --- | --- | --- | --- |
-| Surge | `surge` | `.list` | [查看产物](https://github.com/KuGouGo/Rules/tree/surge) |
-| Quantumult X | `quanx` | `.list` | [查看产物](https://github.com/KuGouGo/Rules/tree/quanx) |
-| Egern | `egern` | `.yaml` | [查看产物](https://github.com/KuGouGo/Rules/tree/egern) |
-| sing-box | `sing-box` | `.srs` | [查看产物](https://github.com/KuGouGo/Rules/tree/sing-box) |
-| mihomo | `mihomo` | `.mrs` | [查看产物](https://github.com/KuGouGo/Rules/tree/mihomo) |
-
示例:
```text
https://raw.githubusercontent.com/KuGouGo/Rules/surge/domain/cn.list
https://raw.githubusercontent.com/KuGouGo/Rules/quanx/domain/emby-cn.list
-https://raw.githubusercontent.com/KuGouGo/Rules/egern/ip/cn.yaml
-https://raw.githubusercontent.com/KuGouGo/Rules/sing-box/domain/cn.srs
+https://raw.githubusercontent.com/KuGouGo/Rules/sing-box/domain/fakeip-filter.srs
https://raw.githubusercontent.com/KuGouGo/Rules/mihomo/ip/google.mrs
```
-各平台的接入方式和最小配置示例位于对应产物分支的 `README.md`。分支 URL 会随成功发布变化,不适合作为不可变版本标识;需要固定内容时,应将分支名替换为产物分支的提交 SHA。
-
-## 规则说明
-
-| 名称 | 类型 | 当前生成方式 |
-| --- | --- | --- |
-| `cn` | domain | v2fly/domain-list-community 的 `cn` 集合及其派生结果 |
-| `cn` | ip | 配置的中国大陆 IP 上游经规范化、去重和 CIDR 合并后的结果 |
-| `geolocation-cn` / `geolocation-!cn` | domain | 上游提供的区域集合名称与内容 |
-| `google` / `telegram` | ip | 配置的服务地址源;Telegram 结果还合并配置的 ASN 前缀 |
-| `emby-cn` / `emby` | domain | 本仓库维护的两个 Emby 规则集合 |
-| `fakeip-filter` | domain | 本仓库维护的 Fake-IP 排除集合 |
-
-在按首条命中处理的客户端中,如果同时使用 `emby-cn` 和 `emby`,应先加载范围较窄的 `emby-cn`。规则文件会随上游增加、删除或改变;使用前应在目标分支确认文件存在并检查内容。
-
-## 转换行为
+常用规则包括 `cn`、`geolocation-cn`、`geolocation-!cn`、`google`、`telegram`、`emby-cn`、`emby` 和 `fakeip-filter`。同时使用 `emby-cn` 与 `emby` 时,应先加载范围较小的 `emby-cn`。
-| 产物平台 | 精确域名 | 后缀 | 关键词 | 正则 | IP CIDR |
-| --- | :---: | :---: | :---: | :---: | :---: |
-| Surge | ✓ | ✓ | ✓ | — | ✓ |
-| Quantumult X | ✓ | ✓ | ✓ | — | ✓ |
-| Egern | ✓ | ✓ | ✓ | ✓ | ✓ |
-| sing-box | ✓ | ✓ | ✓ | ✓ | ✓ |
-| mihomo | ✓ | ✓ | — | — | ✓ |
+## 添加自定义规则
-`✓` 表示当前转换器会保留并输出该类型,`—` 表示当前转换链会省略该类型;该表不判断客户端自身的全部能力。一个列表在目标平台没有可保留条目时,不发布空文件。
+- 域名规则:`sources/custom/domain/*.list`
+- IP 规则:`sources/custom/ip/*.list`
+- 文件名使用小写字母、数字和连字符。
-属性与区域名称沿用上游语义:
+```text
+DOMAIN,api.example.com
+DOMAIN-SUFFIX,example.com
+DOMAIN-KEYWORD,example
+DOMAIN-REGEX,^(.+\.)?example\.com$
+IP-CIDR,192.0.2.0/24
+IP-CIDR6,2001:db8::/32
+```
-- `name@cn`、`name@!cn`、`name@ads` 是属性派生集合,`@!cn` 不是布尔取反。
-- `*-cn`、`*-!cn` 是区域列表名称;明显冗余的属性派生不会发布。
-- `official`、`registry`、`community` 是仓库配置中的来源分类,不代表质量、可信度或许可等级。
+不同文件可以按策略需要重叠;同一文件内不要保留重复或被更宽规则覆盖的条目。
-## 本地维护
+## 本地检查
-本地命令要求 Bash 5+、Python 3.11+、GNU Make 和 Git。macOS 可使用 Homebrew Bash 与 Python 运行检查和文本构建;需要下载 sing-box 或 mihomo 的二进制构建只支持 lock 文件声明的 Linux 平台。
+需要 Bash 5+、Python 3.11+、GNU Make 和 Git。
```bash
-make check
-make validate
-make build-custom-text
-make preflight
-make clean
+make check # 日常快速检查
+make validate # 完整测试
+make build-custom-text # 预览自定义文本产物
+make clean # 清理生成文件
```
-- `make check`:快速检查脚本语法、配置和自定义规则,适合日常改规则。
-- `make validate`:在快速检查基础上运行完整测试。
-- `make build-custom-text`:生成自定义文本产物,不下载二进制工具。
-- `make preflight`:执行 `make validate` 和自定义文本构建;不执行上游完整同步、二进制构建或发布。
-- `make clean`:删除生成产物和临时文件,保留已校验的工具缓存。
-
-完整环境、构建事务和调试命令见 [开发指南](docs/DEVELOPMENT.md)。
-
-## 仓库边界
-
-- 长期分支只保留 `main` 与 `surge`、`quanx`、`egern`、`sing-box`、`mihomo` 五个产物分支。
-- 日常变更可直接提交,也可通过 Pull Request;PR 只运行基础校验,完整生成和发布由 `main` 工作流负责。
-- `main` 在构建相关路径变化、定时任务运行或人工触发时执行发布工作流;产物内容没有变化时不会创建新的产物分支提交。
-- 不启用自动依赖 PR;GitHub Actions 版本按需手工更新。
-- `fakeip-filter` 是本仓库维护的文本源,不下载第三方预编译文件。
-- 构建摘要、manifest 和 CI 通过都不是第三方许可证明。
-- 规则按现状提供。使用者需自行判断策略、顺序和更新带来的影响,并保留可回退版本。
-
-## 文档
-
-| 文档 | 内容 |
-| --- | --- |
-| [贡献指南](CONTRIBUTING.md) | 规则格式、来源要求和评审清单 |
-| [开发指南](docs/DEVELOPMENT.md) | 环境、命令和开发流程 |
-| [仓库结构](docs/STRUCTURE.md) | 同步、构建、manifest、守卫和发布架构 |
-| [故障排查](docs/TROUBLESHOOTING.md) | 常见构建和产物问题 |
-| [安全政策](SECURITY.md) | 安全问题报告范围与方式 |
-| [第三方声明](THIRD_PARTY_NOTICES.md) | 上游来源和人工许可核对状态 |
+更多维护命令见 [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md)。推送到 `main` 后,GitHub Actions 会自动构建并更新五个平台分支;每天也会定时同步一次上游。
+
+## 声明
+
+规则按现状提供,上游内容可能随时变化,请自行确认使用策略并保留回退版本。仓库代码使用 MIT License;第三方内容仍遵循各自条款,来源见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index e2534bfcd..000000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# 安全政策
-
-本文件说明安全支持范围和私密报告方式。规则内容错误、许可核对和一般构建失败分别按质量或治理问题处理。
-
-## 支持范围
-
-仅当前 `main` 及当前自动化生成的五个本仓库维护的发布分支受支持。历史提交、第三方分叉、镜像、用户修改规则和非支持环境不在支持范围内。
-
-可能导致凭据泄露、工作流或发布分支被接管、任意代码执行、供应链污染或绕过发布守卫的问题属于安全问题。规则误分流、上游失效、普通构建错误和许可状态未知通常不是安全漏洞,请使用普通 Issue 或 Pull Request,但不要公开敏感信息。
-
-构建工具固定到 `config/tools-lock.json` 声明的 GitHub Release 资产,并校验归档与解包后二进制的 SHA-256;缓存还会复核来源 metadata、摘要和版本探针。该机制不等同于发布者签名,若发现资产替换、下载链路劫持或缓存投毒证据,请按安全问题私密报告。
-
-## 私密报告
-
-优先通过 [GitHub Security Advisory](https://github.com/KuGouGo/Rules/security/advisories/new) 私密报告。不要在公开 Issue、Pull Request、讨论区或规则文件中披露漏洞细节、令牌或可利用样例。若仓库未启用私密漏洞报告且没有可用的私密联系方式,可先提交一个不含漏洞细节的普通 Issue,请求维护者建立私密沟通渠道。
-
-报告建议包含:
-
-- 受影响提交、脚本、工作流或发布分支;
-- 最小复现步骤、利用条件和影响;
-- 已采取或建议的缓解措施;
-- 希望采用的披露时间表。
-
-请勿在未获授权时访问他人数据、持久化控制、破坏发布分支或高频测试第三方服务。
-
-## 响应与凭据处理
-
-维护者会尽力确认和评估,但不承诺固定响应时限。完成缓解后将按实际影响决定是否发布公告及致谢。
-
-仓库不应接收真实令牌、Cookie、私钥或账号信息。凭据进入提交或日志后应立即在提供方撤销或轮换;删除 Git 历史不能替代轮换。
-
-## 文档导航
-
-- [`README.md`](README.md):用户入口、平台示例和关键边界
-- [`CONTRIBUTING.md`](CONTRIBUTING.md):贡献规则与人工评审清单
-- [`docs/README.md`](docs/README.md):文档职责与阅读路径
-- [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md):环境、命令和开发流程
-- [`docs/STRUCTURE.md`](docs/STRUCTURE.md):构建、产物、守卫和发布结构
-- [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md):常见失败与定位步骤
-- [`SECURITY.md`](SECURITY.md):安全支持范围和私密报告
-- [`NOTICE`](NOTICE) / [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md):许可范围与第三方状态
diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md
index 8dab320d5..0c9f4f1d4 100644
--- a/THIRD_PARTY_NOTICES.md
+++ b/THIRD_PARTY_NOTICES.md
@@ -1,56 +1,20 @@
-# 第三方声明
-
-本文件记录当前已知第三方输入及截至 **2026-07-15** 的人工核对状态。它不是自动生成清单,也不是法律意见。`trust` 只表示采集来源分类;公开可访问、官方托管、注册机构提供或 CI 成功都不等于获得复制、修改或再分发授权。
-
-标准 MIT License 位于 [`LICENSE`](LICENSE),适用范围见 [`NOTICE`](NOTICE)。第三方材料不会因下载、规范化、合并、转换或编译而变为本仓库的 MIT 内容。
-
-## 已确认的上游许可证
-
-| 输入 | 来源 | 人工核对结果 | 说明 |
-| --- | --- | --- | --- |
-| `domain.dlc` | [v2fly/domain-list-community](https://github.com/v2fly/domain-list-community) | MIT License,`Copyright (c) 2018-2019 V2Ray` | 上游 [LICENSE](https://raw.githubusercontent.com/v2fly/domain-list-community/master/LICENSE) 明确声明;再分发时仍需保留其版权与许可声明。 |
-
-“已确认”只表示链接材料中存在明确许可证,不代表自动化验证了每次下载内容、上游全部依赖或具体使用方式。
-
-## 许可或再分发权尚未确认
-
-以下项目统一标记为“未知”。维护者必须在相关合并或发布前人工评审许可证、服务条款、数据来源和适用义务;脚本不会读取本表或据此自动阻断。
-
-| 输入 | 来源 | 分类 | 人工核对状态 |
-| --- | --- | --- | --- |
-| `ip.cn-ipv46` | | `registry` | 未知;响应中未见明确数据许可证。 |
-| `ip.loyalsoldier-geoip-cn`、`ip.loyalsoldier-geoip-private` | [Loyalsoldier/geoip](https://github.com/Loyalsoldier/geoip) `release` 分支 | `community` | 未知;`master` 的 CC BY-SA 4.0 不能自动证明 `release` 聚合产物及全部来源适用相同许可。 |
-| `ip.cn-ipv46-apnic` | | `registry` | 未知;名称提及 APNIC 不等于已获 APNIC 再分发授权。 |
-| `ip.google` | | `official` | 未知;响应中未见独立数据许可证。 |
-| `ip.telegram` | | `official` | 未知;响应中未见独立数据许可证。 |
-| `ip.cloudflare-ipv4`、`ip.cloudflare-ipv6` | 、 | `official` | 未知;未确认独立数据许可证。 |
-| `ip.aws`、`ip.cloudfront` | | `official` | 未知;两个解析器复用同一官方响应,未见独立数据许可证。 |
-| `ip.fastly` | | `official` | 未知;响应中未见独立数据许可证。 |
-| `ip.github` | | `official` | 未知;未确认 Meta API 数据的独立再分发许可证。 |
-| `ip.apple` | (回退:) | `official` | 未知;未确认页面中网络范围数据的独立再分发许可证。 |
-| `ip.ripe-stat` | | `registry` | 未知;未确认 API 响应和 ASN 查询所得前缀集合的再分发许可。 |
-
-`asn_groups.telegram`、`asn_groups.netflix`、`asn_groups.spotify` 和 `asn_groups.disney` 只是 RIPEstat 查询参数分组,不是独立许可声明;所得结果沿用 `ip.ripe-stat` 的“未知”状态。组织名称和商标归各自权利人所有。
-
-## Fake-IP
-
-当前 `fakeip-filter` 是 KuGouGo 在 `sources/custom/domain/fakeip-filter.list` 维护的仓库源码,由自定义构建生成各平台文本产物以及 sing-box、mihomo 二进制产物;它不属于第三方输入,也不下载第三方预编译文件。
-
-## 审计与评审边界
-
-- `config/upstreams.json` 覆盖主上游规则网络输入;工具资产下载另由工具 lock 控制。当前没有 Fake-IP 网络输入或独立同步步骤。
-- `.output/upstream-summary.json` 只覆盖主同步记录,不覆盖本仓库自定义源(包括 `fakeip-filter`)、完整转换链或 HTTP 响应身份,因此不是完整来源追溯记录。
-- `.output/build-summary.json` 由成功构建事务在产物守卫后生成并受 manifest 摘要绑定;它只说明事务产物统计,不证明来源或授权。
-- 当前自动化不解析 `NOTICE` 或本文件,不验证第三方许可,也不会因“未知”状态自动失败。
-- 新增、更换或改变第三方输入时,应同步更新本文件并提供可核验依据;无法确认时保持“未知”,由维护者人工决定停止、替换、取得授权或满足适用义务后再发布。
-
-## 文档导航
-
-- [`README.md`](README.md):用户入口、平台示例和关键边界
-- [`CONTRIBUTING.md`](CONTRIBUTING.md):贡献规则与人工评审清单
-- [`docs/README.md`](docs/README.md):文档职责与阅读路径
-- [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md):环境、命令和开发流程
-- [`docs/STRUCTURE.md`](docs/STRUCTURE.md):构建、产物、守卫和发布结构
-- [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md):常见失败与定位步骤
-- [`SECURITY.md`](SECURITY.md):安全支持范围和私密报告
-- [`NOTICE`](NOTICE) / [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md):许可范围与第三方状态
+# 第三方来源
+
+仓库代码使用 [MIT License](LICENSE)。下列上游数据仍遵循各自的许可证或服务条款,不因本仓库进行下载、合并或格式转换而变为 MIT 内容。
+
+| 内容 | 来源 |
+| --- | --- |
+| 域名规则 | [v2fly/domain-list-community](https://github.com/v2fly/domain-list-community)(MIT) |
+| 中国 IP | 、、[Loyalsoldier/geoip](https://github.com/Loyalsoldier/geoip) |
+| Google IP | |
+| Telegram IP | |
+| Cloudflare IP | 、 |
+| AWS / CloudFront IP | |
+| Fastly IP | |
+| GitHub IP | |
+| Apple 网络范围 | |
+| ASN 前缀 | [RIPEstat](https://stat.ripe.net/) |
+
+除 v2fly/domain-list-community 明确使用 MIT License 外,本仓库不对其他上游数据的再分发许可作保证。使用者应自行确认相关条款。
+
+`fakeip-filter`、`emby`、`emby-cn` 和 `apple-apns` 的本地源位于 `sources/custom/`。当前完整上游配置以 [`config/upstreams.json`](config/upstreams.json) 为准。
diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md
index 708d229df..b025e1bda 100644
--- a/docs/DEVELOPMENT.md
+++ b/docs/DEVELOPMENT.md
@@ -1,89 +1,49 @@
-# 开发指南
-
-本文件说明环境、命令和日常开发流程;构建内部结构见 [仓库结构](STRUCTURE.md)。
-
-## 环境支持
-
-CI 的受支持基准是 GitHub Actions `ubuntu-latest`、Bash 5+ 和 Python 3.11。本地验证与文本构建支持安装了 Bash 5+、Python 3.11+、GNU Make、Git、curl、tar、gzip、find 的 Linux、WSL 和 macOS;macOS 应使用 Homebrew Bash 与 Python,并确保 `/opt/homebrew/bin` 或 `/usr/local/bin` 位于系统路径之前。`make check-runtime` 会在构建前拒绝旧版 Bash 或 Python。
-
-Homebrew 的版本化 Python 将通用的 `python3` 链接放在 `libexec/bin`。macOS 可用以下配置验证当前终端,而无需为本地系统增加二进制规则编译支持:
-
-```bash
-export PATH="$(brew --prefix python@3.11)/libexec/bin:$(brew --prefix)/bin:$PATH"
-make check-runtime
-```
-
-二进制工具下载逻辑仅支持 Linux 的 `amd64`、`arm64` 锁定资产。原生 Windows 在需要下载 sing-box/mihomo 时会被 `require_non_windows_shell` 明确拒绝;macOS 也没有对应 lock 平台。请使用 Linux、WSL 或 GitHub Actions 完成二进制构建。
-
-完整构建只使用 `config/tools-lock.json` 固定的 sing-box 和 mihomo 版本、Linux 资产名、GitHub release asset SHA-256,以及从这些已校验官方归档独立提取的二进制 SHA-256;环境变量不能覆盖版本。下载归档在解包前校验摘要,解包后的程序也必须先匹配锁定摘要才会执行;缓存通过 provenance sidecar、锁定来源、二进制 SHA-256 和版本探针复核,二进制与 sidecar 成对替换,metadata 写入失败不会替换现有缓存。`tag_commit` 仅是记录/人工核对用 metadata,当前流程不认证 tag 与 commit 的关系。工作流缓存键包含锁文件摘要、两个版本和格式前缀。该机制是资产摘要锁定,不是发布者签名。
+# 维护说明
## 常用命令
```bash
-make help
-make check
-make lint
-make test
-make validate
-make build-custom-text
-make build-custom
-make preflight
-make clean
+make check # Shell、Python、配置和自定义规则检查
+make validate # 快速检查 + 全部测试
+make build-custom-text # 生成自定义文本产物
+make build-custom # 生成文本和二进制产物(Linux)
+make clean # 清理临时文件和产物
```
-- `make check` / `make lint`:快速检查 Shell、Python、配置和自定义规则。
-- `make validate`:快速检查后再运行完整测试。
-- `make check-runtime`:验证当前 `PATH` 解析到 Bash 5+ 和 Python 3.11+。
-- `make build-custom-text`:只生成自定义文本产物,不下载二进制编译器。
-- `make build-custom`:生成自定义文本和二进制产物。
-- `make preflight`:`make validate` 加文本自定义构建;不执行完整同步、产物守卫(artifact guard)或发布。
-- `build-artifacts-transaction.sh`:CI 的完整入口。它在 `.tmp/` 中以事务自有的 `RULES_ARTIFACT_ROOT` 组合上游同步或已发布分支恢复、自定义构建、守卫、摘要、manifest 生成与验证;调用方提供 `RULES_ARTIFACT_ROOT` 会被拒绝,测试或运维如需改变最终提升位置应使用 `RULES_LIVE_ARTIFACT_ROOT`。该 live root 必须与仓库 `.tmp/` 位于同一文件系统,跨设备目标会在构建前被拒绝;最终 backup、promotion 和 rollback 均使用不允许复制回退的严格目录 rename,因此检查后的设备变化也会以 EXDEV 失败。全部成功后才提升为 `.output/`(或该显式 live root)。backup 后收到 HUP、INT 或 TERM,以及 promotion rename 失败时,都会通过同一幂等回滚恢复旧目录;恢复本身失败时事务目录保留唯一备份以供人工处理。失败诊断写入非发布目录 `.artifacts/diagnostics/`,并记录 failure reason、promotion state、rollback status 与可用的 signal。`config/upstreams.json` 为每个源声明 parser、required/optional、原始字节、规范条目、地址族和 fallback policy;required 源在主 URL 与允许的回退均失败,或出现语义健康回归时阻断提升。每个 RIPE Stat ASN 响应和合并分组都使用 `ripe-stat` health policy,过小或无效响应会先写入诊断摘要再阻断事务。自定义恢复要求五个发布分支都存在且具有相同 generation/source 身份,并把分支 commit 写入 manifest restoration metadata;缺失或身份分裂时失败关闭,应执行 full 构建恢复发布 cohort。
-- `generate-artifact-manifest.sh`:完整构建事务的内部阶段,不是独立的日常构建入口。它要求当前 artifact root 已有 canonical 输入、摘要、来源记录和发布基线;按能力配置验证五个平台后才写入 schema v4 manifest。缺失或未验证的产物会阻断生成。CI 将 source SHA 绑定到实际 checkout 的 `github.sha`:PR 验证记录被测试的合并提交,正式发布记录 `main` 提交。
-- `verify-artifact-manifest.sh`:严格重算所选 artifact root 内的可发布文件集合、路径、大小和 SHA-256,并重新执行五平台 canonical 验证、核对发布基线、能力/lock 与可选 source SHA;发布 job 在恢复或安装锁定工具后强制执行同一验证。需要单独调试时,应先保留完整事务生成的 artifact root,不要手工拼装 manifest 参数。
+本地需要 Bash 5+、Python 3.11+、GNU Make 和 Git。二进制构建还需要 Linux;日常添加规则运行 `make check` 即可。
-五平台验证以 `.output/.canonical/{domain,ip}/` 为共同基准。Surge、Quantumult X、Egern 解析各自文本/YAML,`.srs` 使用固定的 `sing-box rule-set decompile` 读回 JSON,`.mrs` 使用固定的 `mihomo convert-ruleset mrs INPUT OUTPUT` 读回。每个平台先按能力矩阵过滤不支持的类型,再比较规范化语义集合:域名消除已被更宽后缀覆盖的冗余项,IP 合并为等价 CIDR 并集;值替换、范围扩大、范围丢失、缺少副本和没有 canonical 来源的额外文件都会失败。manifest 记录验证方法、原始计数、读回语义 SHA-256,以及规范输入的语义 SHA-256。
-- `make clean`:删除 `.tmp/`、`.output/`、`.artifacts/`、Python `__pycache__` 和未完成的 `.bin/*.new*`;保留已安装的 `.bin/sing-box`、`.bin/mihomo` 及 provenance sidecar。
+## 目录
-CI 设置 `REQUIRE_SHELLCHECK=1`,本地缺少 ShellCheck 时的跳过不代表 CI 会通过。
-
-GitHub Actions 使用完整 commit SHA 固定版本,按需手工更新。
-
-## 开发流程
-
-1. 直接修改 `main` 或使用临时分支,不手工编辑生成目录。
-2. 修改自定义源、配置、实现或测试夹具。
-3. 日常规则变更运行 `make check`;修改生成逻辑时再运行 `make validate` 或适用的构建命令。
-4. 检查差异中没有 `.output/`、`.tmp/`、`.bin/`、凭据或无关格式化。
-5. 可直接提交到 `main`,也可通过 Pull Request 合并。PR 只运行基础校验;完整候选构建不再重复执行。
-6. `main` 的发布工作流按变更范围生成并更新五个平台分支。
-
-## 自定义规则与名称
-
-域名源位于 `sources/custom/domain/*.list`;可选 IP 源位于 `sources/custom/ip/*.list`,后者可不存在。文件名只使用小写字母、数字和连字符。
-
-新增名称冲突检查仅针对相对基准提交新加入的自定义源,且 domain 与 ip 分开检查五个平台的当前 `.output/` 目标路径。它不是全仓库名称注册表,也不覆盖既有自定义源修改。
+```text
+sources/custom/domain/ 自定义域名规则
+sources/custom/ip/ 自定义 IP 规则
+config/upstreams.json 上游地址和解析方式
+config/tools-lock.json sing-box / mihomo 工具版本
+scripts/ 同步、转换、校验和发布脚本
+templates/ 各产物分支 README 模板
+```
-自定义源会检查类型、值和同一文件内的重复/覆盖关系。不同文件允许有意重叠,以便绑定不同策略,不再维护逐条冲突审批清单。首条命中客户端应先加载细分规则,例如先加载 `emby-cn`,再加载 `emby`。
+不要手工修改 `.output/` 或五个平台产物分支。自定义规则或配置推送到 `main` 后,GitHub Actions 会自动生成并发布。
-## 摘要与许可评审
+## 添加规则
-主上游完整同步生成的 `upstream-summary.json` 记录健康检查后的状态、实际 URL、回退、原始与规范化输入的字节数、条目数和 SHA-256;DLC 另记录检出的 commit。它不包含本仓库维护的自定义源(包括 `sources/custom/domain/fakeip-filter.list`),也不覆盖完整转换链或 HTTP 响应身份,因此仍不是完整来源证明。`fakeip-filter` 与其他自定义规则共用同一构建入口,没有独立下载步骤。
+规则文件使用 `.list` 扩展名,文件名只使用小写字母、数字和连字符。
-`build-summary.json` 是成功构建事务的固有输出:产物守卫通过后、manifest 生成前,由 `build-artifacts-transaction.sh` 在事务 artifact root 中生成。manifest 同时记录摘要文件 SHA-256 与解析后的嵌入内容,发布前验证两者。工作流的 `Show summary` 步骤只负责显示成功输出,或在失败诊断场景中临时生成可读摘要,不定义成功产物。
+```text
+DOMAIN,api.example.com
+DOMAIN-SUFFIX,example.com
+IP-CIDR,192.0.2.0/24
+```
-许可状态完全由维护者人工核验。自动化不解析许可文档,也不会根据“未知”状态自动阻断。
+不同文件允许重叠,以便绑定不同策略;同一文件内的重复、无效格式或被宽规则覆盖的条目会被检查拒绝。
-## 测试约定
+新增上游时修改 `config/upstreams.json`,并按实际情况更新根目录的 `THIRD_PARTY_NOTICES.md`。
-输出行为有意变化时,更新 `tests/fixtures/` 并新增或调整 `scripts/tests/test-*.sh`。测试运行器自动发现 `test-*.sh`。不要通过降低阈值、删除测试或跳过守卫掩盖异常。
+## 自动构建
-## 文档导航
+- PR:只运行快速检查。
+- `main`:检查、构建并发布五个平台分支。
+- 定时任务:每天同步一次上游。
+- 手动运行:Actions → Sync Rules,可选择 `auto`、`custom` 或 `full`。
-- [`README.md`](../README.md):用户入口、平台示例和关键边界
-- [`CONTRIBUTING.md`](../CONTRIBUTING.md):自定义规则格式与修改说明
-- [`docs/README.md`](README.md):文档职责与阅读路径
-- [`docs/DEVELOPMENT.md`](DEVELOPMENT.md):环境、命令和开发流程
-- [`docs/STRUCTURE.md`](STRUCTURE.md):构建、产物、守卫和发布结构
-- [`docs/TROUBLESHOOTING.md`](TROUBLESHOOTING.md):常见失败与定位步骤
-- [`SECURITY.md`](../SECURITY.md):安全支持范围和私密报告
-- [`NOTICE`](../NOTICE) / [`THIRD_PARTY_NOTICES.md`](../THIRD_PARTY_NOTICES.md):许可范围与第三方状态
+构建失败时,先查看 Actions 日志中最早出现的错误。常见原因是规则格式错误、上游不可访问、上游条目数量异常或工具下载失败。
diff --git a/docs/README.md b/docs/README.md
deleted file mode 100644
index 8be4e47f3..000000000
--- a/docs/README.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# 文档索引
-
-本目录保存实现与维护文档;根目录 `README.md` 仍是规则使用入口。
-
-## 文档职责
-
-- [开发指南](DEVELOPMENT.md):受支持环境、工具依赖、本地命令和开发流程。
-- [仓库结构](STRUCTURE.md):同步、构建、审计文件、守卫和发布分支的真实边界。
-- [故障排查](TROUBLESHOOTING.md):按症状定位构建、产物与客户端问题。
-- [贡献指南](../CONTRIBUTING.md):自定义规则格式和修改说明。
-- [`NOTICE`](../NOTICE) 与 [第三方声明](../THIRD_PARTY_NOTICES.md):MIT 适用范围和第三方核对状态。
-- [安全政策](../SECURITY.md):安全问题与普通质量问题的分界及私密报告渠道。
-
-事实冲突时,以脚本、配置和工作流当前实现为准,并修正文档;许可结论只能由维护者基于可核验材料人工评审,不能从自动化结果推导。
-
-## 文档导航
-
-- [`README.md`](../README.md):用户入口、平台示例和关键边界
-- [`CONTRIBUTING.md`](../CONTRIBUTING.md):自定义规则格式与修改说明
-- [`docs/README.md`](README.md):文档职责与阅读路径
-- [`docs/DEVELOPMENT.md`](DEVELOPMENT.md):环境、命令和开发流程
-- [`docs/STRUCTURE.md`](STRUCTURE.md):构建、产物、守卫和发布结构
-- [`docs/TROUBLESHOOTING.md`](TROUBLESHOOTING.md):常见失败与定位步骤
-- [`SECURITY.md`](../SECURITY.md):安全支持范围和私密报告
-- [`NOTICE`](../NOTICE) / [`THIRD_PARTY_NOTICES.md`](../THIRD_PARTY_NOTICES.md):许可范围与第三方状态
diff --git a/docs/STRUCTURE.md b/docs/STRUCTURE.md
deleted file mode 100644
index 1b0025e84..000000000
--- a/docs/STRUCTURE.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# 仓库结构
-
-本文件描述同步、构建、守卫和发布实现,不承担客户端配置教程或许可结论。
-
-## 顶层职责
-
-| 路径 | 职责 |
-| --- | --- |
-| `sources/custom/` | 自有域名规则及可选 IP 规则 |
-| `config/` | 上游端点、首批健康基线、平台能力、自定义规则精确冲突关系和二进制工具 lock |
-| `scripts/commands/` | 同步、恢复、构建、守卫和发布入口 |
-| `scripts/lib/` | 下载、工具缓存和渲染共享函数 |
-| `scripts/tools/` | Python 解析、规范化、校验与摘要工具 |
-| `scripts/tests/`、`tests/fixtures/` | 自动测试与稳定夹具 |
-| `templates/branch-readmes/` | 发布分支 README 模板及随发布树携带的 v2fly MIT 充分通知 |
-| `.output/` | 构建产物及部分审计摘要 |
-| `.output/.canonical/` | 事务内保留的 domain/IP 规范编译输入,只用于跨平台语义校验,不进入发布分支 |
-| `.tmp/` | 可清理临时工作区 |
-| `.bin/` | 外部工具及版本缓存 |
-| `.artifacts/` | 失败构建保留的诊断摘要;属于可清理的本地/CI 数据,不进入发布分支 |
-
-## 构建范围
-
-完整范围依次同步主上游、写入 `.output/.canonical/`、构建自定义规则、执行产物守卫(artifact guard),再上传并发布。自定义范围从五个发布分支恢复同一发布 cohort;旧 cohort 没有 canonical 状态时先从 Egern 文本产物重建,再用本次自定义源覆盖相应规范输入并重建产物。工作流没有独立的 Fake-IP 同步步骤。
-
-`fakeip-filter` 当前源为本仓库维护的 `sources/custom/domain/fakeip-filter.list`,由 `build-custom.sh` 与其他自定义规则一起生成五平台形式,不从网络下载预编译文件。`config/upstreams.json` 覆盖主上游网络输入;工具资产下载另由工具 lock 控制。
-
-`main` 是唯一长期源码与发布源分支;日常修改可直接提交或使用临时分支。发布分支为 `surge`、`quanx`、`egern`、`sing-box`、`mihomo`,只允许生成的 `README.md`、`domain/`、`ip/` 及平台对应扩展名。各分支 `README.md` 由 `templates/branch-readmes/` 生成,并直接包含 v2fly/domain-list-community 的完整 MIT 版权与许可通知;因此发布树无需新增独立许可证文件。模板变更属于构建触发路径。
-
-## 审计文件
-
-- `.output/upstream-summary.json`:主同步在健康检查后记录名称、实际 URL、状态、回退、临时路径、原始与规范化内容的字节数、条目数和 SHA-256;DLC 另含检出的 commit。
-- `.output/domain/rule-manifest.json`:域名列表、区域集合和属性派生结构。
-- `.output/build-summary.json`:GitHub Actions 在产物守卫之后、规范发布清单之前扫描 `.output/` 生成。
-- `.output/.canonical/{domain,ip}/`:规范化、去重后的平台无关规则集合。它是五个平台语义验证的唯一比较基准;manifest 记录验证结果,但不会将该目录列为发布产物。
-- `.output/artifact-manifest.json`:schema v4 规范发布清单,包含 generation/build/source/build scope、完整发布基线(整体状态以及各分支 commit/generation/source)、能力与工具 lock 摘要、工具 provenance metadata、可用的上游/构建摘要,以及每个可发布 domain/ip 文件的平台、类型、扩展名、字节数、SHA-256 和可判定来源。JSON 键与产物按稳定顺序输出;generation/build id 由调用方提供,因此相同输入和 id 可复现相同内容。
-- `.tmp/**/normalize-tasks.json`:批处理任务描述,属于临时数据。
-- `.artifacts/diagnostics//`:失败事务保留的 `transaction-health.json` 及可用的构建/上游摘要;CI 日志只展示白名单内且大小受限的 JSON,完整诊断作为短期 Actions artifact 上传。
-
-`verify-artifact-manifest.sh` 严格重算能力矩阵允许的完整文件集合、路径层级与安全性、非零大小、字节数和 SHA-256,并核对能力/lock 摘要及可选的预期 source SHA。Surge、Quantumult X、Egern、sing-box 和 Mihomo 都会按各自能力过滤规则类型,再与 `.output/.canonical/` 比较等价语义集合;域名后缀覆盖和 CIDR 并集合并允许编译器消除冗余,但值替换、扩大或丢失范围会失败。缺少任一应有平台副本、存在没有 canonical 来源的额外产物,或为只含该平台不支持规则的空集合生成文件,同样失败。清单同时记录读回方法、计数和语义 SHA-256。
-
-发布作业下载后再次验证;`publish-branches.sh` 自身也必须先验证清单,拒绝缺失、额外、被修改或重放的产物。清单只作为流水线审计输入,不复制到发布分支。一次发布中五个分支提交携带共同 generation id 和 source SHA;任一平台 tree 改变时完整 cohort 原子推进并保留各分支父历史,全部 tree 不变时在重新读取远端 cohort 后整体跳过。自定义范围以最近一次一致发布 cohort 的 source 为累计比较基准,而不是只比较 `HEAD^`,因此连续的文档提交不会掩盖此前未发布的规则改动。候选 source/generation 不得早于远端基线;准备前、推送前和推送后均检查远端 `main`,五个产物 ref 使用带预期 SHA lease 的原子推送。Git 协议无法把未变化的 `main` ref 纳入同一次 compare-and-swap;若推送产物后发现 `main` 已前进,本次运行会明确失败,由当前 `main` 的排队运行继续推进。
-
-`scripts/tools/artifact_origins.py` 是 `artifact-origins.json` 的唯一写入口:完整同步重置为 `generated-upstream`,发布分支恢复重置为 `restored-published-branch`,自定义构建只重标本次控制且实际存在的目标,并清除对应平台已经删除或降级省略的旧记录。
-
-`config/domain-platform-capabilities.json` 是平台 branch、extension、format、rule mapping、empty policy、compiler 与 verifier 的唯一结构化来源。`scripts/tools/platform_capabilities.py` 严格加载并校验实现标识,同时向 Python 消费者提供查询对象、向 shell 消费者生成稳定的 tab-separated registry。IP 渲染、构建/守卫的安全循环、摘要和发布均查询该 registry;声明未知实现时构建会 fail closed。公开分支名仍由能力文件中的 `branch` 字段固定。
-
-`upstream-summary.json` 不是完整来源追溯记录:它不覆盖自定义源(包括 `fakeip-filter`)、全部转换步骤或 HTTP 响应身份。上述文件也都不是许可证证明。
-
-## 名称冲突检查
-
-`build-custom.sh` 根据 `RULES_CONFLICT_BASE_SHA`(可用时)或 `HEAD^` 判断自定义源是否为新增。只有新增源会检查五个平台当前 `.output/` 中同类型目标是否已经存在:domain 只对 domain,ip 只对 ip。
-
-因此该检查不覆盖既有自定义源修改、未出现在当前 `.output/` 的潜在未来上游名称,也不禁止 domain 与 ip 使用同一名称。它是防覆盖措施,不是全局命名守卫。
-
-共享解析器先验证 canonical 类型和值,并检查同一自定义文件内的重复或覆盖关系。不同文件允许按策略需要有意重叠。`build-custom.sh` 在生成产物前运行该阶段。
-
-## 产物守卫(artifact guard)范围
-
-当前产物守卫(artifact guard)包括:
-
-- 五个平台 domain 和 ip 的最低文件数量;
-- 五个平台冗余域名属性派生文件名;
-- 基线分支可用且未命中特定兼容跳过条件时,Surge、Quantumult X、Egern 文本域名规则相对发布分支的下降检查;
-- Surge 和 Quantumult X 文本 IP 的地址族及非 `private` 非公网 CIDR 检查;
-- 两个平台部分内置 IP 集的总数与 IPv4/IPv6 最低值;
-- Surge 上部分内置 IP 集相对基线的增长或删除检查。
-
-artifact guard 本身不执行五平台 canonical 语义比较;该检查由随后生成和复验 manifest 的阶段执行,其中 `.srs` / `.mrs` 使用锁定工具真实读回。两者都不审查许可。发布脚本另行检查发布树、扩展名和本地产物完整性。
-
-## 工具缓存与清理
-
-sing-box 和 mihomo 只按 `config/tools-lock.json` 固定版本、tag commit 和 Linux `amd64` / `arm64` 资产下载到 `.bin/`。归档解包前必须匹配 lock 中的 SHA-256。每个缓存二进制都有原子替换的 provenance sidecar,记录 lock commit、资产与归档摘要、二进制摘要和版本探针;命中缓存时会重新核对 sidecar 的完整字段、二进制 SHA 和实时版本输出,不可信缓存会被重新下载替换。工作流缓存键以缓存格式版本开头,并包含两个工具版本、平台和 lock 摘要。该校验是 GitHub release asset digest 锁定,不是发布者签名。`make clean` 保留可信工具缓存,只移除未完成下载与 metadata 临时文件、生成产物、临时目录和 Python 缓存。
-
-## 文档导航
-
-- [`README.md`](../README.md):用户入口、平台示例和关键边界
-- [`CONTRIBUTING.md`](../CONTRIBUTING.md):自定义规则格式与修改说明
-- [`docs/README.md`](README.md):文档职责与阅读路径
-- [`docs/DEVELOPMENT.md`](DEVELOPMENT.md):环境、命令和开发流程
-- [`docs/STRUCTURE.md`](STRUCTURE.md):构建、产物、守卫和发布结构
-- [`docs/TROUBLESHOOTING.md`](TROUBLESHOOTING.md):常见失败与定位步骤
-- [`SECURITY.md`](../SECURITY.md):安全支持范围和私密报告
-- [`NOTICE`](../NOTICE) / [`THIRD_PARTY_NOTICES.md`](../THIRD_PARTY_NOTICES.md):许可范围与第三方状态
diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md
deleted file mode 100644
index 793f14976..000000000
--- a/docs/TROUBLESHOOTING.md
+++ /dev/null
@@ -1,86 +0,0 @@
-# 故障排查
-
-先处理日志中最早的错误,并对照 [开发指南](DEVELOPMENT.md) 的环境边界。
-
-## `make validate` 失败
-
-- `shellcheck not found`:本地默认可跳过,CI 强制要求;安装后重试。
-- Python 编译失败:确认 `python3 --version` 为 3.11 或更高版本,再修复首个语法错误。
-- 配置失败:检查 HTTPS URL、正整数阈值、必需项和支持的枚举。
-- 自定义规则失败:处理非 canonical 类型/值、同文件内的 domain 精确项/后缀覆盖、IP 重复/包含、正则或 CIDR 规范问题。不同文件之间允许按策略需要重叠。
-- 测试失败:运行 `bash scripts/tests/test-*.sh` 中对应的脚本,再检查夹具是否应有意更新。
-
-## `make check-runtime` 失败
-
-本地命令要求 `PATH` 解析到 Bash 5+ 和 Python 3.11+。macOS 应优先使用 Homebrew 安装的版本;若 `python@3.11` 已安装但仍解析到系统 Python,把 `$(brew --prefix python@3.11)/libexec/bin` 放到 `PATH` 前部。分别运行 `bash --version`、`python3 --version` 和 `command -v bash python3`,确认没有落回系统旧版本。
-
-若错误提示 `cross-device artifact promotion refused` 或 `cross-device rename refused`,应把 `RULES_LIVE_ARTIFACT_ROOT` 改到仓库所在文件系统。事务的预检与最终严格 rename 都不会通过跨设备复制模拟原子目录提升。若日志提示 `transaction recovery data preserved`,不要删除所示目录;其中的 `previous-output` 是自动恢复失败后保留的旧 live tree。
-
-## 原生 Windows 构建失败
-
-sing-box/mihomo 下载逻辑会在需要获取新工具时拒绝原生 Windows。请使用 WSL、Linux 或 GitHub Actions。Git Bash 不属于完整支持环境,不能因文本目标偶尔可运行而推断二进制构建受支持。
-
-## 文本成功但二进制失败
-
-`make build-custom-text` 不下载编译器。检查网络、GitHub Release 可用性、`amd64` / `arm64` 架构和 `.bin/` 缓存后运行:
-
-```bash
-make build-custom
-```
-
-若日志报告 checksum mismatch,停止并核对 `config/tools-lock.json` 与官方 GitHub Release 资产,不要绕过校验。缓存命中还会检查 provenance sidecar、二进制 SHA-256 和版本探针;校验失败时会自动重新下载。该机制验证固定资产摘要,但不等同于发布者签名。
-
-## `make clean` 后工具仍存在
-
-这是预期行为。清理会删除 `.tmp/`、`.output/`、`.artifacts/`、Python 缓存及 `.bin/*.new*`,但保留已缓存的 sing-box、mihomo 和 provenance sidecar。若需要强制重新下载,应人工删除对应二进制及其 `.provenance.json`;不要提交 `.bin/`。
-
-## 自定义名称冲突
-
-冲突检查只针对相对基准新加入的自定义源,并在同一 domain/ip 类型内检查当前 `.output/` 的五平台目标。报错时重命名新增规则,不要删除恢复或同步得到的产物。
-
-既有自定义源修改、domain 与 ip 同名、当前产物中尚不存在的未来上游名称不在同一检查范围内,仍需人工审查。
-
-## `emby-cn` 未按预期命中
-
-确认 `emby-cn` 位于 `emby` 之前,并绑定不同策略;反向加载会让宽泛规则先命中。
-
-## 上游同步或条目异常
-
-1. 对照 `config/upstreams.json` 检查主 URL、回退、解析器和阈值。
-2. 成功事务查看 `.output/upstream-summary.json`;失败事务查看 `.artifacts/diagnostics//` 中保留的 upstream/transaction health 报告。失败时 `.output/` 仍是事务开始前的完整树,不会包含部分下载、渲染或编译结果。
-3. 成功后查看 `.output/domain/rule-manifest.json` 定位属性派生。
-4. 对照基线和发布分支判断变化是否预期。
-
-CI 的失败事务会把 `.artifacts/diagnostics/` 上传为保留 7 天的 diagnostics artifact。若日志被截断,优先下载对应 artifact;仅文档或治理文件的 PR 不运行外部上游同步。
-
-该摘要不包括本仓库维护的自定义源(包括 `sources/custom/domain/fakeip-filter.list`),也没有完整转换链或 HTTP 响应身份,不能单独作为完整来源追溯记录或许可依据。`fakeip-filter` 应由 `build-custom.sh` 生成;若日志出现独立同步或预编译下载,应视为回归。
-
-## 找不到 `build-summary.json`
-
-独立运行 `make build-custom*` 不生成它;请运行 `build-artifacts-transaction.sh`。成功事务会在产物守卫之后、manifest 之前生成并绑定该摘要。工作流的 `Show summary` 只显示成功输出,或在失败诊断时临时生成可读摘要;失败时 `.output/` 仍保留上一次成功事务。
-
-## 产物守卫(artifact guard)阻断
-
-检查最低文件数、冗余派生名、文本域名下降、Surge/Quantumult X 文本 IP 合法性和部分内置 IP 基线。随后 manifest 阶段会解析或真实读回五个平台产物,并与 `.output/.canonical/` 中的平台无关规范规则集合精确比较。只有在来源证据、测试和评审说明齐全时才调整阈值。
-
-## 许可状态不明
-
-自动化不会发现或阻断许可问题。停止相关内容的合并或发布,由维护者对照 `NOTICE`、`THIRD_PARTY_NOTICES.md`、上游许可证和条款人工评审。CI 通过不构成授权。
-
-## 客户端问题
-
-- 404:核对分支、domain/ip 类型、规则名和固定扩展名。
-- Quantumult X 策略不存在:用 `filter_remote` 的 `force-policy` 绑定本地策略。
-- mihomo 缺少 domain `.mrs`:只有关键词或正则的列表会因当前降级边界而不发布。
-- 内容未更新:检查发布分支提交、工作流状态和客户端缓存周期。
-
-## 文档导航
-
-- [`README.md`](../README.md):用户入口、平台示例和关键边界
-- [`CONTRIBUTING.md`](../CONTRIBUTING.md):自定义规则格式与修改说明
-- [`docs/README.md`](README.md):文档职责与阅读路径
-- [`docs/DEVELOPMENT.md`](DEVELOPMENT.md):环境、命令和开发流程
-- [`docs/STRUCTURE.md`](STRUCTURE.md):构建、产物、守卫和发布结构
-- [`docs/TROUBLESHOOTING.md`](TROUBLESHOOTING.md):常见失败与定位步骤
-- [`SECURITY.md`](../SECURITY.md):安全支持范围和私密报告
-- [`NOTICE`](../NOTICE) / [`THIRD_PARTY_NOTICES.md`](../THIRD_PARTY_NOTICES.md):许可范围与第三方状态
diff --git a/scripts/commands/guard-artifacts.sh b/scripts/commands/guard-artifacts.sh
index 86cc8a473..8588715d3 100755
--- a/scripts/commands/guard-artifacts.sh
+++ b/scripts/commands/guard-artifacts.sh
@@ -156,7 +156,7 @@ check_no_redundant_attr_filter_artifacts() {
while IFS=$'\t' read -r platform _public _branch section _extension _format _empty _compiler _verifier; do
[ "$section" = domain ] || continue
check_no_redundant_attr_filter_artifacts_in_dir "$ARTIFACT_ROOT/domain/$platform" "domain/$platform"
- done < <(capability_registry)
+ done <<< "$CAPABILITY_REGISTRY"
}
count_domain_rules_from_file() {
@@ -538,7 +538,7 @@ main() {
while IFS=$'\t' read -r platform _public _branch section extension _format _empty _compiler _verifier; do
if [ "$section" = domain ]; then min_expected=1000; else min_expected=10; fi
check_min_files "$ARTIFACT_ROOT/$section/$platform" "$ARTIFACT_ROOT/$section/$platform/*.${extension}" "$min_expected"
- done < <(capability_registry)
+ done <<< "$CAPABILITY_REGISTRY"
# Minimum 10 covers the guaranteed sources:
# cn, private, google, telegram, cloudflare, cloudfront, aws, fastly, github, apple.
# Streaming services (netflix, spotify, disney) are best-effort via RIPE NCC
diff --git a/scripts/commands/publish-branches.sh b/scripts/commands/publish-branches.sh
index e4cbfab6d..4d0416ccd 100755
--- a/scripts/commands/publish-branches.sh
+++ b/scripts/commands/publish-branches.sh
@@ -14,8 +14,7 @@ CAPABILITY_REGISTRY="$(python3 "$ROOT/scripts/tools/platform_capabilities.py" sh
PUBLISH_BRANCH_NAMES=(surge quanx egern sing-box mihomo)
ARTIFACT_SOURCE_SHA="${ARTIFACT_SOURCE_SHA:-}" "$ROOT/scripts/commands/verify-artifact-manifest.sh"
-read -r MANIFEST_GENERATION_ID MANIFEST_SOURCE_SHA MANIFEST_BASELINE_STATUS MANIFEST_BASELINE_SOURCE < <(
- python3 - <<'PY' "$MANIFEST_FILE"
+manifest_identity="$(python3 - <<'PY' "$MANIFEST_FILE"
import json, sys
manifest = json.load(open(sys.argv[1], encoding="utf-8"))
print(
@@ -25,7 +24,8 @@ print(
manifest["baseline"]["source_commit"] or "-",
)
PY
-)
+)"
+read -r MANIFEST_GENERATION_ID MANIFEST_SOURCE_SHA MANIFEST_BASELINE_STATUS MANIFEST_BASELINE_SOURCE <<< "$manifest_identity"
refresh_and_validate_remote_baseline() {
local metadata_file branch commit subject generation source
@@ -221,7 +221,9 @@ has_allowed_extension() {
assert_branch_layout() {
local domain_extensions="$1"
local ip_extensions="$2"
- local file rel
+ local file rel file_list
+ file_list="$(mktemp)"
+ find domain ip -type f -print0 > "$file_list"
[ -f "README.md" ] || {
echo "missing publish file: README.md" >&2
@@ -246,7 +248,8 @@ assert_branch_layout() {
fi
echo "unexpected file in publish tree: $rel" >&2
exit 1
- done < <(find domain ip -type f -print0)
+ done < "$file_list"
+ rm -f "$file_list"
}
cleanup_tempdir() {
diff --git a/scripts/commands/select-build-scope.sh b/scripts/commands/select-build-scope.sh
index db8c36b3c..7eb78b8be 100755
--- a/scripts/commands/select-build-scope.sh
+++ b/scripts/commands/select-build-scope.sh
@@ -159,13 +159,13 @@ load_publication_baseline() {
if [ "$baseline_loaded" -eq 1 ]; then
return 0
fi
+ local baseline_values
if [ -n "$BASELINE_INPUT_FILE" ]; then
- read -r baseline_status baseline_generation baseline_source < <(
- validate_and_write_baseline "$BASELINE_INPUT_FILE" "$BASELINE_FILE"
- )
+ baseline_values="$(validate_and_write_baseline "$BASELINE_INPUT_FILE" "$BASELINE_FILE")"
else
- read -r baseline_status baseline_generation baseline_source < <(resolve_remote_baseline)
+ baseline_values="$(resolve_remote_baseline)"
fi
+ read -r baseline_status baseline_generation baseline_source <<< "$baseline_values"
baseline_loaded=1
echo "Publication baseline: status $baseline_status, generation $baseline_generation, source $baseline_source"
@@ -222,7 +222,7 @@ has_build_relevant_changes() {
}
has_only_non_build_changes() {
- ! grep -Eqv '^(\.github/(CODEOWNERS$|ISSUE_TEMPLATE/|dependabot\.yml$|pull_request_template\.md$)|\.gitignore$|CONTRIBUTING\.md$|LICENSE$|NOTICE$|README\.md$|SECURITY\.md$|THIRD_PARTY_NOTICES\.md$|docs/)'
+ ! grep -Eqv '^(\.gitignore$|LICENSE$|NOTICE$|README\.md$|THIRD_PARTY_NOTICES\.md$|docs/)'
}
if [ "$EVENT_NAME" != "pull_request" ]; then
diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh
index 4f3602562..1816fa2a6 100644
--- a/scripts/lib/common.sh
+++ b/scripts/lib/common.sh
@@ -199,8 +199,8 @@ tool_cache_is_trusted() {
archive_sha="$(tool_lock_value "$tool" sha256 "$platform")"
locked_binary_sha="$(tool_lock_value "$tool" binary_sha256 "$platform")" || return 1
- if ! IFS=$'\t' read -r binary_sha recorded_probe < <(
- python3 - "$sidecar" "$tool" "$version" "$tag_commit" "$platform" "$asset" "$archive_sha" <<'PY'
+ local provenance_values
+ if ! provenance_values="$(python3 - "$sidecar" "$tool" "$version" "$tag_commit" "$platform" "$asset" "$archive_sha" <<'PY'
import json
import re
import sys
@@ -232,9 +232,10 @@ try:
except (OSError, KeyError, TypeError, ValueError, json.JSONDecodeError):
raise SystemExit(1)
PY
- ); then
+ )"; then
return 1
fi
+ IFS=$'\t' read -r binary_sha recorded_probe <<< "$provenance_values"
actual_sha="$(sha256_file "$binary")"
[ "$actual_sha" = "$locked_binary_sha" ] || return 1