import Spec.Prelude /-! # ProjectGroup —— 飞书项目群作为协作空间(ADR-0001) 一个 project 对应一个长生命周期飞书项目群;群是协作空间,不持锁(锁归 `AgentRun`, 见 `Lock` / ADR-0002)。群可在无 agent 处理时保持开启;教师离群/静音与项目权限、 与 agent 生命周期相互独立。 **绑定历史(`PINNED`, ADR-0021):** active binding 严格 1:1;实现可保留 archived historical binding rows 供审计,但 `GroupBinding` 谓词只刻画当前 active 快照。 群解散/不可达的自动化处理 `OPEN`;pilot 纠错由 org admin 显式归档绑定。 -/ namespace Spec.System variable (I : Identifiers) /-- 飞书项目群(`PINNED` 长生命周期协作空间, ADR-0001)。承载 project 与飞书 chat 的 绑定;不持锁(锁归 `AgentRun`,见 `Lock`)。 -/ structure ProjectGroup where /-- 群对应的飞书 chat(`PINNED` 关系, ADR-0001;chat 标识见 `Identifiers.ChatId`)。 -/ chat : I.ChatId /-- 项目↔active 群绑定表(`PINNED` 每项目至多一个 active 群, ADR-0001/0021)。 `ProjectId → Option ChatId` 的结构本身即"一个 project 至多绑一个 active 群"(由 `Option` 自带);良构补另一半——单射。 -/ def GroupBinding := I.ProjectId → Option I.ChatId /-- Active 绑定良构:单射——不同 project 不绑同一 active chat(`PINNED`, ADR-0001/0021)。 "每 project 至多一个群"由 `Option` 结构自带;这条约束"每群至多属于一个 project"。 archived historical bindings 不在本快照不变式内。 -/ def GroupBinding.WellFormed (b : GroupBinding I) : Prop := ∀ p₁ p₂ c, b p₁ = some c → b p₂ = some c → p₁ = p₂ end Spec.System