OpenCnid/weir-rule-language

GitHub: OpenCnid/weir-rule-language

对 Automattic/harper 语法检查器进行逆向工程分析的文档项目,重点剖析其声明式规则语言 Weir 的设计演进与架构密度链。

Stars: 0 | Forks: 0

weir-rule-language: five boxes tracing harper's abstraction ladder from hand-written Rust to a distributable rule pack, the imperative bars shrinking as the declarative bars grow *当一个项目花费两年时间,去缩短“我知道这条规则”与“引擎知道它”之间的距离时,会发生什么。* [![主题](https://img.shields.io/badge/subject-Automattic%2Fharper-b31b1b?logo=github&logoColor=white)](https://github.com/Automattic/harper) [![许可证](https://img.shields.io/badge/license-CC_BY_4.0-3b7ddd)](LICENSE.md) ![已读提交](https://img.shields.io/badge/commits_read-4%2C460-58a6ff) ![已读 PR](https://img.shields.io/badge/pull_requests_read-2%2C266-9b8cf7) ![无定位符声明](https://img.shields.io/badge/claims_without_locators-0-2ea44f) ![凭记忆写出的数字](https://img.shields.io/badge/numbers_from_memory-0-2ea44f) ![已执行代码](https://img.shields.io/badge/code_executed-none_(on_purpose)-ef6fd0)
## 为什么这个代码库以一种规则语言命名 我们着手回答一个问题 —— *harper 对 [Trellis](https://github.com/OpenCnid) 有用吗,以何种形式?* —— 并且我们拒绝仅凭 README 来回答它。因此,我们根据项目自身的记录对它进行了逆向工程:**4,460 次提交,2,266 个 pull request,226 个发布,135 位作者,时间跨度从 2023 年 10 月到 2026 年 7 月。** 答案最终并不是“语法检查器”,而是 **Weir**。 Weir 是 harper 的声明式规则语言,诞生于 2026-01-12 的提交 `46f4547f`。一条规则就是一个文件: ``` expr main (a couple of more) let message "The correct wording is `a couple more`, without the `of`." let description "Corrects `a couple of more` to `a couple more`." let kind "Redundancy" let becomes "a couple more" test "There are a couple of more rules that could be added, how can I contribute?" "There are a couple more rules that could be added, how can I contribute?" ``` 这就是全部内容。匹配、元数据、修复 —— **以及它的测试,都在同一个产物中。** 一个构建脚本会扫描目录并生成注册表;一个生成的测试框架(harness)会运行每个已发布规则的断言,而无需任何人维护测试文件。在六个月内,**所有添加规则的提交中有 42.6% 选择使用 Weir,而不是手写的 Rust。** 有趣的是,同样的设计使得诚实检查成为可能。我们对此进行了测量:**351 条规则中有 64 条完全没有提供断言,而生成的测试依然通过了。** 一个自我测试的产物需要在*注册时*就设定最低底线,而不仅仅是一个运行器。这个发现对我们来说,远比它的语法检查功能更有价值。 ## 阶梯 Weir 并非凭空出现。它是整个项目历史中最清晰发展轨迹的第四级阶梯: | 阶梯 | 诞生时间 | 发生了什么改变 | |---|---|---| | 手写 Rust | `309d840e`, 2024-01-15 | 每条规则都是一个定制的扫描器 | | `Pattern` | `6107594e`, 2024-09-01 | 一个封闭的匹配器代数;规则声明一种形状 | | `Expr` | `a8fb0c6d` (#1393), 2025-06-13 | 匹配返回的是一个 **`Span`** 而不是长度 —— 因此一次遍历就可以服务于 279 个规则文件 | | **Weir** | `46f4547f` (#2357), 2026-01-12 | 规则变成了**数据**,携带其自身的测试 | | **Weirpack** | `3a5cd68b` (#2491), 2026-02-03 | 规则*集合*变成了一个**可分发单元** —— 包含清单、规则以及可选字典 | 每一级阶梯依然建立在下一级的基础之上。没有任何东西被替换 —— 而[这种不替换本身就是一个发现](docs/density-chain/DENSITY-CHAIN.md#c2)。 ## 这里面有什么 | 路径 | 它是什么 | |---|---| | **[`docs/density-chain/DENSITY-CHAIN.md`](docs/density-chain/DENSITY-CHAIN.md)** | **地图。** 一条主干加上九条分支,每条分支都是五个层级的密度链条。共 16,000 字,解决了每一个声明。 | | [`docs/density-chain/DENSITY-CHAIN.html`](docs/density-chain/DENSITY-CHAIN.html) | 同样的内容,渲染后的版本 —— 支持主题、独立完整、无外部请求 | | [`findings/`](findings/) | 五项技能输出,按运行顺序排列:SPARK 诊断、子代理组合、评审团、复杂性大会 | | [`findings/branches/`](findings/branches/) | 九位绘图者的返回结果,未经编辑 | ## 方法,用一段话概括 九个只读的子代理,每个负责一个子系统类别,它们从一个逐字节相同的 ground block 和严格的五层返回框架中并行生成。它们谁也无法看到彼此的输出。每一个子代理必须在**每一个**定量声明中附带 `path:line`(路径:行号)、提交 SHA 或 PR 编号,必须填充 `## Uncovered` 字段以确保缺陷不会在沉默中被掩盖,并且被禁止运行 `cargo`、`pnpm`、`just` 或 `npm`。主干和交叉链接是在事后由 orchestrator 组合而成的,因为一个同级子系统去推测它无法看到的类别,恰好会产生这种规则纪律旨在防止的、无法协调的声明。 总运行量:**1,283,821 个 token,558 次工具调用,执行了零行 harper 代码。** ## 我们发现的 harper 维护者可能会关心的问题 作为观察结果提供,而不是作为补丁 —— 关于我们为什么没有提交 issue,请参阅 [`AGENTS.md`](AGENTS.md)。 每一项的日期均为 2026-07-23/24,均源自于阅读代码,而不是来自执行出的反例: - **`PatchCriteria::WordIs` 在压缩字符时没有进行长度检查**,使其变成了一个前缀匹配 —— 并且已发布的 tagger 模型中 201 个补丁里有 158 个都要经过它。([C6](docs/density-chain/DENSITY-CHAIN.md#c6)) - **`statsPath` 被赋值给了 `base.file_dict_path`**,因此统计信息的位置从来都是无法设置的,而且错误提示至今依然写着 "fileDict"。([C8](docs/density-chain/DENSITY-CHAIN.md#c8)) - **`WordId` 使用有损的 64 位大小写折叠哈希作为字典的键**,因此规范拼写遵循“后来居上”原则。(已知问题:issue #2411。)([C5](docs/density-chain/DENSITY-CHAIN.md#c5)) - **`harper-desktop/.github/workflows/` 位于仓库根目录之下**,因此 Actions 从未读取过它 —— 并且它还调用了两个不存在的配方(recipes)。([C8](docs/density-chain/DENSITY-CHAIN.md#c8)) - **同一个 crate 中存在两个 TLD 表**,分别包含 15 和 106 个条目。([C1](docs/density-chain/DENSITY-CHAIN.md#c1)) ## 想要 harper?只需一条命令,直接从源码获取 我们不托管他人的代码: ``` git clone https://github.com/Automattic/harper.git ``` 或者直接使用它 —— [writewithharper.com](https://writewithharper.com)。 ## 引用人类,而不是我们 ``` @misc{adams2023sparsedense, title = {From Sparse to Dense: {GPT-4} Summarization with Chain of Density Prompting}, author = {Adams, Griffin and Fabbri, Alex and Ladhak, Faisal and Lehman, Eric and Elhadad, No{\'e}mie}, year = {2023}, eprint = {2309.04269}, archivePrefix = {arXiv}, primaryClass = {cs.CL}, url = {https://arxiv.org/abs/2309.04269} } @software{harper, title = {Harper: Offline, privacy-first grammar checker}, author = {Potter, Elijah and {The Harper Contributors}}, year = {2026}, url = {https://github.com/Automattic/harper}, note = {Apache-2.0} } ``` ## 诚实的说明 - **没有执行任何代码。** 所有的测试计数都是对源码中 `#[test]` 属性或 `test` 行的统计 —— *而不是一次实际的绿色通过运行*。上面指出的每一个缺陷都是通过阅读代码得出的。 - **可达性是工作空间范围的。** “没有非测试调用者”是指在 harper 自己的 workspace 内没有调用者。 - **T5 记录的是请求,而不是承诺。** 一个开放的 PR 意味着有人提出了需求,而不是维护者已经同意。 - **这是快速移动目标的快照。** Harper 每月大约合并 60 个 PR。“前沿”部分衰减得最快;有些可能已经过时了。锁定版本为 `efa59c33`,于 2026-07-24 验证。 - **由人类和 AI 共同撰写。** 阅读、计数和起草工作由 Claude 在 [OpenCnid](https://github.com/OpenCnid) 的指导下完成;而提出的问题、设定的范围以及关于什么才是重要的判断,均归于所有者。如果地图有误,那是我们的责任去修复。
*两年的提交,一种规则语言,以及一个无需提出任何要求就能通过 64 次的测试套件。*
标签:VPS部署, 云计算, 可视化界面, 多模态安全, 架构分析, 规则引擎, 语法检查, 软件分析, 防御加固