forked from bai/curriculum-project-hub
docs(spec): 重写 spec/ 与根 README 的语言与取舍
按新文风(简洁书面中文)重写 spec/ 全部 Lean doc 注释、spec/README, 并顺根 README。核心:讲清产品逻辑、去伪术语、去 ADR 黑话、DRY。 语言:砍钉死/留痕/实现侧/将就/脑补/刻意等伪术语;短句;不复述文件系统 能看到的东西;typst 考据移出 spec 指向 ADR。 内容取舍(动结构): - System 层大改:删 can_mono 形式化定理、Capability 9 项枚举与 requiredRole 映射、RunState 6 构造子;Audit.lean 删除并入 System 顶部。 Hub 未建的部分一律 prose 占位,只留 Lock 的 owner=run 与 WellFormed。 - 澄清两个"检查":产品 checker(LLM 判不了合法性,checker 真跑工具补这块) vs 开发时 spec↔impl 一致性检查(无自动闸门)。Oracle 重新定位为 "checker 得委托外部工具才能判的事实",不是"Lean 没写形式化"。 - spec/README 补取舍判据 checklist(自顶向下逐步细化、不在 Lean 里验证实现)。 - 根 README 去 DRY:删硬编码版本号、cache 路径细节;宪法第 3 条吸收 "人/coding assistant 核对"修正;第 5 条与 spec/README 判据去重。 保留:Export/Render 执行语义、Info 的 raw→canonical 设计模式(产品语义, 只顺文风不砍结构);renderIgnoredSeverity(实现对齐依赖)。 lake build 通过(24 jobs)。 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+54
-35
@@ -1,55 +1,74 @@
|
||||
# spec —— Lean 语义母本
|
||||
# spec —— 语义契约
|
||||
|
||||
这是本 monorepo 的**契约**:产品各部件语义的上游参照,用 Lean 编写。它的定位与约束见仓库根 `README.md` 的"宪法"5 条——本文件只讲**怎么往这份契约里写东西**。
|
||||
## 这个项目在解决什么
|
||||
|
||||
## 现状
|
||||
教研产出现在是一摞一次性的文档:写完就躺着,改一次要同步很多地方,没法校验、
|
||||
没法复用、没法追溯。这个项目想把教研产出变成可校验、可复用、能派生多种成品
|
||||
(讲义、教案、课件、归档)的工程化文件。
|
||||
|
||||
刚初始化的 Lean 工程(`lake init`),目前只有占位内容(`Spec/Basic.lean`)。实质领域内容(System 平台层、Courseware 产品层)将逐个概念加入,每个都遵循下面的规范。
|
||||
但光有工程文件还不够。它要变成一个能卖钱的产品,还得:
|
||||
|
||||
## 构建
|
||||
- 工程文件这种形式,正好适合现在大热的 LLM assistant 来改,从而提效;
|
||||
- 但 LLM 判不了一节课合不合法(它不能真去跑 typst 编译器、不能可靠地断言数据合不合
|
||||
schema),所以产品里还有一个 rule-based checker:它真跑工具、给确定性的诊断,补上
|
||||
LLM 判不了的这块。LLM 提效 + checker 兜底,两者一起才是完整的产品闭环。
|
||||
- 加上一些提升体验的小功能:飞书/企业微信集成、自动化提醒之类;
|
||||
- 如果要做 SaaS,还要有基本的管理概念:权限、LLM API 的配置和用量、费用等。
|
||||
|
||||
```sh
|
||||
cd spec
|
||||
lake build
|
||||
```
|
||||
工程文件是起点,不是终点。
|
||||
|
||||
工具链锁定在 `lean-toolchain`(`leanprover/lean4:v4.31.0`)。无外部依赖——Mathlib / Batteries 等留待第一个真正需要它的定理出现时再引入(依赖碰到再加)。
|
||||
## spec 是什么
|
||||
|
||||
## 写作规范
|
||||
spec/ 是产品语义的契约,用 Lean 写。它定义产品各部件"是什么意思"。
|
||||
|
||||
### 双半契约:prose + type
|
||||
- 它是开发者和 coding assistant 共同的语义依据:两边对某个东西的理解,以这里为准。
|
||||
- 它不进产品运行时。运行时真正做校验的那个东西用什么技术实现,还没定;但它的语义,
|
||||
先在这里固定下来。
|
||||
- 它精确、自洽,机器能校验它内部结构没有漏洞。它不保证实现一定符合它——
|
||||
实现和它是否一致,没有自动检查,要靠人工或 coding assistant 不定期(或每次改动后)核对。
|
||||
|
||||
每个 top-level 声明**必须**带 `/-- … -/` doc 注释,用自然语言陈述其语义意图。两半缺一不可:
|
||||
## 人机怎么一起干活
|
||||
|
||||
- **prose 半**给人读——说清"这在领域里是什么、为什么"。
|
||||
- **type 半**给机器读、给 type checker 把关——保证结构无洞。
|
||||
- 凭语义,不凭经验。这个领域新,coding assistant 在这里没有可靠的既有经验,
|
||||
所以语义以 spec 的注释为准,不要凭训练先验臆测。
|
||||
- 契约没写的,就是不存在的。遇到没定的点,提出来让开发者定,不要替它选答案。
|
||||
- 改了实现或 spec 之后,两边是否还对得上,要核对一下;这一致性没有自动闸门。
|
||||
|
||||
agent 不得用预训练先验脑补本领域(领域很新,无先验);prose 是 agent 理解语义的唯一权威来源。
|
||||
## 怎么往 spec 里写
|
||||
|
||||
### 标签分类法
|
||||
### 一条东西要不要进 spec
|
||||
|
||||
在 doc 注释里用以下标签标注每条语义的状态:
|
||||
不写它,开发者和 coding assistant 会不会各自做出不同假设?会,就进;不会
|
||||
(显然的事、纯基础设施、普通 CRUD 字段),就不进。
|
||||
|
||||
- **`PINNED`** —— 已解决的分歧点,契约在此处权威,双方据此对齐。
|
||||
- **`OPEN`** —— 故意未规定。双方均**不得假设**其解;实现遇到时必须 surface 出来讨论,而不是擅自决定。
|
||||
- **`ADR-NNNN`** —— 链接到根 `docs/adr/` 下的对应决策记录(如 `ADR-0002`),交代该语义的决策出处。
|
||||
### 进了之后,钉到多细
|
||||
|
||||
### 分歧点测试(写之前先过一遍)
|
||||
- 现在想清楚的,用 Lean 固定(声明、类型、关系)。
|
||||
- 没想清楚的,两三句话 prose 占位,标 `OPEN`。等讨论或业务反馈后再细化,
|
||||
细化结果可以再用 Lean 固定。
|
||||
- 不在 Lean 里验证实现真的做了这些事。spec 只讲"要做什么、判什么";实现有没有真做,
|
||||
不形式化证明。
|
||||
- 形式化定理:不用写;写了不是坏事,但现在很少有能写的定理。定理本身得是产品语义,
|
||||
不是"实现该满足的性质"。
|
||||
|
||||
新增任何概念前,先问:**"不写明,开发者与 agent 会不会各自做出不同假设?"**
|
||||
### 写的时候
|
||||
|
||||
- 会 → 它是分歧点,入契约。
|
||||
- 不会(显然的东西 / 纯 plumbing / 普通 CRUD 字段)→ 不入。
|
||||
|
||||
详见根 README 宪法第 5 条。
|
||||
|
||||
### 不用 `sorry`
|
||||
|
||||
无法陈述清楚的东西,用 `OPEN` 在 prose 里标注,而**不是**用 `sorry` 留一个假装成立的定理。`sorry` 会让 `lake build` 仍然变绿,却在契约里埋一个谎——这与"契约自包含、无洞"直接冲突。
|
||||
- 每个顶层声明要带 doc 注释,用 `/-- ... -/` 写自然语言,说清这在领域里是什么、为什么。
|
||||
注释是语义的依据,Lean 类型保证结构,两者缺一不可。
|
||||
- 在注释里标这条语义的状态:
|
||||
- `PINNED`:已定,契约在此处权威。
|
||||
- `OPEN`:故意没定。不要假设它的解,遇到要提出来讨论。
|
||||
- `ADR-NNNN`:指向 `docs/adr/` 下的决策记录。
|
||||
- 不用 `sorry`。没想清楚的,用 `OPEN` 标在注释里,不要用 `sorry` 假装成立——
|
||||
那会让构建通过,却在契约里埋一个谎。
|
||||
- 不复述文件系统上能直接看到的东西(目录结构、文件名)。文件系统应当自描述,文档讲 context。
|
||||
- 不写变更史(进 git/ADR)。不搬 ADR 内部黑话,要表达就直说。
|
||||
不为设计选择辩护("刻意用 X 而非 Y"),只说是什么。
|
||||
- "为什么"的背景考据(如某工具的内部机制)不进 spec,指向 ADR;但产品行为和设计模式要钉。
|
||||
|
||||
### 命名
|
||||
|
||||
- **模块 / 命名空间**:PascalCase,对应分层,如 `Spec.System.Run`、`Spec.Courseware.Validity`。
|
||||
- **类型**:PascalCase。
|
||||
- **谓词 / `Prop`**:用意图清晰的命名,如 `Legal…`、`ValidTransition`、`Can…`。
|
||||
- **文件粒度**:原则上"一个带独立不变式的概念一个文件"。
|
||||
- 模块/命名空间:PascalCase,按分层,如 `Spec.System.Run`。
|
||||
- 类型:PascalCase。
|
||||
- 谓词(`Prop`):用意图清楚的词,如 `Legal…`、`ValidTransition`、`Can…`。
|
||||
- 文件粒度:一个带独立不变式的概念一个文件。
|
||||
|
||||
Reference in New Issue
Block a user