docs(workflow): register approved governance implementation scope

This commit is contained in:
weichen
2026-09-21 13:03:34 +00:00
parent a241e83815
commit eb4dbdca5b
5 changed files with 611 additions and 0 deletions
@@ -0,0 +1,234 @@
---
title: "Agent 工作规范增删改审查"
status: done
created: 2026-09-21
owner: Codex
reviewed_dev_sha: a241e838150f218f3a09d3523f93291b847d45fd
implementation_status: not_started
---
# Agent 工作规范增删改审查
## 结论
现有方向合理:任务 worktree、主目录保护、串行集成、真实证据和安全清理应继续保留。当前最值得做的是**消除冲突、减少重复维护、让关键门禁可执行**,不是继续扩充一份越来越长的 AGENTS。
本轮建议集中为 10 组增删改与 2 项安全补充观察。它们不都是缺陷:下文区分已验证问题、流程简化建议与已有方案的实施事项。只形成审查结果,没有修改生效规则、脚本、锁、运行环境或业务代码。
已确定的用户选择不重新讨论:全部新增写入走 `.worktrees`;锁先交付统一入口与提交门禁防误改,OS 权限隔离后续实施;本轮是规范审查,不是实施授权。
## 1. 审查范围与现场
冻结基线为本地 `dev@a241e838`,审查在 `.worktrees/agent-policy-review` 进行。覆盖 AGENTS、PROJECT、worktree 工作规范、Cursor 四条规则、任务/收口/handoff 模板、Herdr roster,并检查相关脚本与测试入口。
主目录采样为干净 dev;未 fetch 或推送。本轮新分支只写审查记录和自己的 CURRENT 快照,不修改被审查规范。
实际测量:
- 基线 CURRENT 并行认领共有 **161 条**:158 条 done、2 条 in_progress、1 条 cancelled。新增本轮认领后为 162 条;不把本轮新增记录算成基线问题。
- 基础启动链六份文件合计 **71,205 字符**,这是文件字符数,不是模型 token 数或耗时指标。
- CURRENT 焦点有 5 项,而 AGENTS 要求 1–3 项;其中长期红线混在当前焦点中。
- 之前的规范收口 `d5302a76` 与 `.locks` 方案 `5987bdcd` 均不是本轮基线 dev 的祖先,不能把它们当作所有 Agent 已能读取的生效规则。
- 本轮没有运行 Go、前端、数据库或产品 PI 测试;命令问题来自源码筛选条件核查,不宣称本轮复现了产品运行故障。
## 2. 优先级总表
“先修”是工程流程优先级,不改变产品 FEATURE-MATRIX 或 production_ready。
| ID | 类别 | 建议动作 | 优先级 | 直接收益 |
|---|---|---|---|---|
| R01 | 已验证冲突 | 修改测试范围与验收模型规则 | 先修 | 消除纯文档也被要求真实 PI 的矛盾 |
| R02 | 已验证命令问题 | 修改真实 PI 示例为准确、可核验的入口 | 先修 | 避免漏测而误以为完成全链路 |
| R03 | 流程简化建议 | 新增任务分级,允许一个主文档承载小任务 | 第二批 | 少建重复记录,减少共享文件写入 |
| R04 | 已验证膨胀/不一致 | 精简 CURRENT 和启动读取范围 | 第二批 | 活跃冲突更易发现,降低每轮上下文成本 |
| R05 | 已验证状态矛盾 | 修改会话结束与任务完成定义 | 先修 | 防止为了结束会话把未完成任务写成 done |
| R06 | 已验证过强要求 | 删除固定五层提交顺序,保留逻辑原子性 | 第二批 | 代码与测试一起可验证、可回退 |
| R07 | 已验证引用问题 + 结构调整 | 确立规范唯一来源与生效版本 | 先修 | 避免客户端副本、草案和历史记录互相覆盖 |
| R08 | 规范增强建议 | 新增任务授权记录与例外处理边界 | 第二批 | 授权内持续执行,超范围才停下确认 |
| R09 | 已知方案实施事项 | 优先落实最小工具门禁 | 与先修并行规划 | 把已知运维误操作挡在执行前 |
| R10 | 收口流程增强 | 明确清理执行者、保留原因和复查触发 | 第二批 | 已完成 worktree 不再长期无主积累 |
## 3. 具体增删改
### R01 修改:测试要求必须按变更范围生效
**依据**:`AGENTS.md:118`、`PROJECT.md:118` 明确纯工程规范/文档不调用产品 PI;`.cursor/rules/test-reports-standard.mdc:49,61` 仍要求报告包含全量 Go 回归,并在报告生成前做真实 PI 全链路。后者是 alwaysApply。旧收口分支虽包含相关澄清,但尚未进入本轮基线 dev。
**后果**:Agent 依据不同入口可能运行无关长测试、误动共享服务,或把必要测试当作可选。冲突本身应先消除,不能依靠“Agent 应该理解”。
**建议修改**:测试范围统一在一处定义,PROJECT 和客户端规则引用它:
| 变更 | 必要验证 |
|---|---|
| 纯规范/普通文档 | 差异、链接、状态与指令一致性 |
| 治理脚本 | 沙盒临时仓库中的真实分支、锁、退出与拒绝路径;不以 shell 语法检查替代行为验证 |
| Go/接口 | 对应单测、项目 Go/架构门禁,受影响 PG/鉴权负例 |
| 前端 | 对应测试和构建;受影响交互用真实浏览器 |
| 迁移/运行配置 | 独立环境升级、兼容性、回退/前滚条件及就绪验证 |
| 产品 Agent/工作流 | 受影响真实产品 PI 链路;不得以 stub/SKIP 替代 |
固定七段报告模板改为“完整报告模板”,小型文档/脚本验证可用精简报告或任务内验证节;必须保留实际命令、结果、提交与适用范围。不要删除真实性要求,也不允许把未运行记作 PASS。
模型要求按目标环境的已批准配置核验并记录实际值。`PROJECT.md:118` 的固定 M2.7-highspeed 不能不分环境套用:当前 dev Compose 默认 M2.7-highspeed,而 test/main Compose 默认 M3。这里是配置源码差异,未检查运行中的秘密配置;建议保留环境策略,禁止为“满足文档”自行切换模型。
### R02 修改:真实 PI 命令要准确选择测试并证明没有跳过
**依据**:`PROJECT.md:91–92` 使用 `RUN_PI_E2E=1 ... go test ./... -run 'PI'`。测试名 `TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E`(`internal/server/piagent_e2e_test.go:66`)及 `TestWorkflowGovernance_PiAgent_PG_*`(同模块的 `workflow_governance_piagent_pg_test.go:264,278,293`)不匹配大小写敏感的 `PI`。
**后果**:命令执行范围与“全链路”的名称不一致;配置缺失还可能让数据库用例跳过。退出码 0 不能单独证明验收完成。
**建议修改**:优先引用已有 `scripts/run-nightly-real-pi.sh` 作为明确基线入口,写清独立 TEST_DATABASE_URL、Runner 认证、KB/运行环境要求。该脚本当前仅选 U8 和 FullNoneMixedChain 两类测试,**不能把它表述为覆盖全部工作流**;任务按变更范围追加精确测试名与浏览器验收。增加 expected-tests 与实际执行/SKIP 对照,保存最终提交、配置与证据。
不得在文档中填写真实凭证,也不运行测试来试探生产数据。
### R03 新增:任务分级;删除小任务必须重复建多份记录的要求
**依据**:`AGENTS.md:12,37,41–44` 要求任何任务落盘、任务文、研究/审计产物、验收及交接;没有最小产物集或合并记录的规则。
**建议**:保留“需要审计的工作必须有持久证据”,明确三档:
- **信息答复**:解释已有结果、查询简单状态,且不产生新决策、持久成果、仓库写入或运行副作用,可直接答复;不为一次答复单独开 worktree。若要写入任何成果,仍进入任务 worktree。
- **单一小任务/有价值的只读审查**:一个任务文或专用 audit/research 主文档可同时承载范围、结论、验证、状态和交接;不强制再复制同一内容到另外三份文档。
- **跨模块、多阶段、数据/部署任务**:完整 task、必要 plan、验证报告、handoff;仅在信息确实独立时拆文件,互相链接而不复制全文。
本次这样的实质规范审查仍须落盘,不能以“只读”免除证据。将相关追问、修正与收口归入原 task_id;只读子审查使用父任务的范围和记录,不为每个 reviewer 再开业务任务链。无关新增任务才从 dev 建新分支。
这项改变需要审核采纳;本轮仍遵守现有落盘规则,没有提前使用豁免。
### R04 修改:CURRENT 只承载活跃协调,历史留索引
**依据**:CURRENT 161 条认领中 158 条已完成;`AGENTS.md:132` 要求 1–3 焦点,当前正文有 5 项。
**建议删除/迁移**:从 CURRENT 活跃表移出已完成/取消且没有后续阻塞的行,历史 owner、branch、worktree、证据在归档任务/历史索引保留。将长期红线独立为受控约束区或链接;它不是每天反复排序的焦点。
**建议保留**:正在进行、阻塞、等待集成及仍需清理的事项。cleanup_pending 是清理/操作阶段,不新增为 task.status 的第六种状态;一行可写任务 done、cleanup pending,并给 owner、原因和下次检查条件。
**启动读取修改**:每会话先读短核心规则、项目入口、活跃状态摘要;编码前按范围补读相关模块标准、相关 FEATURE-MATRIX 行、任务/方案及操作规程。发布才读完整发布门禁。不要通过摘要跳过硬红线,也不要要求每次解释一个已知结果都重读全部历史。
模块开发任务应有明确条件指针指向已有 `.doc/system-design/2026-09-20-module-development-standards.md`,复用现有接口/事件/表写者规则,不新造一套编码规范。
### R05 修改:会话结束、任务完成、合入与清理分别判定
**依据**:收口模板第 3 行适用于“任务完成或切换 Agent”,第 22 行却无条件要求 `status=done`;AGENTS 同时允许 blocked/cancelled。任务模板已有 deployment/cleanup 字段,但缺少明确的结果判定与集成/同步状态。
**建议替换收口条件**:
> 会话结束不等于任务完成。根据实际情况保留 in_progress、blocked、cancelled 或 done;只有任务范围内的验收条件满足才能 done。换 Agent 必须记录剩余工作及接管条件。只有终态任务才归档;不得为了归档改成 done。
为任务记录补充按需字段:`review_state`、`integration_state`、`deployment`、`cleanup`、`remote_sync`。例如“方案研究 done、review pending、未合入、deployment not_required”是合法状态;“代码已合入、部署 failed”不能报交付完成。字段由工具生成优先,避免人工重复维护多张表。
研究/审查的验收是有据可审的产物,不要求把未获实施授权的方案部署到 dev。实现任务的 done 则按其获授权交付范围判定。收口报告始终区分本地提交、dev 合入、实际运行版本和远端状态。
### R06 删除:固定按数据库、服务、API、测试、文档分层提交的硬性顺序
**依据**:`.cursor/rules/git-workflow-and-environments.mdc:33–38` 规定“一个任务必须”按五类依次提交;AGENTS 的原子提交目标是一个逻辑变更一批。
**后果**:小修复也被机械拆分,代码与对应测试分离;一些提交无法独立构建/验证,回退时还可能留下半套契约。
**建议替换**:
> 每个提交围绕一个可解释、可验证、可回退的逻辑变更;实现与其回归测试可同批。迁移、兼容阶段、配置或文档只有在独立审查/回退有价值时拆分,不要求每项任务凑齐固定提交层次。
保留 Conventional Commits、明确文件范围、渐进式交付和独立 worktree;不以“原子”为名把无关改动揉成一批。
### R07 修改:规范来源、生效状态与客户端薄入口
**已验证的小错误**:`.cursor/rules/git-secrets-autonomy.mdc:2,8` 把 Secrets 指向 AGENTS §8,实际在 §9。AGENTS 开头称可整文件复制到任意项目,但正文包含本仓库日期路径、脚本和 Herdr 约定;应改为“可复用基线,项目路径/流程需调整”。
**建议新增规范生命周期**:每项规则记录 proposed/approved/active/deprecated 的规则状态、适用范围、生效提交与 owner;工具能力另记 manual/enforced。这里是规则生命周期,不复用任务 status。
外层系统约束和当前用户授权仍有效;项目内部规则冲突时有明确处理:AGENTS 保存通用硬边界,PROJECT 定义其授权范围内的项目细则,专门 runbook 负责操作流程;客户端入口只引用同一来源,不复制一套近似规则。草案、旧审计和历史报告属于证据,不能自行覆盖生效规则;较新的日期不等于已生效。
此前收口和锁方案未进入当前 dev,说明“已经写好/提交”与“已被所有新任务读取”必须分开。旧任务启动时记录 policy revision,集成前重读当前 dev 的相关生效规则;期间发生变化时做差异检查,不默默套旧规则,也不突然按未来未实施机制阻塞旧任务。
删除 PROJECT 中重复的“当前已无 blocker”等长期硬编码断言,改为引用有日期/制品身份的权威门禁结果。模型、schema、角色可用性等动态值记录在环境/执行收据中;不要在多个入口重复写一份可能过期的“当前值”。
### R08 新增:任务授权记录与例外边界
这是一项规范增强建议,不是声称现有 Agent 已越权。现有手册限制自动审批扩权、push 和破坏性操作,但任务模板只有范围/非目标,没有统一记录“这次到底获准做到哪一步”。
建议任务创建时记录:任务类型(研究/实现/运维)、用户目标、允许写路径、可执行环境、交付终点及明确禁止项。已授权范围内自主持续执行,不在每个 Git/测试步骤重复确认;分析和方案请求默认不包含业务实施。
只有扩大业务范围、增加外部写入、操作未授权环境或破坏性恢复等才重新确认。push 仍遵守明确授权规则;凭证存在不代表允许推送。合理默认写进任务模板,不用每次都问用户一张权限问卷。
紧急/迁移例外需记录 owner、原因、范围、期限/退出条件和恢复动作;例外仅覆盖明确条款。`AGENTS.md:29` 的紧急热修免启动阅读不能被解释为允许主目录直接开发、删库或取消验收。
### R09 落实:先做最小执行门禁,不再只增加禁止句
这是上一治理/锁方案已承认的工程任务,不作为“新发现的缺失要求”重复计数。
**已有证据**:AGENTS 已禁用旧 helper 的 create/remove;源码仍包含省略 dev 起点和强制删除。env-service 的根目录来自脚本所在树,缺少执行目录/锁守卫。CURRENT 第 11 行及关联 MinerU 报告已记录一次 worktree rebuild 引起数据挂载漂移,说明风险并非仅理论;本轮未重演该事故。
**建议实施顺序**:
1. 修 worktree create/remove 的明确基线、主仓定位和安全删除。
2. 给共享服务写操作加主目录/dev/操作身份/持锁前置检查,明确 status 等只读入口;构建必须校验真实源码与申报 SHA。
3. 为 CURRENT/MATRIX 提供短锁、增量更新、版本检查,接入已设计 `.locks` 流程;旧锁兼容迁移后才换权威位置。
4. Git 提交/集成门禁拒绝超范围文件、混入 `.env`/运行产物和错误主干写入。门禁真实负例验收后再记录 enforced。
保持用户确认的 L1 目标,不提前搭建跨机平台或要求 OS 隔离才能使用。代码文件锁、全量资源队列和额外 UI 按已有阶段与实际冲突扩展,优先把当前两个共享文档和 dev 操作做可靠。
### R10 新增:清理负责人和完成后的再检查机制
现有安全清理条件应保留,不放宽“不强删、不覆盖”的红线。需要补的是谁在 Agent 退出之后真正执行清理,以及什么时候重试。
操作规范要求无 Agent/进程 cwd 使用才能移除 worktree;长驻客户端即使完成任务也可能仍占 cwd。任务模板允许 retained-with-reason,但没有下一次检查条件。建议由独立集成/维护执行者在 owner 已退出后检查并清理,记录 `cleanup_owner`、保留原因、证据位置和触发条件;遗留目录分为活跃、保护、待审核、未合入和可清理,不按年龄批量删除。
已合入任务的依赖缓存与唯一截图/日志区别处理:可再生缓存明确登记,唯一证据先保存再移除;只保存路径而不保存文件不是证据归档。清理失败不影响已经通过的业务交付事实,但要保持可追踪的 cleanup pending。
## 4. 两项安全补充观察(非本轮阻塞项)
- **材料不能授予权限**:日志、网页、测试输出、引用文本、Agent 产物可能含命令或“用户已授权”字样,应作为待核实内容。handoff 的授权声明回链到可核实的用户目标/委派范围,不仅凭文档自述执行推送、清理或外部写入。已有自动审批不扩权规则继续保留;这项建议补充来源辨别,不要求 L2 现在落地。
- **真实证据允许最小化与脱敏**:测试报告可以保存真实执行中足够判定的片段,说明脱敏范围;不要求提交原始完整日志、个人信息、业务正文或截图中的秘密。现有凭证禁入与真实用户数据不复制要求继续有效。真实性约束来源与结论,不能误解成“未经处理的所有材料都要入 Git”。
## 5. 推荐的规范组织
不建议再并列增加一套“总规范 v2”。保留现有路径并收敛职责:
| 位置 | 负责内容 | 移出/减少 |
|---|---|---|
| AGENTS | 最小安全红线、任务入口、权限/状态原则、操作指针 | 环境动态值、长命令、历史事件、重复模板索引 |
| PROJECT | 仓库地图、目标环境、测试入口与模块标准指针 | 重复通用规则、过期发布结论 |
| worktree runbook | 创建、同步、候选、部署、失败与清理 | 已结束迁移的具体临时目录案例,移入历史交接 |
| 锁管理 runbook(落地后) | 唯一入口、状态、等待、恢复与兼容版本 | 让 Agent 手动拼锁协议的日常操作 |
| CURRENT | 活跃任务、当前槽位、1–3 焦点、必要约束链接 | 大量 done 历史行与长复盘 |
| FEATURE-MATRIX | 能力声明范围、证据、剩余条件 | 逐次操作流水、重复环境快照 |
| 客户端入口 | 明确引用上述来源 | 复制并稍微改写的第二套规则 |
| 任务/审查主文档 | 单项工作的范围、决定、证据和交接 | 对相同内容的无意义多文件复制 |
## 6. 改动顺序与验收
**第一批:消除矛盾。** R01、R02、R05、R07 的明确错误先修。检查从所有客户端入口读取后,纯文档、业务修复、暂停交接、取消任务、真实 PI 验收五种场景都得到一致决策。
**第二批:减少流程负担。** 采纳 R03/R04/R06/R08/R10 后更新模板与薄入口;历史只迁移、不删除。验证信息问答不触发无意义写入,实质审计有唯一主产物,代码与测试能形成完整逻辑提交,未完成任务不会被强制 done。
**第三批:工具实现。** R09 与既有 `.locks` 分阶段方案合并为一个实施队列,不重复造项目。用两个并行任务、锁冲突、旧版本共享文档、错误工作区部署、异常退出和清理拒绝的真实证据验收。当前 user-approved 的 L1 防误改边界不变。
规范检查可以自动化为轻量 `doctor/lint`:本地链接、必需字段/状态、过期 waiver、活跃认领冲突、测试入口存在、脚本能力版本与规范声明对齐。没有明确规则契约的模糊 prose lint 不作硬失败,也不为文案偏好构造复杂测试。
## 7. 审查覆盖与可信度
使用 ce-doc-review 非交互只读流程,审查依据为上述实际文件及脚本,而非仅凭历史记忆。
| 审查视角 | 结果 | 本报告处理 |
|---|---|---|
| 一致性(独立上下文) | 3 项 | 复用声明/引用合入 R07,焦点上限合入 R04 |
| 可执行性(独立上下文) | 1 项 | PI 测试筛选问题合入 R02,主审已核对源码 |
| 范围/减负(独立上下文) | 3 项 | 合入 R03/R04;保留实质审计必须落盘,收窄纯只读豁免 |
| 安全(独立上下文) | 2 项观察,置信锚 50 | 仅列为 §4 补充观察,不当作已证实漏洞 |
| 反例审查(独立上下文) | 0 项新增缺陷 | 候选 SHA、失败恢复、累计部署差异等已有引用约束,未重复提出 |
| 主审当前源核查 | 测试范围冲突、状态模板、提交顺序、动态配置与工具事实 | 补充 R01/R05/R06 等;明确区分改进建议与已知实施项 |
外部第三方 CLI 跨模型复核未执行:本轮未获得向其他外部服务发送仓库文档的显式授权;未以此阻塞会话内独立视角审查。未更改技能或项目配置来伪造关闭该步骤。
未采纳的建议形态:不把纯只读豁免扩大到有持久价值的审计;不把 cleanup_pending 塞进既有任务 status;不要求当前实现 OS 级权限隔离;不因为当前 helper 明确标为未修复,就重复说规范已承诺了不存在的能力。
**已应用规范修正:0。** 上述均是待审核建议。本轮只写审查产物与任务记录,未升级 FEATURE-MATRIX、未改 production_ready、未运行产品测试、未合入 dev 或 push。
## 8. 相关资料
- [当前工作手册](../../AGENTS.md)
- [项目入口](../../PROJECT.md)
- [已采纳工作方式](../ops/2026-09-21-agent-worktree-workflow.md)
- [既有治理方案](../remediation/2026-09-21-agent-workflow-governance-plan.md)
- `.locks` 补充方案:目前在 `feature/agent-lock-coordination-plan@5987bdcd` 的 `.doc/remediation/2026-09-21-agent-lock-coordination-plan.md`,不在本轮 dev 基线;后续合入时再建立普通相对链接。
+1
View File
@@ -15,6 +15,7 @@
| owner | task | branch | worktree | mutex | status |
|-------|------|--------|----------|-------|--------|
| Codex | 2026-09-21-agent-governance-implementation | feature/agent-governance-implementation | .worktrees/agent-governance-implementation | agent-governance | in_progress |
| Cursor | 2026-09-21-workflow-scope-weighting | feature/workflow-scope-weighting-2026-09-21 | .worktrees/workflow-scope-weighting-2026-09-21 | intent+web+docgov | done |
| Cursor | 2026-09-21-upload-parse-ux-dedup | feature/upload-parse-ux-2026-09-21 | .worktrees/upload-parse-ux-2026-09-21 | server+web+storage | done |
| Cursor | 2026-09-21-mineru-doc-parsing | feature/mineru-doc-parsing-2026-09-21 | .worktrees/mineru-doc-parsing-2026-09-21 | storage+bizdev+kb | done |
@@ -0,0 +1,56 @@
---
title: "Agent .locks 与共享文档锁机制核查"
created: 2026-09-21
status: done
confidence: high
---
# Agent .locks 与共享文档锁机制核查
## 结论
项目级 `.locks` 适合作为所有 worktree 的统一协调位置,但目录或锁文件存在本身不禁止写入。应把原子锁管理、Agent 会话、统一写入口、版本检查和故障恢复一起设计;CURRENT/FEATURE-MATRIX 尤其需要防止旧副本覆盖,而不只是防止同时写。
## 当前现场(2026-09-21 采样)
- 主目录已回到干净 `dev@99905571454281f7d14223443a51da5235d0e655`。原治理提交后的“主目录被旧任务占用”已不是当前事实。
- `.locks` 不存在;`.git/agent-control/` 存在,包含 `dev-integration.lock`、手工 `active-operation.json` 和历史治理收据。
- 采样时 active-operation 为 Cursor / upload-parse-ux / merging,但没有 pid、operation ID、base_dev_sha 等统一身份字段。`lslocks` 查询未观察到对应文件锁;这是瞬时观察,不能断言已失锁或安全抢占。
- 主仓和 linked worktree 的 CURRENT 是不同 Git 快照。dev 中旧治理 adoption 仍为 in_progress;旧任务分支有尚未合入收口,说明任务结束与文档可见状态可能不同步。
- 主机工作目录为 ext4,`flock` 来自 util-linux 2.42.3。该方案按单机本地文件系统设计,不默认支持网络文件系统或跨机器协调。
- 本轮仅从明确 dev 创建新的研究 worktree,未获取、释放、迁移或写入既有运行锁,未修改服务或产品数据。
## 源码与规则证据
| 位置 | 发现 | 方案影响 |
|---|---|---|
| `AGENTS.md` §6;`.doc/ops/2026-09-21-agent-worktree-workflow.md` §3 | 目前是本机 flock 与人工校验,明确自动协调尚未实现 | 新设计作为补充,不宣称当前已具备原子认领或强制拦截 |
| `.doc/remediation/2026-09-21-agent-workflow-governance-plan.md` §5 | 已提出共同 Git 目录内注册表与队列,但接口、过期持有者和共享文档写入协议未展开 | 本轮细化,同时提议统一到 `.locks`,旧方案路径暂不自动替换 |
| `scripts/agent-worktree.sh:5–7,50,67–69` | 从自身目录推主仓、创建未给 dev 起点、删除强制 | 新工具必须使用仓库身份及登记路径;不能把旧 helper 当作锁代理 |
| `scripts/env-service.sh` | 无锁令牌、实例身份、操作代次校验 | 只在 AGENTS 写要求不能强制阻止运行操作 |
| `scripts/herdr-agent-start.sh:97–113`、dispatch 66–77 | 主要检查 feature/fix 分支及 cwd,不具有跨工具持久会话租约 | 增加通用 CLI/会话包装,再适配客户端;不将 Herdr 作为唯一入口 |
| `.gitignore:20–36`、`.dockerignore:1–20` | 未排除整个 `.locks/`;部分 DB 后缀 ignore 不覆盖 JSON/锁/socket | 新增目录时须整体排除 Git、镜像上下文与任务清理,不依赖零散后缀规则 |
| `go.mod` 与 `go.sum` | go.sum 有历史 modernc/sqlite 条目,但 go.mod 没有当前 SQLite require | 若采用 Go+SQLite,需显式评估并加入驱动,不能把旧校验和视为已接入能力 |
| CURRENT 与 FEATURE-MATRIX | 人工 Markdown 表格、行无稳定机器 ID、多个历史状态叙述 | 先给需要自动更新的记录稳定 ID,按行/字段补丁操作;禁止覆盖全表 |
## 官方机制核验与推论
- [flock(2)](https://man7.org/linux/man-pages/man2/flock.2.html):本地 advisory lock 与打开的文件描述关联。由此推论:不同工具调用中只跑一次获取命令,命令退出后不能假定锁仍在;客户端忽略 flock 仍可写入。
- [flock(1)](https://man7.org/linux/man-pages/man1/flock.1.html):支持用一个持锁进程包裹命令。适合明确生命周期的短操作和部署执行器,不代替多轮 Agent 会话管理。
- [unlink(2)](https://man7.org/linux/man-pages/man2/unlink.2.html):删除路径不立即消灭仍被进程打开的文件。结合 flock 推论:删旧锁再建同名文件可能形成不同 inode 的两个协调域,不能用 rm 当解锁。
- [Git worktree](https://git-scm.com/docs/git-worktree):linked worktree 具有独立工作树,共享部分 Git 状态;锁根必须由 common-dir 与登记主目录定位,不能使用各自 cwd/.locks。
- [Git hooks](https://git-scm.com/docs/githooks):hooks 是 Git 生命周期入口。由此推论:提交门禁不等于普通编辑器写入拦截,也不自动覆盖所有 Git 更新命令。
- [SQLite transaction](https://www.sqlite.org/lang_transaction.html):同一时刻只有一个写事务;短事务可原子完成多资源冲突检查与租约登记。不能把多小时开发装入数据库事务。
- [SQLite WAL](https://www.sqlite.org/wal.html):允许读写并行,但要求同机,不能推广为网络共享锁。WAL/备份、checkpoint 与版本兼容需要验收。
- [rename(2)](https://man7.org/linux/man-pages/man2/rename.2.html):单次重命名的原子性不等于 CURRENT、FEATURE-MATRIX、SQLite 与 Git 的跨介质事务;需要操作记录、恢复及 Git 提交作为发布边界。
- [Landlock](https://man7.org/linux/man-pages/man7/landlock.7.html):Linux 可对进程施加文件系统访问约束。属于系统级约束的候选机制,未验证本机/各客户端兼容性,不宣称已经可用。
## 用户已确认的强度
先统一操作入口与提交门禁防误改,后续再加权限隔离。方案采用 L1a–L1d 为当前交付设计,明确不提前承诺 OS 级阻止任意写入。
## 研究限制
没有实现或运行锁原型/并发测试,没有安装沙箱、改变文件权限、清理锁、读取 `.env` 内容或更改已采纳工作规范。性能目标和故障演练均为后续验收要求,不是实测结果。
[完整补充方案](../../remediation/2026-09-21-agent-lock-coordination-plan.md)
@@ -0,0 +1,40 @@
---
title: "落实 Agent 规范与 L1 操作门禁"
status: in_progress
created: 2026-09-21
updated: 2026-09-21
owner: Codex
branch: feature/agent-governance-implementation
worktree: .worktrees/agent-governance-implementation
base_dev_sha: a241e838150f218f3a09d3523f93291b847d45fd
mutex: agent-governance
review_state: approved
integration_state: pending
deployment: not_required
cleanup: pending
remote_sync: not_requested
---
# 落实 Agent 规范与 L1 操作门禁
用户已授权“按照方案实现这些规范”。范围:审查 R01–R10、两项安全补充、两个共享文档与 dev 操作的 L1 管理入口。所有修改在本任务 worktree;不改产品业务代码、数据库、模型配置,不升级 test/main,不 push。Python 标准库 sqlite3/fcntl 实现本机协调,不增加产品 Go 依赖。
## 实施单元与所有权
- 规范 Agent:AGENTS/PROJECT/客户端薄入口/模板/测试规范/CURRENT 归档,互斥 policy-docs。
- 工具 Agent:worktree helper、env-service、candidate-images-build 与对应测试,互斥 ops-scripts。
- 根 Agent:agentctl/SQLite/lease/CAS/提交与集成门禁、runbook、报告、FEATURE-MATRIX、ignore,互斥 coordination-core。
- 测试 Agent:核心独立行为测试,仅写自己的测试文件,使用临时 Git 仓库。
## 验收
- [ ] 新规范一致、轻量入口和真实状态可用;历史迁移不丢失。
- [ ] 主仓唯一 .locks;原子资源集合、父子冲突、活跃/失效身份、幂等及保守恢复。
- [ ] CURRENT/MATRIX 受控增量/CAS 更新,旧基线不覆盖,记录恢复证据。
- [ ] 错误工作区/无租约服务写入被拒;候选镜像源码 SHA 不符被拒。
- [ ] 安全 create/remove、commit/ref 门禁正反例通过。
- [ ] 独立代码审查及真实临时仓库并发验收;本地 dev 接收验证后的候选;安全清理。
## 交付边界
L1 对统一入口与 Git hooks 防误改,不能阻止任意同 UID shell 绕过。OS 沙箱、跨机锁、产品 PI 镜像交付等独立运行架构变更不在本次规范/最小门禁改动内。纯工程代码与文档不触发产品重建;将验证主目录运行挂载和就绪未因本轮改变。
@@ -0,0 +1,280 @@
---
title: "Agent .locks、共享文档与并行工作流补充方案"
status: planned
created: 2026-09-21
updated: 2026-09-21
owner: Codex
---
# Agent .locks、共享文档与并行工作流补充方案
## 1. 结论与边界
建议采用 **主仓唯一 `.locks` + 统一管理工具 + 受控写入 + 版本校验 + 可恢复操作记录**。保留已采纳的任务 worktree、dev 合并候选与串行部署流程,将上一方案的人工协调补成机器可执行协议。
`.locks` 是协调状态位置,不是“只要放一个文件,系统就自动不许修改”的机制。对你的要求应明确两种行为:
- **排他写锁**:有效持有者可以修改授权范围,其他 Agent 不可以;没有有效租约也不能调用受保护写入口。
- **冻结**:用于不允许任何 Agent 修改的资源,持有者也不能直接写;必须先完成受控解冻。部署/验收中的制品可以冻结,但不要冻结所有日常开发目录。
**用户已确认本期强度**:“先统一操作入口和提交门禁,防止 Agent 误改;后续再加权限隔离”。因此本期按 L1a–L1d 完整交付设计,L2 为后续阶段;这不等于当前已经实现任何自动锁机制。系统级禁止绕过仍需进程沙箱/独立用户与写代理。
本轮只研究并形成方案,不创建运行 `.locks`,不迁移现有锁,不修改生效规范或业务代码。[核查依据](../ops/research/2026-09-21-agent-lock-coordination-research.md)。
## 2. 为什么单加锁文件仍不够
| 问题 | 仅用“文件存在”或单个 flock 的不足 | 必须补充 |
|---|---|---|
| 两个 Agent 同时申请 | 先检查再 touch 有竞态 | 事务内检查并登记,不拆成两次操作 |
| 各自 worktree 都有锁目录 | 各锁各的,互相看不到 | 所有任务定位主仓唯一 `.locks` |
| A 改了 CURRENT,B 持有旧副本 | 即使排队写,B 仍覆盖 A | 拿锁后读最新内容、校验版本、按记录更新 |
| 一方锁目录,另一方锁子文件 | 不同锁名不自动冲突 | 规范化路径与父子范围冲突检查 |
| LLM 两次 shell 调用 | 上一次命令结束,fd 锁可能已释放 | 一个 supervisor 包裹操作或持续会话 |
| Agent 崩溃或暂停 | TTL 过期不证明进程停止写 | 会话身份、suspect、物理写者确认、旧令牌拒绝 |
| Agent 手工 rm 锁 | 可能重建出不同 inode,旧持有者仍在 | 稳定锁文件,只有管理器释放状态 |
| 编辑器绕过工具写文件 | advisory lock 没有 OS 写保护 | 客户端接入;若需硬约束则限制文件与父目录写权限 |
| 两份文档更新中途断电 | 文件 rename 与 DB/Git 不构成一个事务 | 可恢复 operation、前后 hash、统一 Git 发布提交 |
因此不能只给 CURRENT.md 和 FEATURE-MATRIX.md 各加一个 `.lock` 文件便结束。
## 3. 单一锁根与存储选择
### 3.1 目录
```text
Agent-System/
.locks/ 唯一本机运行状态;不提交 Git
identity.json repo_id、主目录、common-dir、schema/policy 版本
state.sqlite 会话、租约、队列、操作与事件的权威状态
state.sqlite-wal / state.sqlite-shm SQLite 自主管理,不手删
os/
manager.lock 防止多个本机协调服务实例争用
shared-writeback.lock 保护“校验令牌→文件写回”的短临界区
dev-integration.lock 稳定 inode;与旧锁兼容迁移
operations/<operation-id>/ 受保护的前后 hash、暂存补丁、恢复证据
snapshots/ 人可读 JSON;可再生,非加锁判据
logs/ 有界诊断日志;不记录秘密
.worktrees/<task-id>/ 不另建独立锁根
```
工具从 `git-common-dir` 找仓库身份,再核对主工作区登记;不是 `git --show-toplevel` 后直接拼 `.locks`,因为 linked worktree 的 top-level 是任务目录。根路径、repo_id、Git 元数据不一致时报错,**禁止静默在当前 cwd 新建第二套锁**。第一版拒绝 bare/网络文件系统及未知 topology;未来迁移显式登记。
`.locks/` 整体加入 `.gitignore` 和 `.dockerignore`;不复制到 worktree,不打进镜像,不作为旧任务清理的一部分。Git 跟踪的锁策略单独放 `configs/agent-governance.yaml`;运行锁内容不入 Git。策略读取已采纳 dev 版本,旧客户端不满足最小协议版本时拒绝写入,不能让每个 feature 自己改策略绕过门禁。
### 3.2 推荐 SQLite,保留小而明确的职责
| 方案 | 判断 |
|---|---|
| 每资源一个 JSON + touch/rm | 简单但多资源、目录层级、崩溃恢复和幂等容易出错,不采用 |
| 单 JSON + 全局 flock + 原子 rename | 可用于小型过渡实现;请求队列、会话、历史和恢复扩展后容易自己造事务系统 |
| 本机 SQLite + 短事务 + 少量稳定 OS 锁 | **推荐**;能统一租约、等待票据、幂等操作与事件,便于审计 |
| 产品 PostgreSQL/Redis/跨机锁服务 | 当前不采用;工程协调不应依赖产品容器是否能启动,不接触业务数据库 |
建议做小型 `agentctl` 工具及本机 supervisor,复用同一核心校验模块;不是新建网页中控台。选 Go 实现时 SQLite 驱动属于需要评估的新依赖,当前 go.sum 的历史条目不能视为已集成。先支持 Linux 本机/ext4;SQLite 的版本、WAL、synchronous、busy_timeout、checkpoint 与故障恢复须纳入验收,不能只凭启用 WAL 宣称可靠。
## 4. 锁住什么:区分逻辑资源与物理写入
### 4.1 资源类型
| 类型 | 标识示例(示意) | 范围 / 持有时长 |
|---|---|---|
| 任务写范围 | `claim:repo:web/src/engine` | 跨 worktree 的逻辑路径/模块,任务工作期;防两项未经协调的改动互相覆盖 |
| 工作区写操作 | `tree:<worktree-id>:web/src/engine/a.ts` | 指定 worktree 的物理路径,具体操作期间 |
| Git 工作区/index | `git-tree:<worktree-id>` | 同 worktree 的 commit/checkout/reset/merge 等 Git 更新排他 |
| Git 共享资源 | `git:worktrees`、`git:dev`、`migration:sequence` | 创建/清理工作区、更新 dev、分配迁移号等短操作 |
| 共享文档记录 | `doc:CURRENT:task/<id>`、`doc:MATRIX:module/<id>` | 同一逻辑记录更新排他;不同记录可同时提交提案 |
| 共享文档发布 | `doc:governance-publish` | CURRENT/MATRIX 受控写回和发布短窗口;第一版统一锁两份文件 |
| 环境 | `env:dev` | 部署、迁移、使用共享 dev 的写入/固定版本验收;不包含普通本地单测 |
普通代码任务保留单写者模块/路径认领;研究者和审查者读取不可变 Git 快照,无需为阅读占锁。所有跨 worktree 逻辑资源绑定 repo_id;物理资源还绑定 worktree_id。路径不是随分支改名而失效的标签。
目录锁对后代文件生效:`web/src` 与 `web/src/App.tsx` 冲突,和 `web/src2` 不冲突;基于路径组件而不是字符串前缀。规范化 `.`/`..`、平台大小写策略与真实父目录;拒绝 symlink 越界和未登记硬链接别名。不存在的新文件也用已验证父目录 + 文件名登记。rename/delete 同时声明源和目标及受影响父范围。
“逻辑范围没有重叠”不是“物理写入没有风险”:Git checkout/merge 可能改变受保护路径,必须根据实际变更集取得同一份文档/文件写许可;不能只拦编辑器而放过 Git 命令。
### 4.2 模式与多资源请求
读稳定快照可无锁;需要稳定的可变资源视图时使用 S,共享读可并存。写用 X,与重叠的 S/X 冲突。冻结是有 owner/原因/恢复条件的资源状态,会拒绝全部普通写请求,不能用“我就是 owner”绕过。
一次操作声明**完整资源集合**,在同一 SQLite 写事务中检查父子重叠、模式、冻结、会话及公平队列,全部成功才同时授予;失败不保留部分资源。第一版不提供阻塞式锁升级,不允许持有 A 再无限等待 B;扩展范围需安全检查点后按合并资源集合重申。
排队按冲突资源先到先得,不相关资源可继续运行,避免一个繁忙模块拖住全仓。取消票据、超时、重试使用同一 request_id;未知结果先 query,不自动创建第二项有副作用操作。
## 5. Agent 如何控制锁
### 5.1 只让工具管理生命周期
以下是**拟提供接口,当前尚未实现**:
```text
agentctl doctor --json
agentctl task open --task <id> --worktree <path> --scope-file <file>
agentctl session run --task <id> -- <agent-client>
agentctl with --resources-file <file> --wait 10s -- <command>
agentctl docs propose --file <delta.json> --request-id <id>
agentctl docs publish --request-id <id>
agentctl lock status --resource <key> --json
agentctl operation status <id> --json
agentctl task close --task <id>
agentctl recover --operation <id> --inspect
```
Agent 常规只需“开任务、执行受控操作、提交状态变更、结束任务”。无需手写锁 JSON、计算 TTL、后台循环 touch 或自行 rm 锁。`release/recover/freeze/unfreeze` 作为有身份及审计条件的管理操作,不暴露无条件 unlock-all。
- 命令型任务:supervisor 先获完整许可,包裹子命令至退出,记录进程树,释放自身 lease;子进程继承与退出策略明确。
- 跨多次工具调用的 Agent:由客户端启动包装器或本机 sidecar 维持 session;不能把一次 shell 中的 `exec 9>` 当跨工具会话的持久锁。
- IDE 集成需用能识别真实客户端生命周期的适配器;无法关联的临时 shell 只获短操作许可,不获无人维护的长租约。
- 有效心跳只证明 supervisor 存活,不证明 Agent 正在进展;长时间无操作提示 idle/suspect,不能无条件释放或无限延长所有资源。
- `status/doctor` 只读,不隐式建锁、初始化库或修复数据;未知状态清晰报错。没有服务时读诊断快照可以,但写操作不得默认放行。
### 5.2 身份、返回与等待
会话至少记录 `repo_id / task_id / agent_instance_id / session_id / worktree_id / branch / host / boot_id / pid / process_start_time / protocol_version`。租约记录 `lease_id / resource_set / mode / generation / coordinator_epoch / operation_id / heartbeat / state`。PID 或可伪造的 owner 名称都不足以安全接管;会话标识也不是 OS 权限隔离。
默认快速返回:`LOCK_BUSY` 带持有任务、资源、队列票据和 retry_after;Agent 改做不冲突的工作。需要等时最多等待短窗口(建议默认 10 秒),然后返回票据,不让模型反复高频轮询或长时间卡在工具里。事件通知优先,有限退避兜底;超时意味着“尚未拿到/结果未知”,不等于对方已死亡。
错误区分 `LOCK_BUSY / SESSION_EXPIRED / STALE_GENERATION / BASE_CHANGED / FROZEN / RECOVERY_REQUIRED / PATH_OUT_OF_SCOPE / POLICY_MISMATCH`。每次失败给出可执行下一步,避免 Agent 靠猜测改流程。
## 6. 租约失效、旧写者与死锁
```mermaid
stateDiagram-v2
[*] --> queued
queued --> held: 原子授予
held --> released: 操作完成且证据保存
held --> suspect: 心跳或客户端异常
suspect --> held: 核实原会话并恢复
suspect --> recovering: 确认需接管
recovering --> released: 写者停止且现场核对完成
released --> [*]
```
建议初始心跳 10 秒、失联观察阈值 60 秒;属于待压测参数,不是保证。使用 monotonic 时间判断本次启动内超时,wall clock 只用于展示;重启以 boot_id/epoch 识别,不拿旧 monotonic deadline 比较。
**TTL 到期只进入 suspect,不立即授予下一位。** 必须确认旧进程及其子进程/外部操作已结束,或受控终止后确认,再结束旧租约。数据库不可用时阻止新受保护写入;supervisor 中止/暂停其可控操作并报告,不能声称已撤销未知外部写者。
协调器重启先停止新写准入,核对存储、旧 session、in-flight 操作和物理锁;确认恢复边界后再开放。重建/恢复协调库必须切换 epoch,旧令牌全部失效,旧写进程仍需先核实停止,不能因 epoch 已变就放行相同资源。
每次新授予带递增 generation 和 coordinator_epoch;旧 token 的 renew、write、release 全部拒绝。只有接收端实际校验才有意义,令牌不能自动撤销已经打开的文件 fd 或远端 Docker 操作。
为防“检查 token 后暂停,恢复时覆盖新写者”:统一写入口在稳定 OS 写回锁内完成身份/代次校验、CAS 和最终 rename;接管也取得同一写回锁。执行期间保留 in-flight 标记,不能先重发租约再等旧写者退出。若旧进程持物理锁,接管等待或进入受控恢复,不因 TTL 到期删锁。
多资源事务只持续毫秒级元数据工作,不能等待 LLM、跑测试、构建镜像或执行 Git merge。OS 兼容锁必须在登记事务外等待;不持数据库写事务等待另一个资源,避免内部死锁。
## 7. CURRENT / FEATURE-MATRIX 的正确更新流程
### 7.1 职责分离
CURRENT 的实时任务占用来自 `.locks` 中的会话/资源状态,Markdown 是带时间和 generation 的可审阅快照。FEATURE-MATRIX 的能力状态与证据仍是版本化事实,不能因为任务结束或锁释放自动标 done。
普通 Agent 在自己任务文里记录事实,并提交结构化 delta;不直接改共享表格或把整份旧文档覆盖回来。不同任务的 delta 使用唯一文件名,可放 `.doc/ops/updates/<task-id>/<request-id>.json`,通过 task branch 和冻结提交交付。工作开始时的实时认领先入管理器,不等待一轮 Markdown 提交才能开工。
第一版只给任务行、集成槽位、模块行增加稳定 ID 与受控区块,保留原叙述和历史段落。不要为使用锁而重写全部文档体系,也不依赖易变的中文标题或行号当机器主键。
### 7.2 增量接口
一个 delta 包含:`request_id, actor_session, task_id, target, record_id, expected_record_revision, observed_doc_blob, operation, field_changes, evidence_refs, source_commit`。
记录 revision 取自已发布 dev 中该稳定 ID 对应受控字段的规范化摘要;未发布提案不能推进正式 revision。SQLite 可缓存,但每次发布从实际 Git 内容核对,不能让缓存掩盖外部 Git 改动。
身份与可写范围从已登记任务和可信策略解析,不能由 delta 自报 owner 或任意指定 publisher 角色。允许白名单操作,例如更新本人任务阶段/证据、建议模块状态、申请/释放本人持有槽位。slot 的 holder 来自实际租约,不允许某 Agent 写一行 `idle` 来释放别人的环境。模块能力 done 需满足原声明范围、报告可追溯和必要审查;production_ready 仍只由现有发布门禁决定。
不同记录可自动重放到最新文档;同记录期望版本不符返回 BASE_CHANGED 并展示当前字段,要求重新判断。禁止机械地“最后写入者赢”,也禁止遇到冲突整段 ours/theirs 覆盖共享表。
### 7.3 发布步骤
1. 接收提案时持短 DB 事务去重并排队,**尚不占共享文件长锁**。
2. 发布者选择当前可处理批次,从最新 dev 创建独立文档 worktree。根据已合入证据及待合入的同批证据解析变更;不存在的报告/未验收业务不生成 done。
3. 取得 `doc:governance-publish` 及该 worktree 的写/index 许可;读取最新文件/记录 revision,验证 delta 与会话权限,按字段应用并保留未知内容。
4. 写回前再次比较文档 blob/hash 与 epoch/generation;变化则重读重算或报冲突。`CURRENT`、`FEATURE-MATRIX` 如需一致更新,作为同一 operation 生成,写后检查链接、表格/区块完整性及状态契约。
5. 对同批文件生成一个文档提交,释放文档写锁。Git 集成仍走队列与候选验证;不持文档锁等待长测试或部署。
6. dev 若前进,重新读取最新 dev 并应用 delta,再形成候选;不能因为旧 worktree 曾持锁就直接合入陈旧表格。普通文档无需重建服务。
7. dev 成功接收候选后标记 request 已发布,记录 publish_commit;发布答复丢失可按 request_id 查询,不再重复更新。仅本地 commit 但未合入的状态叫 pending_publication。
**示例**:A 更新 CURRENT 的任务 A;B 更新任务 B。两者同时提交 delta,发布者可以批量一次更新两行。若 B 的依据是旧文档,只要 B 行本身版本仍匹配就可应用,不能把 A 行回退。若 A/B 都改同一个模块状态,后者必须依据新证据重新确认。
### 7.4 多文件原子性与恢复
SQLite 事务不能把两个 Markdown 文件和 Git 引用纳入同一原子提交。写前先持久化 operation 的原 blob、目标 hash 和完整补丁,文件用同目录临时文件/fsync/rename。任何阶段失败留下 RECOVERY_REQUIRED,冻结受影响发布,恢复者根据实际 hash 判断未写/部分写/已写/已提交/已发布。
只有原值仍匹配时才可定向恢复;出现第三方更新则保留现场,不覆盖。路径上的两个文件可能被裸读取者看到中间状态,因此一致读取以同一个 Git commit 或管理器 generation 快照为准,不能声称两次 rename 让任意目录读取都原子。
## 8. 与日常工作流衔接
| 阶段 | Agent 操作 | 锁策略 |
|---|---|---|
| 开工 | doctor → 登记任务与范围 → 从 dev 建 worktree | `git:worktrees` 短锁 + 范围认领;CURRENT 异步发布 |
| 开发 | 启动有身份的会话,修改自己的授权路径 | 任务范围租约;自己的短写/index 锁;不占共享文档或 env:dev |
| 测试 | 冻结测试提交,独立数据库/目录 | 本地测试按资源配额;共享 dev 写验收另获 env:dev |
| 状态变化 | 提交本任务的 delta 与证据 | 并行提案;短锁批量发布,不长锁整个 CURRENT |
| 集成 | 构建候选、验证、比较 dev SHA、接收同一节点 | git:dev 与实际涉及文档/路径许可;所有入口用同一协调器 |
| 部署 | 对准确制品更新并验收 | env:dev + 当前兼容 dev-integration 锁;保留恢复记录 |
| 收口 | task close,发布事实,条件清理 | 清理需无有效 session/lease/operation,普通 remove/-d |
Git 核心自己的 index/ref 锁仍由 Git 管理,不拿本工具替代 `.git/index.lock` 或手删 Git 锁。开发范围租约也不是工作树数据锁:同一 Agent 的两个并发工具请求不能共享同一个写/index 许可并同时改文件。
## 9. “不允许修改”的实现等级
| 等级 | 能保证什么 | 不能保证什么 |
|---|---|---|
| L0 文档约定 + 锁文件 | 提醒合作 Agent | 竞态、崩溃、直接写入都不能可靠防止 |
| L1 统一 CLI/会话 + CAS + 提交/集成门禁 | 对受控入口实现排他、旧写者拒绝、旧版本拒绝;防误提交 | 同 UID Agent 仍可绕开工具直接写文件,hook 也可绕过 |
| L2 沙箱/独立用户 + 写代理 | 在受支持客户端下,OS 拒绝对受保护路径及其父目录的任意越权写/删除/替换 | 不能阻止有宿主管理员权限的行为,跨机也需另建协调 |
按用户选择,L1 是本期交付线,所有受保护变更入口接入后才能称“受控写入已强制”;未来需要“任何 shell/编辑器都绝不许改”时必须验收 L2。不要用 chmod 只改文件权限:可写父目录仍可能允许替换文件,同 UID 可改回权限;主目录递归只读也会误伤 `.worktrees`、`.git` 和运行数据。
L2 对 CURRENT/MATRIX 的推荐方式是长期只读给开发 Agent,发布者作为唯一有写权限的主体,主目录、共同 Git 管理和 `.locks` 也只由受限代理修改。不是每次拿锁就临时把全仓 chmod 成可写。保留各任务自己的工作目录可写;客户端所有 shell、文件工具和子进程必须进入同一隔离边界;文件替换、父目录 rename、预先打开 fd、symlink 等路径需实测。配置管理员能力不下放给普通 Agent。
## 10. 从现有锁迁移,避免两套锁各自放行
旧锁是 common-dir 下 `agent-control/dev-integration.lock`,不能直接改成 `.locks/os/dev-integration.lock` 后同时让旧客户端继续运行。
推荐迁移步骤:
1. 盘点所有旧入口、活跃操作、持锁进程及历史非终态记录;先发布兼容版本和检查工具,保持旧锁的权威。
2. 在受控初始化窗口创建唯一 `.locks` 和 repo 身份。暂不把“不存在新锁”当作空闲。
3. 同文件系统且旧路径为预期普通文件时,可用**受校验硬链接**让新旧 dev 锁路径指向同一稳定 inode,核对 device/inode;保留旧路径。不能复制内容、删旧再建或原子替换该 OS 锁文件。该方式需专项双入口验收,不能仅按路径存在判断。
4. 无法保持同 inode 时使用明确的双锁兼容阶段:所有新执行器先取得旧锁再取得新门禁,旧执行器仍受旧锁约束;不要在 SQLite 写事务中等待任一 OS 锁。
5. 新租约记录和旧手写状态不能双向互相覆盖。旧不完整记录只导入为 needs_inspection,不能猜 PID/有效期限自动接管。
6. 确认旧客户端已退出、所有写入口已升级并有 recovery 结果后,才能淘汰旧状态格式。保留兼容路径直至新旧锁身份与所有客户端能力审计完成;不做按日期删除锁文件的 cron。
主目录当前已回 dev,不复用早前“临时 dev worktree 仍在检出 dev”的过时假设;迁移现场每次重新核对。
## 11. 分阶段交付与验收
| 阶段 | 交付 | 关键验收 |
|---|---|---|
| L1a 基础 | 唯一锁根、repo/worktree 身份、策略版本、SQLite 原子租约与 status/doctor | 跨 worktree 同资源仅一个成功;路径别名/层级冲突;存储不可用拒绝写 |
| L1b 生命周期 | session/supervisor、心跳、完整资源申请、队列、幂等请求、恢复 | 多轮调用不断锁;异常/重启/PID 复用不误抢;不同资源不互相阻塞 |
| L1c 共享文档 | 稳定记录 ID、delta、CAS、短时 publish、operation 恢复 | A/B 更新不同任务不丢行,同模块旧版本冲突;两文件中断可恢复 |
| L1d 接入 | Git/环境/worktree/客户端统一入口,旧锁兼容迁移 | 普通写、Git 更新、部署、清理均验证同一身份;旧客户端不会另开协调域 |
| L2 后续阶段 | 只读沙箱、独立发布者、受限写代理 | 绕过 CLI 的写、删除、rename、symlink、子进程等越权尝试被 OS 拒绝 |
L1a–L1d 是一项完整交付;不能只完成“创建 .locks”就宣称可靠锁已实现。第一批聚焦 CURRENT、FEATURE-MATRIX、dev 集成,不给每个源码文件默认起独立守护进程,也不提前建设跨机平台。
**必须覆盖的故障与竞争用例(待实施,未执行)**:
- 20 个并发请求抢同一资源:只有一个 X;不相关资源仍可获准。
- 目录/子文件、rename 源目标、别名、越界、错误 worktree 与不同仓库身份。
- 多资源反向请求、取消排队、重复 request_id、答复丢失、长队公平性。
- Agent 暂停超过 TTL 后恢复、supervisor 被杀但子进程尚存、PID 复用、机器重启、系统时间跳变。
- 旧 generation 写/释放失败;检查后暂停的旧写者不能越过受控写回门禁。
- DB busy/满盘/损坏、写 temp 后失败、首份文档 rename 后失败、Git commit 后答复丢失、dev 前进。
- CURRENT 槽位非本人不得释放;FEATURE done 无证据拒绝;未知字段/历史记录保留。
- 不同 worktree 的旧 CURRENT/MATRIX 提案:行级 CAS 与最终 dev 基线检查均有效。
- 锁存在但无人持有、元数据写 merging 但锁未观察到:doctor 能区分,不能自动偷锁。
- 新旧 dev 锁路径同时申请、旧客户端重启、错误迁移目录、遗留不完整 owner。
- 清理被 session/操作占用的 worktree 必须拒绝;只允许普通安全删除。
- L2 需真实客户端绕过测试;L1 未部署 L2 时如实展示其安全边界。
建议性能目标(均未实测):本机无争用申请/释放 P95 <100ms;短文档更新锁持有 P95 <1s(不含 Git 验证/排队);批处理上限建议 1 秒或 20 项提案;每次心跳合并更新同 session 的租约。先测基线,再调 TTL/批量/并行数,避免为了达标隐藏锁等待或跳过持久化。
## 12. 与既有规范的关系及下一步
本方案补充上一方案 §5、§6、§8:提议把权威协调数据统一到 `.locks`,明确 advisory 边界、会话协议、共享文档增量发布及恢复。既有 `.git/agent-control` 流程在迁移验收前继续有效;本文不会令旧锁失效,也不会授权其他 Agent 忽略现有槽位。
实施时同步 AGENTS/PROJECT/操作规范、CURRENT/FEATURE-MATRIX 更新规则、任务/收口模板、相关脚本、Gitignore/Dockerignore 和客户端入口;脚本守卫应共享一个核心实现,禁止每个客户端复制一套不同判断。
运行 state.sqlite 的备份使用 SQLite 支持的一致性备份方式;不复制一个脱离 WAL 的裸库,不把备份中的旧租约直接恢复成 active。`.locks` 缺失/损坏时停止受保护写入,按持久化 Git/操作收据和存活进程重建,再切换 epoch;不能把清空目录当复位。历史里程碑导出到 `.doc`,本机日志与快照有界轮转,当前稳定 OS 锁文件不轮转。
本次结论:按用户确认,先把两个共享文档和 dev 操作纳入 L1a–L1d,验证正确性与并行效率;系统级“不可修改”由后续 L2 交付,不能提前承诺。独立源码任务仍并行,锁只约束有冲突的资源与短发布窗口。