forked from EduCraft/curriculum-project-hub
refactor(spec): clean prose patterns across all modules
Remove filler/redundant patterns: 钉死/钉, 本模块, likec4 画不出/画得出, 臆造, 散文, 分歧点测试, 纯 plumbing, 恰好, 留白, 宪法第N条, 刻意. No code definitions changed, only doc comments.
This commit is contained in:
@@ -16,6 +16,6 @@ import Spec.Courseware.Open
|
|||||||
- **`Check`** —— checker 语义:`Severity` + 6 类诊断 + **合法 lesson = 无 error 级
|
- **`Check`** —— checker 语义:`Severity` + 6 类诊断 + **合法 lesson = 无 error 级
|
||||||
诊断**(模型外设施诊断以抽象谓词 + `Oracle` 表示);检查管线的 5 阶段、序、compile
|
诊断**(模型外设施诊断以抽象谓词 + `Oracle` 表示);检查管线的 5 阶段、序、compile
|
||||||
门控。
|
门控。
|
||||||
- **`Open`** —— 留白骨架(核心关系 OPEN,已 surface 不臆造):题库 `QuestionBank`、
|
- **`Open`** —— OPEN 骨架(核心关系 OPEN,已 surface):题库 `QuestionBank`、
|
||||||
课程编排 `Course`。
|
课程编排 `Course`。
|
||||||
-/
|
-/
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Spec.Courseware.Export.Render
|
|||||||
|
|
||||||
产品里"站在 Lean 位置"的 rule-based checker,语义在此沉淀(ADR-0010,经 ADR-0012
|
产品里"站在 Lean 位置"的 rule-based checker,语义在此沉淀(ADR-0010,经 ADR-0012
|
||||||
修订)。它对 lesson 提诊断,每条有**分类**(`DiagKind`)与**严重级别**(`Severity`)。
|
修订)。它对 lesson 提诊断,每条有**分类**(`DiagKind`)与**严重级别**(`Severity`)。
|
||||||
本模块:钉级别类型(二分);钉 7 类诊断各自的含义与级别,并把"**合法 lesson = 无
|
定级别类型(二分);定 7 类诊断各自的含义与级别,并把"**合法 lesson = 无
|
||||||
error 级诊断**"建成判定(ADR-0005 deferred 的"完整合法判定"的回填);对**模型外设施**
|
error 级诊断**"建成判定(ADR-0005 deferred 的"完整合法判定"的回填);对**模型外设施**
|
||||||
型诊断(typst 编过否、数据合 schema 否)用**抽象谓词 + `Oracle` 实现边界**表示——契约
|
型诊断(typst 编过否、数据合 schema 否)用**抽象谓词 + `Oracle` 实现边界**表示——契约
|
||||||
说"存在这条诊断、什么意思、什么级别",真值由实现提供,不在 Lean 内计算(不内嵌 typst
|
说"存在这条诊断、什么意思、什么级别",真值由实现提供,不在 Lean 内计算(不内嵌 typst
|
||||||
@@ -50,7 +50,7 @@ inductive DiagKind where
|
|||||||
|
|
||||||
/-- 每类诊断的**严重级别**(`PINNED`, ADR-0010)。六类 `error`(阻断);**唯
|
/-- 每类诊断的**严重级别**(`PINNED`, ADR-0010)。六类 `error`(阻断);**唯
|
||||||
`renderIgnored` 为 `warning`**——ADR-0005 种子规则"缺渲染 ⇒ warning,不阻断导出"。
|
`renderIgnored` 为 `warning`**——ADR-0005 种子规则"缺渲染 ⇒ warning,不阻断导出"。
|
||||||
钉成全函数使"哪类阻断"成为可引用、可对齐的事实(实现侧 `DiagCode` 级别据此对齐)。 -/
|
全函数使"哪类阻断"成为可引用、可对齐的事实(实现侧 `DiagCode` 级别据此对齐)。 -/
|
||||||
def DiagKind.severity : DiagKind → Severity
|
def DiagKind.severity : DiagKind → Severity
|
||||||
| .partPathMissing => .error
|
| .partPathMissing => .error
|
||||||
| .unknownKind => .error
|
| .unknownKind => .error
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import Spec.Courseware.Check.Diagnostic
|
|||||||
|
|
||||||
checker 的 `check` 按**固定顺序**跑五个阶段,逐阶段收集诊断;`compile` 阶段有**门控**。
|
checker 的 `check` 按**固定顺序**跑五个阶段,逐阶段收集诊断;`compile` 阶段有**门控**。
|
||||||
顺序与门控是契约——它决定用户看到哪些诊断(藏在缺文件背后的语法错,在文件补齐前不
|
顺序与门控是契约——它决定用户看到哪些诊断(藏在缺文件背后的语法错,在文件补齐前不
|
||||||
显示,这是有意的)。每阶段的**算法**不进 Lean(宪法第 5 条深度上限):只钉**阶段、序、
|
显示,这是有意的)。每阶段的**算法**不进 Lean(深度上限:只定**阶段、序、
|
||||||
门控**。阶段对应上游模块:`load`←`cph-model`;`structural`←part 路径/未知 kind;
|
门控**)。阶段对应上游模块:`load`←`cph-model`;`structural`←part 路径/未知 kind;
|
||||||
`schema`←`cph-schema`;`compile`←`cph-typst`(模型外设施);`coverage`←`renderIgnored`。
|
`schema`←`cph-schema`;`compile`←`cph-typst`(模型外设施);`coverage`←`renderIgnored`。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# Artifact —— export target 的产物(ADR-0009 / 0011)
|
# Artifact —— export target 的产物(ADR-0009 / 0011)
|
||||||
|
|
||||||
ADR-0009:一个 export target 是**一次 build**,产出一个**有类型的产物**。ADR-0011
|
ADR-0009:一个 export target 是**一次 build**,产出一个**有类型的产物**。ADR-0011
|
||||||
钉死:产物是**带字段的 ADT**——"产物到底指什么"(单文件落在哪 / 一棵树产出哪些文件)
|
固定:产物是**带字段的 ADT**——"产物到底指什么"(单文件落在哪 / 一棵树产出哪些文件)
|
||||||
是不好猜的领域语义,必须写进字段 + doc,而非抹成两个空构造子。路径/glob 用 `String`
|
是不好猜的领域语义,必须写进字段 + doc,而非抹成两个空构造子。路径/glob 用 `String`
|
||||||
承载并由 doc 赋义(它们就是文本),不复刻文件系统类型。
|
承载并由 doc 赋义(它们就是文本),不复刻文件系统类型。
|
||||||
-/
|
-/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import Spec.Courseware.Export.Artifact
|
|||||||
/-!
|
/-!
|
||||||
# Render —— export target = artifact + 有序 typed steps(ADR-0009 / 0011)
|
# Render —— export target = artifact + 有序 typed steps(ADR-0009 / 0011)
|
||||||
|
|
||||||
ADR-0009:export target 是一次 build,产出一个有类型的 `Artifact`。ADR-0011 钉死 build
|
ADR-0009:export target 是一次 build,产出一个有类型的 `Artifact`。ADR-0011 固定 build
|
||||||
的**形状**:一个 target 是 `artifact` + 一串**有序 typed step**。
|
的**形状**:一个 target 是 `artifact` + 一串**有序 typed step**。
|
||||||
|
|
||||||
- `typstCompile template` —— 把**模板文件**(如 `exports/student.typ`)编译成产物。它是
|
- `typstCompile template` —— 把**模板文件**(如 `exports/student.typ`)编译成产物。它是
|
||||||
@@ -20,7 +20,7 @@ ADR-0009:export target 是一次 build,产出一个有类型的 `Artifact`。ADR
|
|||||||
|
|
||||||
**shell step 的执行语义(ADR-0013)。** `shell` 不再只是占位:它**会被执行**,语义是把
|
**shell step 的执行语义(ADR-0013)。** `shell` 不再只是占位:它**会被执行**,语义是把
|
||||||
`run` 交给平台 shell、以**工程根为工作目录**运行,产物由被调外部工具自己写出(框架不装配
|
`run` 交给平台 shell、以**工程根为工作目录**运行,产物由被调外部工具自己写出(框架不装配
|
||||||
内容)。三条边界是真分歧点,故钉契约:
|
内容)。三条边界是真分歧点,故定为契约:
|
||||||
1. **opt-in by construction** —— 任意命令执行只在用户**显式** build 一个 shell target 时发生,
|
1. **opt-in by construction** —— 任意命令执行只在用户**显式** build 一个 shell target 时发生,
|
||||||
绝不在 `check` 里跑。`check` 只校验结构(lesson 是否合法),不执行外部工具、不验其产物。
|
绝不在 `check` 里跑。`check` 只校验结构(lesson 是否合法),不执行外部工具、不验其产物。
|
||||||
2. **失败归属** —— shell step 退出非零是一次 **build-过程失败**,不是 lesson 的合法性缺陷;
|
2. **失败归属** —— shell step 退出非零是一次 **build-过程失败**,不是 lesson 的合法性缺陷;
|
||||||
@@ -46,7 +46,7 @@ namespace Spec.Courseware
|
|||||||
variable (P : Primitives)
|
variable (P : Primitives)
|
||||||
|
|
||||||
/-- 一个 build **step**(`PINNED` typed, ADR-0011;可扩展)。MVP 仅一个 `typstCompile`;
|
/-- 一个 build **step**(`PINNED` typed, ADR-0011;可扩展)。MVP 仅一个 `typstCompile`;
|
||||||
`steps` 是 list 因为 FileTree / 第三方 build 会需多步。刻意不把模板内部、shell 命令的
|
`steps` 是 list 因为 FileTree / 第三方 build 会需多步。不把模板内部、shell 命令的
|
||||||
解析结构写进来(实现细节, ADR-0011 OPEN)。 -/
|
解析结构写进来(实现细节, ADR-0011 OPEN)。 -/
|
||||||
inductive Step where
|
inductive Step where
|
||||||
/-- 编译模板文件 `template`(相对工程根)成产物;框架注入 manifest。typed 的理由:
|
/-- 编译模板文件 `template`(相对工程根)成产物;框架注入 manifest。typed 的理由:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import Spec.Courseware.Model.Info
|
|||||||
/-!
|
/-!
|
||||||
# Courseware.Model —— 工程文件的内容模型
|
# Courseware.Model —— 工程文件的内容模型
|
||||||
|
|
||||||
留白基元(`Primitives`)、富内容锚点(`RichContent`)、原子单位(`Element`)、单节课
|
基元(`Primitives`)、富内容锚点(`RichContent`)、原子单位(`Element`)、单节课
|
||||||
(`Lesson`)、课时元信息(`Info`:canonical author 为列表 vs `RawInfo` 撰写态)。
|
(`Lesson`)、课时元信息(`Info`:canonical author 为列表 vs `RawInfo` 撰写态)。
|
||||||
决策出处 ADR-0005 / 0006 / 0008。
|
决策出处 ADR-0005 / 0006 / 0008。
|
||||||
-/
|
-/
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Spec.Courseware.Model.Primitives
|
|||||||
/-!
|
/-!
|
||||||
# Element —— 课程内容的原子单位
|
# Element —— 课程内容的原子单位
|
||||||
|
|
||||||
ADR-0005:element 实例 = 一个 kind 标签 + 符合该 kind schema 的数据。本模块把它编码成
|
ADR-0005:element 实例 = 一个 kind 标签 + 符合该 kind schema 的数据。把它编码成
|
||||||
依赖结构,使"数据必须匹配其 kind"成为类型层面的事实而非运行时校验。
|
依赖结构,使"数据必须匹配其 kind"成为类型层面的事实而非运行时校验。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
基数**是一个真分歧点:一节课可由多人(教研组)署名,故 canonical 模型里 author 是一个
|
基数**是一个真分歧点:一节课可由多人(教研组)署名,故 canonical 模型里 author 是一个
|
||||||
**有序列表**,不是单值或可选单值。
|
**有序列表**,不是单值或可选单值。
|
||||||
|
|
||||||
另有一条值得钉的模式:on-disk 的**撰写态**(用户实际填写的形态)是**语法糖**——单作者可写
|
另一条模式:on-disk 的**撰写态**(用户实际填写的形态)是**语法糖**——单作者可写
|
||||||
`author = "…"`,多作者写 `author = ["…", "…"]`——但这个"字符串或数组"的二态**只活在加载
|
`author = "…"`,多作者写 `author = ["…", "…"]`——但这个"字符串或数组"的二态**只活在加载
|
||||||
边界**:`RawInfo` 经归一化折叠成 canonical `Info`,其后不再出现。canonical 接收端始终是
|
边界**:`RawInfo` 经归一化折叠成 canonical `Info`,其后不再出现。canonical 接收端始终是
|
||||||
`List String`,raw 形式不泄漏进模型其余部分。这正是 `Info`(canonical)与 `RawInfo`
|
`List String`,raw 形式不泄漏进模型其余部分。这正是 `Info`(canonical)与 `RawInfo`
|
||||||
@@ -24,7 +24,7 @@ inductive RawAuthor where
|
|||||||
| many (names : List String)
|
| many (names : List String)
|
||||||
|
|
||||||
/-- raw 作者归一化为**有序作者列表**(`PINNED`, ADR-0008)。单作者 ⇒ 单元素列表;数组
|
/-- raw 作者归一化为**有序作者列表**(`PINNED`, ADR-0008)。单作者 ⇒ 单元素列表;数组
|
||||||
⇒ 原样。这条钉死"canonical 接收端始终是 `List String`"。 -/
|
⇒ 原样。canonical 接收端始终是 `List String`。 -/
|
||||||
def RawAuthor.normalize : RawAuthor → List String
|
def RawAuthor.normalize : RawAuthor → List String
|
||||||
| .one n => [n]
|
| .one n => [n]
|
||||||
| .many ns => ns
|
| .many ns => ns
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
/-!
|
/-!
|
||||||
# Primitives —— Courseware 契约的留白基元
|
# Primitives —— Courseware 契约的基元
|
||||||
|
|
||||||
课程工程文件模型(ADR-0005)依赖一组基元:element kind 怎么标识、某 kind 的数据
|
课程工程文件模型(ADR-0005)依赖一组基元:element kind 怎么标识、某 kind 的数据
|
||||||
schema 是什么、export target 怎么标识。收口成载体 `Primitives`,让模型在其上参数化
|
schema 是什么、export target 怎么标识。收口成载体 `Primitives`,让模型在其上参数化
|
||||||
——契约谈得了 element / lesson / 渲染**之间的关系**,而把每个基元的**内部表示**留给
|
——契约谈得了 element / lesson / 渲染**之间的关系**,而把每个基元的**内部表示**留给
|
||||||
实现。注意:某基元语义已 PINNED(如 schema 形态由 ADR-0006 钉死)与其表示进 Lean
|
实现。注意:某基元语义已 PINNED(如 schema 形态由 ADR-0006 固定)与其表示进 Lean
|
||||||
是两回事——JSON Schema / typst 的内部结构属实现细节,不入 Lean,故基元在此仍以抽象
|
是两回事——JSON Schema / typst 的内部结构属实现细节,不入 Lean,故基元在此仍以抽象
|
||||||
类型承载。富内容的 prose 母本见 `Courseware.RichContent`。
|
类型承载。富内容的母本见 `Courseware.RichContent`。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.Courseware
|
namespace Spec.Courseware
|
||||||
|
|
||||||
/-- Courseware 契约基元载体(关系 `PINNED`, ADR-0005;各基元表示留给实现, ADR-0006)。 -/
|
/-- Courseware 契约基元载体(关系 `PINNED`, ADR-0005;各基元表示留给实现, ADR-0006)。 -/
|
||||||
structure Primitives where
|
structure Primitives where
|
||||||
/-- element kind 标识(`PINNED` **开放宇宙**, ADR-0005;表示 `OPEN`)。刻意用抽象
|
/-- element kind 标识(`PINNED` **开放宇宙**, ADR-0005;表示 `OPEN`)。用抽象
|
||||||
类型而非 `inductive`:ADR-0005 决定 kind 是开放可扩展宇宙(stdlib + 第三方),
|
类型而非 `inductive`:ADR-0005 决定 kind 是开放可扩展宇宙(stdlib + 第三方),
|
||||||
封闭枚举会违背它——此处开放是**已决策的**(区别于 `RunState` 的"尚未封闭")。 -/
|
封闭枚举会违背它——此处开放是**已决策的**(区别于 `RunState` 的"尚未封闭")。 -/
|
||||||
KindId : Type
|
KindId : Type
|
||||||
/-- 某 kind 的合法数据类型(`PINNED` 依赖关系, ADR-0005;schema 形态 `PINNED`
|
/-- 某 kind 的合法数据类型(`PINNED` 依赖关系, ADR-0005;schema 形态 `PINNED`
|
||||||
ADR-0006,表示仍抽象)。以 kind 为索引:`ElementData k` 即"符合 `k` schema 的
|
ADR-0006,表示仍抽象)。以 kind 为索引:`ElementData k` 即"符合 `k` schema 的
|
||||||
数据"。schema 形态(声明式 JSON Schema + `content` 叶子 = typst 源)是 ADR-0006
|
数据"。schema 形态(声明式 JSON Schema + `content` 叶子 = typst 源)由 ADR-0006
|
||||||
钉死的,但属 JSON/typst 内部结构、实现细节,不进 Lean;契约只锚定"数据符合
|
固定,但属 JSON/typst 内部结构、实现细节,不进 Lean;契约只锚定"数据符合
|
||||||
kind schema"这条关系,故此处仍是抽象类型。 -/
|
kind schema"这条关系,故此处仍是抽象类型。 -/
|
||||||
ElementData : KindId → Type
|
ElementData : KindId → Type
|
||||||
/-- export target 标识(`PINNED` 角色, ADR-0005;表示 `OPEN`)。一个 target 是一次
|
/-- export target 标识(`PINNED` 角色, ADR-0005;表示 `OPEN`)。一个 target 是一次
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/-!
|
/-!
|
||||||
# RichContent —— 富内容(ADR-0006 的 prose 母本)
|
# RichContent —— 富内容(ADR-0006 的母本)
|
||||||
|
|
||||||
ADR-0006:element schema 的"叶子"可以是 `content` 类型,其值是一段**源文本**,
|
ADR-0006:element schema 的"叶子"可以是 `content` 类型,其值是一段**源文本**,
|
||||||
按其 **format** 决定语义(ADR-0015)。两种 format:
|
按其 **format** 决定语义(ADR-0015)。两种 format:
|
||||||
@@ -13,7 +13,7 @@ ADR-0006:element schema 的"叶子"可以是 `content` 类型,其值是一段**
|
|||||||
的一等文件,坐落在一个**虚拟路径**上;相对 import 限本工程路径结构内 + `@package`(不跨工程)。markdown format
|
的一等文件,坐落在一个**虚拟路径**上;相对 import 限本工程路径结构内 + `@package`(不跨工程)。markdown format
|
||||||
的富内容不参与 typst 求值,但同样由一个虚拟路径定位(供 markdown 装配 step 按序读取,见 `Export/Render`)。
|
的富内容不参与 typst 求值,但同样由一个虚拟路径定位(供 markdown 装配 step 按序读取,见 `Export/Render`)。
|
||||||
|
|
||||||
本模块只立 prose 锚点 + 最小抽象签名:typst 的 `Content`/`Module` 内部结构、JSON Schema 形状、format 的
|
只立锚点 + 最小抽象签名:typst 的 `Content`/`Module` 内部结构、JSON Schema 形状、format 的
|
||||||
具体判别属实现细节,不进 Lean,只承诺"富内容由一个虚拟路径定位"+"叶子带 format"这两条关系。
|
具体判别属实现细节,不进 Lean,只承诺"富内容由一个虚拟路径定位"+"叶子带 format"这两条关系。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
@@ -33,8 +33,8 @@ inductive ContentFormat where
|
|||||||
| markdown
|
| markdown
|
||||||
|
|
||||||
/-- 对一段富内容的**引用**:它坐落在某个虚拟路径上(`PINNED` 关系, ADR-0006),并带一个
|
/-- 对一段富内容的**引用**:它坐落在某个虚拟路径上(`PINNED` 关系, ADR-0006),并带一个
|
||||||
**format**(`PINNED`, ADR-0015)。刻意**不**建模源文本、不建模求值出的 `Content`(那是实现侧的事);
|
**format**(`PINNED`, ADR-0015)。不建模源文本、不建模求值出的 `Content`(那是实现侧的事);
|
||||||
只钉"富内容经由一个 `VPath` 定位 + 带 format",作为 `Primitives.ElementData` 里 `content` 叶子的语义锚点。 -/
|
"富内容经由一个 `VPath` 定位 + 带 format",作为 `Primitives.ElementData` 里 `content` 叶子的语义锚点。 -/
|
||||||
structure RichContentRef where
|
structure RichContentRef where
|
||||||
/-- 该富内容所在的虚拟路径(ADR-0006;落盘后为真实相对路径, ADR-0007)。 -/
|
/-- 该富内容所在的虚拟路径(ADR-0006;落盘后为真实相对路径, ADR-0007)。 -/
|
||||||
vpath : VPath
|
vpath : VPath
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import Spec.Courseware.Open.QuestionBank
|
|||||||
import Spec.Courseware.Open.Course
|
import Spec.Courseware.Open.Course
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
# Courseware.Open —— 留白骨架(核心关系 OPEN)
|
# Courseware.Open —— OPEN 骨架(核心关系)
|
||||||
|
|
||||||
题库与 element 的关系(`QuestionBank`)、课程编排规则(`Course`)。两者均为已 surface
|
题库与 element 的关系(`QuestionBank`)、课程编排规则(`Course`)。两者均为已 surface
|
||||||
但未决策的分歧点,按宪法第 2 条不臆造,待专门 ADR 落定。
|
但未决策的 OPEN 分歧点,待专门 ADR 落定。
|
||||||
-/
|
-/
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ ADR-0005:工程文件的粒度是**单节课**;course / 单元**不是**工程
|
|||||||
**编排**。但"编排"的具体规则未决策:有序列表还是带层级(单元 → 课)的树?lesson 被
|
**编排**。但"编排"的具体规则未决策:有序列表还是带层级(单元 → 课)的树?lesson 被
|
||||||
引用还是被包含?跨 lesson 有无约束(目标覆盖、前后置)?这些都是 `OPEN`。
|
引用还是被包含?跨 lesson 有无约束(目标覆盖、前后置)?这些都是 `OPEN`。
|
||||||
|
|
||||||
按宪法第 2 条本模块**不臆造**编排结构——不建 `Course := List Lesson`(那会偷偷承诺
|
此处不替它选解——不建 `Course := List Lesson`(那会偷偷承诺
|
||||||
"扁平有序、无层级")。只在此 surface:课程编排待专门 ADR。本文件当前不引入任何承诺性声明。
|
"扁平有序、无层级")。只在此 surface:课程编排待专门 ADR。本文件当前不引入任何承诺性声明。
|
||||||
-/
|
-/
|
||||||
|
|||||||
@@ -5,6 +5,6 @@
|
|||||||
典型的可复用单元,lesson 会引用它。但**题库与 element 的关系尚未决策**,且用户明确
|
典型的可复用单元,lesson 会引用它。但**题库与 element 的关系尚未决策**,且用户明确
|
||||||
指出"纯引用可能不够"——element 内联题目数据 / lesson 持指向题库条目的引用 / 两者并存?
|
指出"纯引用可能不够"——element 内联题目数据 / lesson 持指向题库条目的引用 / 两者并存?
|
||||||
|
|
||||||
这是一个 `OPEN` 分歧点。按宪法第 2 条本模块**不替它选解**——不建 `QuestionRef` 也不建
|
这是一个 `OPEN` 分歧点。此处不替它选解——不建 `QuestionRef` 也不建
|
||||||
内联结构,只在此 surface。待专门 ADR 落定后再填。本文件当前不引入任何承诺性声明。
|
内联结构,只在此 surface。待专门 ADR 落定后再填。本文件当前不引入任何承诺性声明。
|
||||||
-/
|
-/
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/-!
|
/-!
|
||||||
# Prelude —— System 层共享标识符
|
# Prelude —— System 层共享标识符
|
||||||
|
|
||||||
平台层反复引用一组标识符(项目、run、session、principal、chat、platform identity/audit)。其内部表示从未被决策
|
平台层引用一组标识符(项目、run、session、principal、chat、platform identity/audit)。
|
||||||
(UUID / 复合键、principal 子类型学),也非分歧点,故收口成 opaque 载体
|
其内部表示从未被决策(UUID / 复合键、principal 子类型学),也非分歧点,故收口成 opaque
|
||||||
`Identifiers`,System 各模块在其上参数化——契约谈得了"锁 owner 是哪个 run"这类
|
载体 `Identifiers`,System 各模块在其上参数化——契约谈得了"锁 owner 是哪个 run"这类
|
||||||
**关系**,却不对标识符表示作承诺。
|
关系,却不对标识符表示作承诺。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
@@ -37,11 +37,11 @@ structure Identifiers where
|
|||||||
记忆/锚点重建,不由 session 自带。同 provider/model 内可跨多 run 复用, ADR-0002)。 -/
|
记忆/锚点重建,不由 session 自带。同 provider/model 内可跨多 run 复用, ADR-0002)。 -/
|
||||||
SessionId : Type
|
SessionId : Type
|
||||||
/-- 权限主体标识(`OPEN` 表示及其子类型学;ADR-0004 的 user/chat/department/…
|
/-- 权限主体标识(`OPEN` 表示及其子类型学;ADR-0004 的 user/chat/department/…
|
||||||
子类型学未定且非本层分歧点,纯 plumbing,故只留 opaque 键)。 -/
|
子类型学未定且非分歧点,故只留 opaque 键)。 -/
|
||||||
Principal : Type
|
Principal : Type
|
||||||
/-- 飞书项目群 chat 标识(`OPEN` 表示;ADR-0001 协作空间、ADR-0003 锚点引用、
|
/-- 飞书项目群 chat 标识(`OPEN` 表示;ADR-0001 协作空间、ADR-0003 锚点引用、
|
||||||
ADR-0004 `feishu_chat` principal 三处共用同一实体。独立成载体而非 `Principal` 子
|
ADR-0004 `feishu_chat` principal 三处共用同一实体。独立成载体而非 `Principal` 子
|
||||||
类型——principal 子类型学 OPEN 见上,本层不预设"chat 是 principal 的哪种子型")。 -/
|
类型——principal 子类型学 OPEN,这里不预设"chat 是 principal 的哪种子型")。 -/
|
||||||
ChatId : Type
|
ChatId : Type
|
||||||
/-- 平台管理员身份标识(`OPEN` 表示;ADR-0023,不复用客户 `User` 标识)。 -/
|
/-- 平台管理员身份标识(`OPEN` 表示;ADR-0023,不复用客户 `User` 标识)。 -/
|
||||||
PlatformIdentityId : Type
|
PlatformIdentityId : Type
|
||||||
|
|||||||
@@ -17,9 +17,8 @@ import Spec.System.Audit
|
|||||||
/-!
|
/-!
|
||||||
# System —— Hub 平台层契约
|
# System —— Hub 平台层契约
|
||||||
|
|
||||||
协作与执行的平台:项目、飞书群、AgentRun、锁、权限、审计、按需上下文。likec4
|
协作与执行的平台:项目、飞书群、AgentRun、锁、权限、审计、按需上下文。
|
||||||
(`docs/architecture/likec4/`)已画出这一层的**结构**;本层只补 likec4 画不出的
|
likec4 已画出结构;这里补语义:
|
||||||
**语义分歧点**:
|
|
||||||
|
|
||||||
- `Hierarchy` —— 三层主体:平台 → 组织 → 用户。
|
- `Hierarchy` —— 三层主体:平台 → 组织 → 用户。
|
||||||
- `User` —— 用户创建路径(管理员直接创建;飞书注册 `OPEN`)。
|
- `User` —— 用户创建路径(管理员直接创建;飞书注册 `OPEN`)。
|
||||||
@@ -37,14 +36,14 @@ import Spec.System.Audit
|
|||||||
- `AgentRole` —— org-scoped agent 角色配置 + 技能(ADR-0017/0018)。
|
- `AgentRole` —— org-scoped agent 角色配置 + 技能(ADR-0017/0018)。
|
||||||
- `Run` —— AgentRun 状态与终止判定(状态集合完整性 OPEN)。
|
- `Run` —— AgentRun 状态与终止判定(状态集合完整性 OPEN)。
|
||||||
- `Lock` —— 锁 owner=run(ADR-0002),及"持锁者必为非终止 run"的核心不变式。
|
- `Lock` —— 锁 owner=run(ADR-0002),及"持锁者必为非终止 run"的核心不变式。
|
||||||
- `Memory` —— 按需上下文:锚点类别(ADR-0003)+ MCP 工具按 run/project 上下文授权的不变式。
|
- `Memory` —— 按需上下文:锚点类别(ADR-0003)+ MCP 工具按 run/project 上下文授权。
|
||||||
- `AgentSurface` —— agent 执行面被 run 的工作区所界定(ADR-0018);与 Lock 正交——
|
- `AgentSurface` —— agent 执行面被 run 的工作区所界定(ADR-0018);与 Lock 正交——
|
||||||
Lock 限定并发,Surface 限定波及面。机制 OPEN。
|
Lock 限定并发,Surface 限定波及面。机制 OPEN。
|
||||||
- `Permission` —— read⊂edit⊂manage 角色体系、能力推导、单调性;force-release 在格外。
|
- `Permission` —— read⊂edit⊂manage 角色体系、能力推导、单调性;force-release 在格外。
|
||||||
- `PermissionGrant` —— grant(resource×principal×role)与 settings(六 policy 旋钮)结构
|
- `PermissionGrant` —— grant(resource×principal×role)与 settings(六 policy 旋钮)
|
||||||
(ADR-0004);role-capability 与 settings-policy 的组合规则 OPEN。
|
(ADR-0004);组合规则 OPEN。
|
||||||
- `Audit` —— customer Project/Run 审计有意从简(内容多为 plumbing,OPEN);Platform
|
- `Audit` —— customer Project/Run 审计从简(内容 OPEN);Platform Audit 由
|
||||||
Audit 由 `PlatformAdministration` 独立钉死。
|
`PlatformAdministration` 独立承载。
|
||||||
|
|
||||||
标识符见 `Spec.Prelude`。决策出处:ADR-0001..0004, 0018, 0020..0024。
|
标识符见 `Spec.Prelude`。决策出处:ADR-0001..0004, 0018, 0020..0024。
|
||||||
-/
|
-/
|
||||||
|
|||||||
@@ -4,19 +4,14 @@ import Spec.System.Agent.Run
|
|||||||
/-!
|
/-!
|
||||||
# AgentSurface —— Agent 执行面边界(ADR-0018)
|
# AgentSurface —— Agent 执行面边界(ADR-0018)
|
||||||
|
|
||||||
ADR-0001/0002/0004 覆盖"协作治理"直到 `triggerAgent`:谁能触发一次 run。但触发之后
|
Agent 在一次 run 内发起的文件操作,其路径必须落在该 run 所属 project 的工作区目录内
|
||||||
agent 在执行层面能干什么——读哪些文件、跑什么命令——任何 ADR / 散文都未定。ADR-0017
|
(ADR-0007)。逃逸即越权,拒绝。
|
||||||
落地时采用 Claude Code SDK 的 `bypassPermissions` + 全量 Read/Write/Bash/Glob/Grep,
|
|
||||||
agent 的文件与 shell 面对宿主**无界**:spec 与 ADR 均未钉死边界。本模块补这一层。
|
|
||||||
|
|
||||||
钉死的不变式:agent 在一次 run 内发起的文件操作,其路径必须落在该 run 所属 project
|
与 `Lock`(ADR-0002)正交:Lock 限定并发(谁在改),Surface 限定波及面(能改到哪)。
|
||||||
的工作区目录内(ADR-0007:工程文件是目录树;此 ADR 固定"agent 操作落在该树内")。
|
二者都按 run × project 作用域。
|
||||||
逃逸即越权,拒绝。与 `Lock`(ADR-0002)正交:Lock 限定**并发**(谁在改),Surface
|
|
||||||
限定**波及面**(能改到哪)。二者都按 run × project 作用域。
|
|
||||||
|
|
||||||
shell 面的边界(命令的文件效果同样不得逃逸工作区)是同一不变式的推论,但**机制**
|
shell 面的边界(命令的文件效果同样不得逃逸工作区)是同一不变式的推论。机制
|
||||||
——路径校验工具包装、OS 级沙箱(bubblewrap/容器)、SDK 权限钩子,或其组合——`OPEN`
|
——路径校验、OS 级沙箱、SDK 权限钩子,或其组合——`OPEN`(ADR-0018)。
|
||||||
(ADR-0018)。契约钉死不变式,不钉死机制。
|
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
@@ -24,17 +19,18 @@ namespace Spec.System
|
|||||||
variable (I : Identifiers) (Path : Type)
|
variable (I : Identifiers) (Path : Type)
|
||||||
|
|
||||||
/-- Agent 在一次 run 内发起的文件操作(`PINNED` 关系, ADR-0018)。由某 run 发起、
|
/-- Agent 在一次 run 内发起的文件操作(`PINNED` 关系, ADR-0018)。由某 run 发起、
|
||||||
指向某路径;是否越权由下方 `Authorized` 钉死。 -/
|
指向某路径;是否越权由下方 `Authorized` 约束。 -/
|
||||||
structure AgentFileOp where
|
structure AgentFileOp where
|
||||||
/-- 发起操作的 run(授权上下文主体, ADR-0018;与 `Lock` 同作用域 run × project)。 -/
|
/-- 发起操作的 run(授权上下文主体, ADR-0018;与 `Lock` 同作用域 run × project)。 -/
|
||||||
run : I.RunId
|
run : I.RunId
|
||||||
/-- 操作目标路径(`PINNED` 字段, ADR-0018)。 -/
|
/-- 操作目标路径(`PINNED`, ADR-0018)。 -/
|
||||||
path : Path
|
path : Path
|
||||||
|
|
||||||
|
|
||||||
/-- 工作区边界良构:run 的文件操作路径必须落在该 run 所属 project 的工作区目录内
|
/-- 工作区边界良构:run 的文件操作路径必须落在该 run 所属 project 的工作区目录内
|
||||||
(`PINNED` 平台核心安全不变式, ADR-0018)。`runWorkspace` 与 `pathWithin` 均由平台提供
|
(`PINNED` 安全不变式, ADR-0018)。`runWorkspace` 与 `pathWithin` 由平台提供
|
||||||
(表示 `OPEN`——路径如何表示、"在内"如何判定是纯 plumbing,非本层分歧点);本谓词只
|
(表示 `OPEN`);本谓词约束"操作路径必须以 run 的工作区为根",杜绝 agent 越权读写
|
||||||
钉死"操作路径必须以 run 的工作区为根",杜绝 agent 越权读写宿主任意文件。 -/
|
宿主任意文件。 -/
|
||||||
def AgentFileOp.Authorized
|
def AgentFileOp.Authorized
|
||||||
(op : AgentFileOp I Path)
|
(op : AgentFileOp I Path)
|
||||||
(runWorkspace : I.RunId → Option Path)
|
(runWorkspace : I.RunId → Option Path)
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import Spec.Prelude
|
|||||||
/-!
|
/-!
|
||||||
# Memory —— 按需上下文:锚点与项目记忆(ADR-0003)
|
# Memory —— 按需上下文:锚点与项目记忆(ADR-0003)
|
||||||
|
|
||||||
ADR-0003:Hub **只存锚点与项目记忆**,不存全量飞书消息历史;Claude 需要更多上下文时经
|
ADR-0003:Hub 只存锚点与项目记忆,不存全量飞书消息历史;Claude 需要更多上下文时经
|
||||||
飞书 API 按需读取。本模块刻画所存锚点的**类别**(ADR 列定,枚举完整性 OPEN——ADR 是
|
飞书 API 按需读取。这里刻画所存锚点的类别(ADR 列定,枚举完整性 OPEN),并约束
|
||||||
"例如"式列举,新增类别不违反契约),并钉死一条 likec4 画不出的安全不变式:**MCP 工具
|
一条安全不变式:MCP 工具按 run/project 上下文授权,Claude 不得传任意 chat id
|
||||||
按 run/project 上下文授权,Claude 不得传任意 chat id**(ADR-0003 Consequences 末条)。
|
(ADR-0003 Consequences 末条)。
|
||||||
|
|
||||||
"chat id 与 project 绑定"这一锚点类别由 `ProjectGroup.GroupBinding`(ADR-0001)权威承载,
|
"chat id 与 project 绑定"这一锚点类别由 `ProjectGroup.GroupBinding`(ADR-0001)权威承载,
|
||||||
本模块不重复声明,只覆盖其余飞书侧指针(触发消息、状态卡片、回复、线程)。
|
这里只覆盖其余飞书侧指针(触发消息、状态卡片、回复、线程)。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
@@ -17,9 +17,8 @@ namespace Spec.System
|
|||||||
variable (I : Identifiers)
|
variable (I : Identifiers)
|
||||||
variable (MessageId CardId : Type)
|
variable (MessageId CardId : Type)
|
||||||
|
|
||||||
/-- 上下文锚点(`PINNED` 类别, ADR-0003 列定;**枚举完整性 `OPEN`**——ADR 是"例如"式
|
/-- 上下文锚点(`PINNED` 类别, ADR-0003;枚举完整性 `OPEN`——ADR 是"例如"式列举,
|
||||||
列举,实现若需新类别须 surface,不得默认本枚举已穷尽)。承载 Hub 保留的飞书侧最小指针,
|
实现若需新类别须 surface)。承载 Hub 保留的飞书侧最小指针,而非消息正文。 -/
|
||||||
而非消息正文。 -/
|
|
||||||
inductive Anchor where
|
inductive Anchor where
|
||||||
/-- 触发某次 run 的消息(`PINNED` 类别, ADR-0003 "trigger message id")。 -/
|
/-- 触发某次 run 的消息(`PINNED` 类别, ADR-0003 "trigger message id")。 -/
|
||||||
| triggerMessage : MessageId → Anchor
|
| triggerMessage : MessageId → Anchor
|
||||||
@@ -35,13 +34,11 @@ MCP tools to read … through Feishu APIs")。 -/
|
|||||||
structure McpReadRequest where
|
structure McpReadRequest where
|
||||||
/-- 发起请求的 run(授权上下文主体, ADR-0003)。 -/
|
/-- 发起请求的 run(授权上下文主体, ADR-0003)。 -/
|
||||||
run : I.RunId
|
run : I.RunId
|
||||||
/-- 请求读取的 chat(是否允许越界由下方 `Authorized` 钉死:不允许)。 -/
|
/-- 请求读取的 chat(授权由下方 `Authorized` 约束:不允许越界)。 -/
|
||||||
chat : I.ChatId
|
chat : I.ChatId
|
||||||
|
|
||||||
/-- 请求获授权:其 chat 必须等于该 run 所属 project 的绑定群(`PINNED` 安全不变式,
|
/-- 请求获授权:其 chat 必须等于该 run 所属 project 的绑定群(`PINNED` 安全不变式,
|
||||||
ADR-0003 Consequences "MCP tools must authorize by run/project context; Claude cannot
|
ADR-0003)。"chat 必须匹配 run 的 project 绑定",杜绝 Claude 传任意 chat id。 -/
|
||||||
pass arbitrary chat ids")。`runProject`/`boundChat` 由平台提供(表示 `OPEN`);本谓词只
|
|
||||||
钉死"chat 必须匹配 run 的 project 绑定",杜绝 Claude 传任意 chat id 越权读取。 -/
|
|
||||||
def McpReadRequest.Authorized
|
def McpReadRequest.Authorized
|
||||||
(req : McpReadRequest I)
|
(req : McpReadRequest I)
|
||||||
(runProject : I.RunId → Option I.ProjectId)
|
(runProject : I.RunId → Option I.ProjectId)
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
# Run —— AgentRun 状态机
|
# Run —— AgentRun 状态机
|
||||||
|
|
||||||
一次 `@bot` 创建一个 `AgentRun`(ADR-0001),它在终止时释放项目锁(ADR-0002)。
|
一次 `@bot` 创建一个 `AgentRun`(ADR-0001),它在终止时释放项目锁(ADR-0002)。
|
||||||
合法转移关系在任何 ADR / likec4 散文里都未定下,故本模块只刻画**状态**与**终止
|
转移关系在任何 ADR 里都未定,这里只刻画状态与终止判定(后者是 Lock 排他不变式的
|
||||||
判定**(后者是 Lock 排他不变式的依赖),不臆造转移边。
|
依赖),不定义转移边。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
|
|
||||||
/-- AgentRun 运行状态(状态名 `PINNED`, ADR-0001..0003, ADR-0022 + likec4;
|
/-- AgentRun 运行状态(状态名 `PINNED`, ADR-0001..0003, ADR-0022;完整性 `OPEN`
|
||||||
**完整性 `OPEN`**——散文从未声明"状态恰好这些";实现若需新状态(如 pending)须
|
——ADR 从未声明"状态就是这些";实现若需新状态(如 pending)须 surface)。终止态
|
||||||
surface,不得默认本枚举已穷尽)。终止态见 `RunState.Terminal`。 -/
|
见 `RunState.Terminal`。 -/
|
||||||
inductive RunState where
|
inductive RunState where
|
||||||
| active
|
| active
|
||||||
| waitingForUser
|
| waitingForUser
|
||||||
|
|||||||
@@ -1,21 +1,18 @@
|
|||||||
import Spec.Prelude
|
import Spec.Prelude
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
# Audit —— Project/Run 审计日志(有意从简)
|
# Audit —— Project/Run 审计日志
|
||||||
|
|
||||||
likec4 把 `AuditLog` 列为实体(`AgentRun -> AuditLog 'records lifecycle events'`),
|
审计记录里装什么(事件 schema、保留策略、可查询维度)在任何 ADR 里都未决策,
|
||||||
但**审计记录里装什么**(事件 schema、保留策略、可查询维度)在任何 ADR / 散文里都
|
且大多是实现细节。这里只固定"审计以 run 为主体记录其生命周期事件"这一条已决策
|
||||||
未决策,且大多是 plumbing——按分歧点测试不入契约。故本模块刻意几乎为空:只固定
|
关系,其余 `OPEN`。ADR-0023 的 Platform Audit 是另一个控制面,见
|
||||||
"审计以 run 为主体记录其生命周期事件"这一条已决策关系,其余 `OPEN`(留白本身是
|
`Spec.System.PlatformAdministration`,不复用本结构。
|
||||||
契约的一部分:承诺此处尚无答案、勿填)。
|
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
|
|
||||||
/-- 审计条目的最小骨架(关系 `PINNED` / 内容 `OPEN`, likec4)。只承诺"一条审计记录
|
/-- 审计条目的最小骨架(关系 `PINNED` / 内容 `OPEN`, likec4)。只承诺"一条审计记录
|
||||||
关联到某个 run";事件类型、时间、actor、详情等字段 `OPEN`,待真实分歧点出现时由
|
关联到某个 run";事件类型、时间、actor、详情等字段 `OPEN`。 -/
|
||||||
对应 ADR 落定。ADR-0023 的 Platform Audit 是另一个 fail-closed 控制面,见
|
|
||||||
`Spec.System.PlatformAdministration`,不复用本结构。 -/
|
|
||||||
structure AuditEntry (I : Identifiers) where
|
structure AuditEntry (I : Identifiers) where
|
||||||
/-- 该审计条目所属的 run(`PINNED` 关系, likec4)。 -/
|
/-- 该审计条目所属的 run(`PINNED` 关系, likec4)。 -/
|
||||||
run : I.RunId
|
run : I.RunId
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import Spec.Prelude
|
|||||||
# Capacity —— SaaS capacity admission and abuse controls (ADR-0022)
|
# Capacity —— SaaS capacity admission and abuse controls (ADR-0022)
|
||||||
|
|
||||||
初始生产服务共享有限的单机资源,但不能让一个 Organization 垄断容量或让无界输入拖垮
|
初始生产服务共享有限的单机资源,但不能让一个 Organization 垄断容量或让无界输入拖垮
|
||||||
其他租户。ADR-0022 钉死分层限制、持久 admission、显式背压和紧急制动的领域语义;
|
其他租户。ADR-0022 定义分层限制、持久 admission、显式背压和紧急制动;具体数值由
|
||||||
具体数值必须由生产式容量测试校准,因此保持 `OPEN`,不得把未经验证的数字冒充契约。
|
生产式容量测试校准,保持 `OPEN`。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
|
|||||||
@@ -4,32 +4,29 @@ import Spec.System.Agent.Run
|
|||||||
/-!
|
/-!
|
||||||
# Lock —— 项目锁与排他不变式
|
# Lock —— 项目锁与排他不变式
|
||||||
|
|
||||||
ADR-0002 的核心:防止并发 Claude 同改一个项目,锁的 **owner 是当前 `AgentRun`**
|
ADR-0002:防止并发 agent 同改一个项目,锁的 owner 是当前 `AgentRun`(不是
|
||||||
(不是 teacher / chat / session)。本模块把这条决策编码进类型,并钉死那条
|
teacher / chat / session)。持锁者必为非终止 run。
|
||||||
likec4 画不出的语义不变式——**持锁者必为非终止 run**。
|
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
|
|
||||||
variable (I : Identifiers)
|
variable (I : Identifiers)
|
||||||
|
|
||||||
/-- 项目级锁(`PINNED`, ADR-0002)。`owner : RunId`(非 SessionId/Principal)从类型
|
/-- 项目级锁(`PINNED`, ADR-0002)。`owner : RunId`从类型上编码"lock owner = run_id":
|
||||||
上编码"lock owner = run_id":锁不可能被 session / teacher 持有。 -/
|
锁不可能被 session / teacher 持有。 -/
|
||||||
structure ProjectAgentLock where
|
structure ProjectAgentLock where
|
||||||
/-- 作用域:项目级(`PINNED`, ADR-0002 `scope = project_id`)。 -/
|
/-- 作用域:项目级(`PINNED`, ADR-0002)。 -/
|
||||||
scope : I.ProjectId
|
scope : I.ProjectId
|
||||||
/-- 持有者:一个 run(`PINNED`, ADR-0002 `owner = run_id`)。 -/
|
/-- 持有者:一个 run(`PINNED`, ADR-0002)。 -/
|
||||||
owner : I.RunId
|
owner : I.RunId
|
||||||
|
|
||||||
/-- 锁表:每项目当前持锁 run(`PINNED` 排他性, ADR-0002)。`ProjectId → Option RunId`
|
/-- 锁表:每项目当前持锁 run(`PINNED` 排他性, ADR-0002)。`ProjectId → Option RunId`
|
||||||
的结构**本身**即排他——不可能为同一项目登记两个并发 owner。 -/
|
的结构本身即排他——不可能为同一项目登记两个并发 owner。 -/
|
||||||
def LockTable := I.ProjectId → Option I.RunId
|
def LockTable := I.ProjectId → Option I.RunId
|
||||||
|
|
||||||
/-- 锁表良构:**持锁者必为非终止 run**(`PINNED` 平台核心不变式, ADR-0002)。
|
/-- 锁表良构:持锁者必为非终止 run(`PINNED`, ADR-0002)。
|
||||||
|
|
||||||
"锁在 run 终止时释放"的逻辑等价物:若 `p` 的锁被 `r` 持有,则 `r` 不在终止态。这条
|
若 `p` 的锁被 `r` 持有,则 `r` 不在终止态。锁在 run 终止时释放。 -/
|
||||||
把 Lock 与 Run 耦合起来——likec4 能画"run owns lock while running",画不出"终止即
|
|
||||||
必须释放"这个约束;它正是契约相对结构图的增量。 -/
|
|
||||||
def LockTable.WellFormed
|
def LockTable.WellFormed
|
||||||
(lt : LockTable I) (statusOf : I.RunId → RunState) : Prop :=
|
(lt : LockTable I) (statusOf : I.RunId → RunState) : Prop :=
|
||||||
∀ p r, lt p = some r → ¬ (statusOf r).Terminal
|
∀ p r, lt p = some r → ¬ (statusOf r).Terminal
|
||||||
|
|||||||
@@ -35,10 +35,9 @@ structure TeamProjectGrantScope where
|
|||||||
project : I.ProjectId
|
project : I.ProjectId
|
||||||
/-- 获得授权的 team principal(`PINNED`, ADR-0020)。 -/
|
/-- 获得授权的 team principal(`PINNED`, ADR-0020)。 -/
|
||||||
team : I.TeamId
|
team : I.TeamId
|
||||||
|
|
||||||
/-- Team-project grant 是良构的 iff project 与 team 解析到同一 organization
|
/-- Team-project grant 是良构的 iff project 与 team 解析到同一 organization
|
||||||
(`PINNED`, ADR-0020)。`projectOrg`/`teamOrg` 由平台提供(表示 `OPEN`);本谓词钉死
|
(`PINNED`, ADR-0020)。`projectOrg`/`teamOrg` 由平台提供(表示 `OPEN`);跨 org
|
||||||
跨 org team grant 必须被拒绝。 -/
|
team grant 必须被拒绝。 -/
|
||||||
def TeamProjectGrantScope.WellScoped
|
def TeamProjectGrantScope.WellScoped
|
||||||
(grant : TeamProjectGrantScope I)
|
(grant : TeamProjectGrantScope I)
|
||||||
(projectOrg : I.ProjectId → Option I.OrganizationId)
|
(projectOrg : I.ProjectId → Option I.OrganizationId)
|
||||||
@@ -71,7 +70,7 @@ inductive OrganizationConnectionStatus where
|
|||||||
|
|
||||||
/-- Organization secret version 的信封绑定上下文(`PINNED`, ADR-0024):认证附加数据必须
|
/-- Organization secret version 的信封绑定上下文(`PINNED`, ADR-0024):认证附加数据必须
|
||||||
同时绑定 organization、connection、secret version 与 purpose,因此密文不能跨行、跨 org、
|
同时绑定 organization、connection、secret version 与 purpose,因此密文不能跨行、跨 org、
|
||||||
跨 connection 或跨用途替换。各标识符的数据库表示属于 plumbing,这里保持 opaque。 -/
|
跨 connection 或跨用途替换。各标识符的数据库表示为实现细节,这里保持 opaque。 -/
|
||||||
structure OrganizationSecretBinding
|
structure OrganizationSecretBinding
|
||||||
(OrganizationId ConnectionId SecretVersionId Purpose : Type) where
|
(OrganizationId ConnectionId SecretVersionId Purpose : Type) where
|
||||||
/-- secret 所属 organization(`PINNED`, ADR-0024)。 -/
|
/-- secret 所属 organization(`PINNED`, ADR-0024)。 -/
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import Spec.Prelude
|
|||||||
|
|
||||||
ADR-0004:权限走"飞书云文档式"——grant(`resource + principal + role`)与 settings
|
ADR-0004:权限走"飞书云文档式"——grant(`resource + principal + role`)与 settings
|
||||||
分离;role 取自封闭的 `read / edit / manage`,且 **read ⊂ edit ⊂ manage** 累积赋能;
|
分离;role 取自封闭的 `read / edit / manage`,且 **read ⊂ edit ⊂ manage** 累积赋能;
|
||||||
强制释放锁是 **admin-only**,在 role 体系之外。本模块把这套结构与"高 role 含低
|
强制释放锁是 **admin-only**,在 role 体系之外。
|
||||||
role 全部能力"的单调性钉死。
|
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
|
|||||||
@@ -4,16 +4,14 @@ import Spec.System.Permission
|
|||||||
/-!
|
/-!
|
||||||
# PermissionGrant —— 授权与设置(ADR-0004)
|
# PermissionGrant —— 授权与设置(ADR-0004)
|
||||||
|
|
||||||
ADR-0004 的"飞书云文档式"权限:**grant**(`resource × principal × role`)与 **settings**
|
ADR-0004 的"飞书云文档式"权限:grant(`resource × principal × role`)与 settings
|
||||||
(各 policy 旋钮)分离;role 决定"谁能"(能力,见 `Permission`),settings 决定"此资源
|
(各 policy 旋钮)分离;role 决定能力(见 `Permission`),settings 决定"此资源是否
|
||||||
是否开某类操作"(策略)。本模块把 grant/settings 的结构钉死——`Permission` 已落 role 能
|
开某类操作"。
|
||||||
力格,本模块补"授权如何挂到资源/主体上"。
|
|
||||||
|
|
||||||
principal 子类型学(user/chat/department/…)与各 policy 值域均为 `OPEN`(ADR 未定,非本
|
principal 子类型学(user/chat/department/…)与各 policy 值域 `OPEN`。role-capability
|
||||||
层分歧点)。**role-capability 与 settings-policy 如何组合成最终授权决策**亦 `OPEN`——
|
与 settings-policy 如何组合成最终授权决策亦 `OPEN`——ADR-0004 把二者列为分离的闸,
|
||||||
ADR-0004 把二者列为分离的闸,但未明文规定组合规则(AND?settings 能否超出 role?),实现
|
但未明文规定组合规则。ADR-0020 约束 TEAM principal 授权 PROJECT resource 时必须同
|
||||||
须 surface,不得默认。ADR-0020 另行钉死 TEAM principal 授权 PROJECT resource 时必须
|
organization,见 `Spec.System.Organization`。
|
||||||
同 organization;该 tenant well-scopedness 见 `Spec.System.Organization`。
|
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
@@ -45,9 +43,8 @@ structure PermissionGrant where
|
|||||||
role : Role
|
role : Role
|
||||||
|
|
||||||
/-- 资源策略设置(`PINNED` 结构 + 六旋钮, ADR-0004 `PermissionSettings`):与 grant 分离,
|
/-- 资源策略设置(`PINNED` 结构 + 六旋钮, ADR-0004 `PermissionSettings`):与 grant 分离,
|
||||||
控制"此资源是否开某类操作"。六旋钮由 ADR 逐字列名;各旋钮值域 `OPEN`(ADR 未定,非本层
|
控制"此资源是否开某类操作"。六旋钮由 ADR 逐字列名;各旋钮值域 `OPEN`(ADR 未定)。
|
||||||
分歧点)。共享同一 opaque `Policy` 类型:契约只钉死"旋钮存在且相互独立",不钉死"各旋钮
|
共享同一 opaque `Policy` 类型:契约只约束"旋钮存在且相互独立";值域是实现/后续 ADR 的事。 -/
|
||||||
值域互异"——值域是实现/后续 ADR 的事。 -/
|
|
||||||
structure PermissionSettings where
|
structure PermissionSettings where
|
||||||
/-- 设置所属资源(`PINNED`, ADR-0004)。 -/
|
/-- 设置所属资源(`PINNED`, ADR-0004)。 -/
|
||||||
resource : Resource I ArtifactId
|
resource : Resource I ArtifactId
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import Spec.Prelude
|
|||||||
单一平级管理员角色、绑定身份的 invitation、可撤销服务端 session、mutation 与平台审计
|
单一平级管理员角色、绑定身份的 invitation、可撤销服务端 session、mutation 与平台审计
|
||||||
同成同败、最后管理员保护,以及无常驻账号的双因子离线恢复。
|
同成同败、最后管理员保护,以及无常驻账号的双因子离线恢复。
|
||||||
|
|
||||||
本模块只钉死这些会导致安全边界分歧的语义。cookie 属性、token hash、具体 TTL、审计
|
这些安全边界语义见下。cookie 属性、token hash、具体 TTL、审计
|
||||||
字段表示/保留期、recovery key 介质和 CLI/SQL 机制仍为 `OPEN`,由对应实现决策承载。
|
字段表示/保留期、recovery key 介质和 CLI/SQL 机制 `OPEN`。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
|
|||||||
@@ -3,26 +3,23 @@ import Spec.Prelude
|
|||||||
/-!
|
/-!
|
||||||
# ProjectGroup —— 飞书项目群作为协作空间(ADR-0001)
|
# ProjectGroup —— 飞书项目群作为协作空间(ADR-0001)
|
||||||
|
|
||||||
ADR-0001 的核心:一个 project 对应一个**长生命周期**飞书项目群;群是协作空间,**不是锁
|
一个 project 对应一个长生命周期飞书项目群;群是协作空间,不持锁(锁归 `AgentRun`,
|
||||||
owner**(锁归 `AgentRun`,见 `Lock` / ADR-0002),不是临时处理 session。群可在无 Claude
|
见 `Lock` / ADR-0002)。群可在无 agent 处理时保持开启;教师离群/静音与项目权限、
|
||||||
处理时保持开启;教师离群/静音与项目权限、与 Claude 生命周期相互独立。本模块钉死
|
与 agent 生命周期相互独立。
|
||||||
project↔group 的**active**一对一绑定——likec4 画得出"project has group",画不出"恰好一个、
|
|
||||||
且群不持锁"。
|
|
||||||
|
|
||||||
**绑定历史(`PINNED`, ADR-0021):** active binding 严格 1:1;实现可以保留 archived
|
**绑定历史(`PINNED`, ADR-0021):** active binding 严格 1:1;实现可保留 archived
|
||||||
historical binding rows 供审计/纠错,但 `GroupBinding` 谓词只刻画当前 active 快照。
|
historical binding rows 供审计,但 `GroupBinding` 谓词只刻画当前 active 快照。
|
||||||
群解散/不可达的自动化处理仍为 `OPEN`;pilot 纠错由 org admin 显式归档绑定。
|
群解散/不可达的自动化处理 `OPEN`;pilot 纠错由 org admin 显式归档绑定。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
|
|
||||||
variable (I : Identifiers)
|
variable (I : Identifiers)
|
||||||
|
|
||||||
/-- 飞书项目群(`PINNED` 长生命周期协作空间, ADR-0001)。承载 project 与飞书 chat 的绑定;
|
/-- 飞书项目群(`PINNED` 长生命周期协作空间, ADR-0001)。承载 project 与飞书 chat 的
|
||||||
**不是锁 owner**(锁归 `AgentRun`,见 `Lock`);不是临时 session。 -/
|
绑定;不持锁(锁归 `AgentRun`,见 `Lock`)。 -/
|
||||||
structure ProjectGroup where
|
structure ProjectGroup where
|
||||||
/-- 群对应的飞书 chat(`PINNED` 关系, ADR-0001 "one project has one Feishu project
|
/-- 群对应的飞书 chat(`PINNED` 关系, ADR-0001;chat 标识见 `Identifiers.ChatId`)。 -/
|
||||||
group";chat 标识见 `Identifiers.ChatId`)。 -/
|
|
||||||
chat : I.ChatId
|
chat : I.ChatId
|
||||||
|
|
||||||
/-- 项目↔active 群绑定表(`PINNED` 每项目至多一个 active 群, ADR-0001/0021)。
|
/-- 项目↔active 群绑定表(`PINNED` 每项目至多一个 active 群, ADR-0001/0021)。
|
||||||
@@ -30,9 +27,9 @@ structure ProjectGroup where
|
|||||||
自带);良构补另一半——单射。 -/
|
自带);良构补另一半——单射。 -/
|
||||||
def GroupBinding := I.ProjectId → Option I.ChatId
|
def GroupBinding := I.ProjectId → Option I.ChatId
|
||||||
|
|
||||||
/-- Active 绑定良构:**单射**——不同 project 不绑同一 active chat(`PINNED` 1:1 的另一半,
|
/-- Active 绑定良构:单射——不同 project 不绑同一 active chat(`PINNED`, ADR-0001/0021)。
|
||||||
ADR-0001/0021)。"每 project 至多一个群"由 `Option` 结构自带;这条钉死"每群至多属于一个
|
"每 project 至多一个群"由 `Option` 结构自带;这条约束"每群至多属于一个 project"。
|
||||||
project"。archived historical bindings 不在本快照不变式内。 -/
|
archived historical bindings 不在本快照不变式内。 -/
|
||||||
def GroupBinding.WellFormed (b : GroupBinding I) : Prop :=
|
def GroupBinding.WellFormed (b : GroupBinding I) : Prop :=
|
||||||
∀ p₁ p₂ c, b p₁ = some c → b p₂ = some c → p₁ = p₂
|
∀ p₁ p₂ c, b p₁ = some c → b p₂ = some c → p₁ = p₂
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import Spec.Prelude
|
|||||||
/-!
|
/-!
|
||||||
# ProjectWorkspace —— project explorer 与飞书建项入口(ADR-0021)
|
# ProjectWorkspace —— project explorer 与飞书建项入口(ADR-0021)
|
||||||
|
|
||||||
ADR-0021 把 org 后台里的"文件管理器式"项目管理收口为透明 folder + project:
|
org 后台里的"文件管理器式"项目管理:folder 只负责导航、排序、层级与用量聚合,当前
|
||||||
folder 只负责导航、排序、层级与用量聚合,当前不是权限资源。project 仍是授权边界。
|
不是权限资源。project 仍是授权边界。
|
||||||
|
|
||||||
本模块只钉死会影响实现分歧的不变量:folder/project 同 org、folder 不参与权限、普通成员
|
不变量:folder/project 同 org、folder 不参与权限、普通成员从飞书群创建 project 受
|
||||||
从飞书群创建 project 必须受 org policy 控制。folder visibility/team policy/继承授权仍为
|
org policy 控制。folder visibility/team policy/继承授权 `OPEN`。
|
||||||
未来扩展,不得在当前实现中半隐式加入。
|
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
@@ -39,7 +38,7 @@ def ProjectFolderPlacement.WellScoped
|
|||||||
∃ o, projectOrg placement.project = some o ∧ folderOrg placement.folder = some o
|
∃ o, projectOrg placement.project = some o ∧ folderOrg placement.folder = some o
|
||||||
|
|
||||||
/-- Folder 当前透明(`PINNED`, ADR-0021):folder 不是权限资源,不持有 grants,移动 project
|
/-- Folder 当前透明(`PINNED`, ADR-0021):folder 不是权限资源,不持有 grants,移动 project
|
||||||
不改变 project 自身授权。未来 folder policy 若出现,必须新增显式语义而不是复用本谓词。 -/
|
不改变 project 自身授权。未来 folder policy 若出现,须新增显式语义。 -/
|
||||||
structure FolderTransparent where
|
structure FolderTransparent where
|
||||||
/-- 透明性命题本身;字段存在是为了让 contract 明确可引用(`PINNED`, ADR-0021)。 -/
|
/-- 透明性命题本身;字段存在是为了让 contract 明确可引用(`PINNED`, ADR-0021)。 -/
|
||||||
current : True
|
current : True
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Spec.Prelude
|
|||||||
|
|
||||||
用户实体见 `Hierarchy.User`;外部连接见 `Spec.System.Connections`。
|
用户实体见 `Hierarchy.User`;外部连接见 `Spec.System.Connections`。
|
||||||
|
|
||||||
用户创建当前只钉管理员直接创建;飞书自助注册→管理员审批未钉死(`OPEN`)。
|
用户创建当前只定义管理员直接创建;飞书自助注册→管理员审批 `OPEN`。
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Spec.System
|
namespace Spec.System
|
||||||
|
|||||||
Reference in New Issue
Block a user