内容
# SpecDrift
确定性规范检查,用于基于清单的黄金路径。
黄金路径的存活与否取决于一个承诺:**清单是唯一的真实来源。**
模式验证清单的形状,而静态分析器保护代码 — 但没有人检查清单与其他产物之间的空间,即清单说X,仓库做Y的地方。这种差距正是AI生成的更改腐烂的地方。SpecDrift是针对该差距的检查层,它故意设计得非常枯燥:**它从不调用LLM — LLM调用它。**
```bash
dotnet tool install -g SpecDrift
SpecDrift validate .platform/manifest.yaml --schema manifest.schema.json --rules rules.yaml
```
## 在任何地方运行
| 方式 | 一行命令 |
|---|---|
| .NET 工具 | `dotnet tool install -g SpecDrift` |
| Docker(任何栈) | `docker run --rm -v "$PWD:/work" -w /work ghcr.io/qorpe/specdrift:0.4.1 <参数>` |
| GitHub Actions | `- uses: qorpe/specdrift@v0.4.1` with `args:` |
| MCP 服务器(代理) | `docker run --rm -i ghcr.io/qorpe/specdrift:0.4.1 mcp` — stdio 工具 `spec_validate`、`spec_drift` |
镜像支持多架构(amd64 + arm64)。引擎是通用的:模式、规则和偏移配置文件是**数据** — 指向任何仓库、任何语言。
## 它做什么(v1)
- **`validate`** — YAML/JSON 清单的 JSON-Schema 验证 **以及您声明的跨字段不变性** (`rules.yaml`):当此路径包含该值时,必须存在另一个路径。每个发现都有一个规则 ID、严重性和一条教导修复的消息。输出:人类文本或 `--format json`;退出代码是合约(0 clean · 1 findings · 2 usage/IO)。
模式评估是**树内、无依赖评估器**,适用于实际使用的 2020-12 子集清单(`type · enum · const · required · properties · additionalProperties · unevaluatedProperties · oneOf/anyOf/allOf/not · if/then/else · $ref(#/…) · pattern · min/maxLength · min/maximum · items · uniqueItems · min/maxItems`)。未知的断言关键字是**硬失败** — 引擎永远不会猜测。报告默认无噪音:失败的 `if` 仅取消其分支,失败的 `oneOf` 在决策点产生**一个**发现,而不是每个替代方案一个。(为什么是树内:每个候选库都失败了该项目自己的关卡 — 有一个附带维护费的 EULA,其 NuGet 二进制文件,一个在运行时编译代码,一个静默跳过 `if/then`。)
- **`drift`** — 清单 ↔ 仓库现实,由偏移配置文件(`.specdrift/drift.yaml`)驱动:一个功能启用时,其包或线路调用缺失(每个方向都有自己的发现 — 包括“引用但未启用”),已提交的 API 文档在语义上与已构建的文档不同,以及清单模式版本偏差。检测**按文本**设计,并说明这一点;报告永远不会自动修复。
```yaml
# .specdrift/drift.yaml
version: 1
manifest: .platform/manifest.yaml
schemaVersion: 1
wiring:
- feature: features.outbox
package: Platform.Messaging
call: AddPlatformOutbox
- feature: providers.auth # 值门控线路
equals: openid
package: Platform.Auth
call: AddPlatformAuth
openapi:
- committed: specs/openapi.json
built: artifacts/openapi.json
```
- **`mcp`** — 相同的两个动词通过 stdio MCP 提供(`spec_validate`、`spec_drift`),因此编码代理询问引擎而不是猜测。像任何 stdio 服务器一样注册它:
```json
{ "mcpServers": { "SpecDrift": { "command": "SpecDrift", "args": ["mcp"] } } }
```
## 配置文件是数据,引擎是通用的
SpecDrift 不了解任何特定平台。模式、 invariant 规则和(即将推出的 `drift`)线路表是**配置文件数据**,每个黄金路径都在其自己的仓库中提供:
```yaml
# rules.yaml
version: 1
rules:
- id: SPEC0101
description: L2 缓存需要 Redis 连接名称
when: { path: features.distributedCaching.levels, op: contains, value: l2 }
require: { path: features.distributedCaching.redis.connectionName }
severity: error
message: "features.distributedCaching.levels 包括 'l2' 但 redis.connectionName 缺失 - 命名缓存应使用的连接。"
```
支持的 `when` 操作:`exists`、`equals`、`contains`(数组成员或子字符串)。约束:`require`(路径必须存在且非空)和 `forbid`(路径必须不存在)。没有 `when` 的规则无条件应用。
## 确定性合约
- 相同的输入 → 字节相同的报告。无网络、无时钟在输出中、无 LLM。
- 未知的清单模式版本是**硬失败** — 引擎永远不会猜测。
## 许可证
MIT。