import Spec.Prelude import Spec.System.Run /-! # AgentSurface —— Agent 执行面边界(ADR-0018) ADR-0001/0002/0004 覆盖"协作治理"直到 `triggerAgent`:谁能触发一次 run。但触发之后 agent 在执行层面能干什么——读哪些文件、跑什么命令——任何 ADR / 散文都未定。ADR-0017 落地时采用 Claude Code SDK 的 `bypassPermissions` + 全量 Read/Write/Bash/Glob/Grep, agent 的文件与 shell 面对宿主**无界**:spec 与 ADR 均未钉死边界。本模块补这一层。 钉死的不变式:agent 在一次 run 内发起的文件操作,其路径必须落在该 run 所属 project 的工作区目录内(ADR-0007:工程文件是目录树;此 ADR 固定"agent 操作落在该树内")。 逃逸即越权,拒绝。与 `Lock`(ADR-0002)正交:Lock 限定**并发**(谁在改),Surface 限定**波及面**(能改到哪)。二者都按 run × project 作用域。 shell 面的边界(命令的文件效果同样不得逃逸工作区)是同一不变式的推论,但**机制** ——路径校验工具包装、OS 级沙箱(bubblewrap/容器)、SDK 权限钩子,或其组合——`OPEN` (ADR-0018)。契约钉死不变式,不钉死机制。 -/ namespace Spec.System variable (I : Identifiers) (Path : Type) /-- Agent 在一次 run 内发起的文件操作(`PINNED` 关系, ADR-0018)。由某 run 发起、 指向某路径;是否越权由下方 `Authorized` 钉死。 -/ structure AgentFileOp where /-- 发起操作的 run(授权上下文主体, ADR-0018;与 `Lock` 同作用域 run × project)。 -/ run : I.RunId /-- 操作目标路径(`PINNED` 字段, ADR-0018)。 -/ path : Path /-- 工作区边界良构:run 的文件操作路径必须落在该 run 所属 project 的工作区目录内 (`PINNED` 平台核心安全不变式, ADR-0018)。`runWorkspace` 与 `pathWithin` 均由平台提供 (表示 `OPEN`——路径如何表示、"在内"如何判定是纯 plumbing,非本层分歧点);本谓词只 钉死"操作路径必须以 run 的工作区为根",杜绝 agent 越权读写宿主任意文件。 -/ def AgentFileOp.Authorized (op : AgentFileOp I Path) (runWorkspace : I.RunId → Option Path) (pathWithin : Path → Path → Prop) : Prop := ∃ w, runWorkspace op.run = some w ∧ pathWithin op.path w end Spec.System