# Evo Contract DSL reference

Evo Contract 是面向“版本演进推理”的轻量文本格式。它刻意保持行式语法，便于代码审查、生成 fixture 和嵌入 MoonBit/Wasm 应用。

## 文档结构

```text
contract <contract-name> <version>

type <object-name> <open|closed>
field <field-name> <type> <required|optional> [constraint=value ...]
end
```

- 一份文档只能有一个 `contract` 头；
- 至少声明一个 `type`；
- `type` 名称在文档中唯一；
- `field` 名称在所属类型中唯一；
- `#` 后内容为注释；
- 允许空行、LF 和 CRLF 换行。

标识符以 ASCII 字母或下划线开头，后续可包含字母、数字、下划线和连字符。

## 对象开放性

```text
type Event open
```

开放对象接受未声明字段。它适合可扩展事件元数据，但字段删除后仍可能被静默接受。

```text
type Command closed
```

封闭对象拒绝未声明字段。它适合严格协议，但新增生产者字段可能破坏旧消费者的向前兼容性。

从 `open` 变为 `closed` 会缩小可接受输入集合，因此在相同数据方向上属于破坏性变化。

## 字段类型

| 写法 | JSON 值 | 说明 |
|---|---|---|
| `string` | 字符串 | 长度按 Unicode 字符计数 |
| `int` | 无小数的 JSON number | 支持 `min`、`max` |
| `number` | JSON number | 支持 `min`、`max`；边界目前用整数表示 |
| `bool` | `true` / `false` | 无额外约束 |
| `enum:a|b` | 字符串 | 值只能含字母、数字、`_`、`-`、`.` |
| `ref:User` | 对象 | 引用同一契约内的类型 |
| `list:string` | 数组 | 同质列表，支持长度约束 |
| `list:ref:User` | 对象数组 | 每项递归校验引用类型 |

引用可以指向后面声明的类型，也允许递归。解析完成后会统一检查悬空引用。

## 存在性

```text
field id string required
field note string optional
```

`required` 表示字段必须存在；`optional` 表示可以省略。可选字段变为必填字段会拒绝省略该字段的旧数据。

## 约束

```text
field count int required min=0 max=100
field title string required minlen=1 maxlen=80
field tags list:string optional maxlen=16
field locale string optional default=zh-CN
```

- `min`、`max` 仅用于 `int` 和 `number`；
- `minlen`、`maxlen` 仅用于 `string` 和 `list`；
- 最小值不得大于最大值；
- `default` 是迁移与文档提示，不改变输入是否有效；
- 同一约束重复出现时，后值覆盖前值；建议生成器避免重复。

提高最小值或降低最大值会缩小输入集合。分析器会从被排除的边界中选择最小反例。

## 完整示例

```text
# Inventory event contract
contract Inventory 3.0.0

type Location closed
field aisle string required minlen=1 maxlen=8
field shelf int required min=0
end

type StockEvent open
field event_id string required minlen=8
field kind enum:received|reserved|released required
field quantity int required min=1
field location ref:Location required
field labels list:string optional maxlen=12
end
```

## 诊断稳定性

解析错误包含 `line`、`column`、`code`、`message` 和 `source_line`。错误码是公开兼容面：

- `E001`–`E018`：文档结构；
- `E020`–`E029`：字段和约束语法；
- `E030`–`E035`：类型表达式；
- `E040`–`E043`：约束语义；
- `E050`：引用完整性。

同一 0.x 次版本内不会无故改变已有错误码的含义。
