面向在本仓库工作的 AI Agent 和新加入的开发者。动手前必读。
本文件是“怎么在这个仓库干活”的入口;“系统应该是什么样”以 doc/ 下的权威文档为准。
两者冲突时,以 doc/ 为准,并按第 6.5 节流程先改文档。
AUTO-MAS Runtime 用 Go 实现 Windows 本机运行时管理程序,产出单个可执行文件
auto-mas-runtime.exe,接管当前由 AUTO-MAS(Electron + Python)承担的初始化、更新
和后端进程管理职责。
Electron 通过「命令行参数数组 + stdin/stdout NDJSON + 退出码」调用 Runtime, Vue 仍直接访问 Python 后端的 HTTP/WebSocket 业务接口。Runtime 只在控制面, 不代理任何业务流量。
Runtime 负责: 本机环境检测与部署、受管后端 Git 仓库更新、uv/Python/依赖同步、 后端进程启动与监督、健康检查、诊断、修复、清理、进程树回收;M12 完成后还负责 白名单化的运行质量遥测与内部错误观测。
Runtime 不负责: 业务 HTTP/WebSocket 代理、Python 插件依赖管理、自身自动更新、 Vue/Electron/Python 的改写、CI/CD 发布流程本身。
首版正式发布仅支持 Windows。2026-08-04 起登记跨平台与遥测扩展(决策 D7/D8);
2026-08-12 按当前决策将 M12 收敛为 Sentry-only 错误观测;D10 的自建 Umami 方案已取消,
仅保留历史追溯。以上均不改变既有 Windows 协议契约;详见 doc/架构设计.md
「平台支持策略」「遥测与错误观测策略」两节。
| 里程碑 | 状态 |
|---|---|
| M0 工程基础与最小 CI | T0.1~T0.4 已完成 |
M1 协议层 internal/protocol |
T1.0~T1.9 已完成 |
| M2 基础设施(config/logging/state/lock/filesystem/mirror/下载器) | T2.1~T2.9 已完成(T2.9 收口 hosted Windows 的路径别名、Reparse 与 rename 占用语义) |
| M3 CLI 框架与基础命令 | T3.1~T3.8 已完成(含三轮对抗性审查的修复与可维护性收敛) |
| M4 工作区同步 | T4.0~T4.7 已完成(含三轮对抗性审查与组件矩阵) |
| M5 uv、Python 与依赖 | T5.1~T5.8 已完成(复审修复收口于 8deb9d7,含官方 uv 资产、完整组件矩阵与 race 验证) |
| M6 后端监督 | T6.1~T6.7 已完成(真实 Windows Job/health/control/restart/development/E2E 与对抗复审收口于 ea886f8) |
| M7 GitHub CI/CD 发布 | T7.1~T7.4 已完成(beta.2 Release run 31407585577、三 job 全绿、独立资产/NDJSON 验收通过);T7.5 按 D3 延后;T7.7 CNB 代码与发行版同步 已完成(2026-09-17:sync-cnb.yml 镜像 + publish-cnb job + backfill 工作流 + scripts/publish-cnb-release.ps1;双侧 22 refs 一致、18 个 Release 全部回填、36/36 资产黑盒哈希一致;设计见 doc/current/M7/设计-T7.7-CNB代码与发行版同步.md;自动双发布待下次发版观察) |
| M9 联调与首版验收 | T9.1 development 真后端联调 已完成(2026-09-02,ba27db3 构建对 AUTO-MAS 集成树 integ/runtime-20260901 跑通启动→就绪→优雅关闭);T9.2 managed 全链路 已完成(2026-09-02,用本地 HTTPS smart-git 模拟 release/* 分支:bootstrap → supervise → 升级 → 降级 → 关 stdin 隐式关闭,真实发布分支复跑待 push 后);T9.3 Electron 接入 🚧(off 六场景与 development 一轮桌面 E2E 完成,复跑进行中,未宣布通过);T9.4 首版验收清单核对 已完成(2026-09-03,doc/首版验收记录.md:标准第 1~11 条满足,第 12/14 条不满足、第 13 条未验证,均属 AUTO-MAS 侧发布动作并附解除条件);M9 整体待真实 release/* 复跑与阶段 0/5/6 收口后勾选 |
| M10 工程可维护性收敛 | T10.1 文档信息架构已完成;后续阶段见维护设计 |
| M11 跨平台适配(Linux/macOS) | 规划中(决策 D7,2026-08-04 立项);仅 T11.1 设计任务可执行 |
| M12 遥测与错误观测(Sentry-only) | T12.1、T12.2、T12.4、T12.5、T12.7、T12.8、T12.9 已完成;T12.6 本地发布配置已提交,待 Repository secret 与授权后的远端验收;T12.3/Umami 已取消 |
| M13 dev 基线接入配套 | 2026-08-31 按决策 D12 与 doc/契约补充-v1-增补1.md(C6~C11)立项;T13.1(后端工作目录)、T13.2(Job 允许显式脱离)、T13.3(关闭超时参数化,含优雅关闭误报修复)、T13.4(锁副本改写参与包索引镜像轮换,显式 package-index 排最前)已完成;T13.5 已完成(注入面 020b3b9:AUTO_MAS_UV_CACHE_DIR / AUTO_MAS_UV_PYTHON_INSTALL_DIR / AUTO_MAS_MIRROR_PACKAGE_INDEX / AUTO_MAS_MIRROR_PYTHON;池目录重新分类按设计关闭——Runtime 的 repair/cleanup 只处理自己的目录,池 venv 失效后由后端判定重建);T13.6 ⏸ 未开始;2026-09-02 真机联调后按增补 1 C12 / C13 完成 T13.7(f7d5edb:backend supervise --port,缺省 managed 36163 / development 36164,注入 AUTO_MAS_SUPERVISED_PORT,健康/关闭地址与 baseUrl 由 internal/health 派生,E2E 改用空闲端口)与 T13.8(41c51d3,收尾 23033f9:backend supervise 的 stdin EOF / 读取出错视为隐式 shutdown,stdout 已断不影响 HTTP 优雅关闭,真实 exe 黑盒 E2E 锁定,宿主崩溃不再留孤儿)已完成;T13.9(da710c4,增补 1 C14:新 warning BACKEND_ORPHANS_REAPED,BACKEND_FORCE_TERMINATED 收窄为主进程被强杀)已完成;T13.10(c46babf,C13 第 4 条修订:协议日志转发失败不再回给 process 层,避免宿主崩溃时把正在优雅关闭的后端连同进程树杀掉)与 T13.11(7fa56a1,C15:Job 快照跳过正在消亡的成员、健康探针错误连续 3 次才判失败、根进程已退出时不再发 close)已完成;T13.14(e8bc217:克隆传输期脉冲由「按 sideband 写入次数计数、上限 64」改为固定间隔时间心跳,仍只发不带数值的 running)已完成 |
| M14 网络源测速与回环中继 | 2026-09-11 按用户需求与 doc/契约补充-v1-增补2.md(C16~C20)立项并当日完成:T14.1(契约与设计)、T14.2(测速排序,惰性触发)、T14.3(internal/relay 回环中继)、T14.4(uv 接线与锁规划)、T14.5(CLI、字节进度、supervise 常驻)、T14.6(protocol 字段与 network.probe)、T14.7(组件矩阵与三次真实镜像黑盒)、T14.8(分片取回的慢源判定)、T14.9(宿主配置与 Python 环境隔离:UV_NO_CONFIG=1、PYTHON* / 颜色 / Rust 调试变量剔除、NO_PROXY 必含回环)已完成;本地 main 领先 origin/main 未推送,发版与 AUTO-MAS 钉扎待用户授权 |
代码现状:
internal/protocol、config、filesystem、logging、state、lock、mirror、cli、doctor、cleanup、version已实现;gitrepo已实现版本映射、go-git 浅克隆、仓库校验、原子替换、中断恢复和 workspace 服务;uv已实现固定工具 bootstrap、受管 Python、锁定依赖、恢复和 repair;process、health、backend已实现 Windows Job 进程树、固定健康检查、managed/development 监督、控制关闭与一次重启;internal/cli已按架构命令树注册全部命令,version/doctor/cleanup、workspace 和 M5 environment/bootstrap/dependencies/repair 以及 M6backend supervise为真实实现;尚未实现的 模式仍失败关闭并返回UNSUPPORTED_MODE;.github/workflows/release.yml已实现 Windows x64 测试、版本注入、未签名 EXE/SHA-256 直接发布与 Release 资产冒烟验证,并使用原生 Node.js 24 的 upload v7/download v8/release v3 action; beta.2 测试 Release 已完成远端验收;cmd/auto-mas-runtime/main.go是唯一持有os.Stdout的入口。
Git:远端 origin = git@github.com:AUTO-MAS-Project/AUTO-MAS-Runtime.git。
本地 main 与 origin/main 的实际关系以 git status -sb / git log --oneline -5 为准,
不要依赖本文件里的哈希(它会随每次提交过期)。
特性分支 codex/runtime-implementation 在 .worktrees/codex-runtime-implementation 下。
| 文档 | 内容 | 何时必读 |
|---|---|---|
| doc/README.md | 文档导航、分层与生命周期规则 | 查找任何项目文档时 |
| doc/架构设计.md | 冻结的系统架构:边界、CLI 命令树、NDJSON 协议、错误码/退出码/stage/state 全集、Git 更新流程、uv 策略、目录安全、测试矩阵、验收标准 | 任何涉及对外契约的改动 |
| doc/契约补充-v1.md | 协议 v1 的 5 项定稿细节(C1~C5:后端端口(已由增补 1 C12 改为 Runtime 注入)、身份注入环境变量、failed 字面量、AUTO_MAS_SUPERVISED=1、development 检查边界) |
涉及后端启动/健康检查/环境变量 |
| doc/契约补充-v1-增补1.md | 对 v1 的增量修订(C6~C11:后端工作目录、受监督优先级扩展到端口、Job 逃逸、关闭预算参数化、依赖镜像改写轮换、运行池基础设施共享),并修订 C2 第 1 条与 C4 第 1 条 | 同上;与 契约补充-v1.md 冲突时以本文件为准 |
| doc/契约补充-v1-增补2.md | 第二次增量修订(C16~C19:网络源测速排序、回环中继、进度事件字节字段与细目、Python 分发源增补),并修订增补 1 的 C10 第 3/7 条与 C11 第 3 条 | 涉及镜像、下载、进度事件;与增补 1 冲突时以本文件为准 |
| doc/任务拆分.md | 逐任务清单、依赖、验收项、决策记录 D1~D12、待决项 D-open-*、AUTO-MAS 侧 TODO、变更记录 | 每次开工前确认自己在做哪个任务 |
| doc/代码审查清单.md | 自动化门禁覆盖不到的架构边界检查 | 提交前自查、审查他人代码 |
doc/current/M*/ |
尚未完成任务的设计与实施计划 | 执行某个具体任务时 |
doc/archive/M*/ |
已完成阶段仍有解释价值的设计与审查记录 | 追溯设计背景时 |
优先级: 契约补充-v1-增补2(最新增量修订) > 契约补充-v1-增补1 > 契约补充-v1(更具体) > 架构设计(概括) > 任务拆分(派生清单)。
cmd/auto-mas-runtime/ 进程入口,唯一可持有 os.Stdout
internal/cli/ 参数解析与应用服务分发(不含业务逻辑)
internal/protocol/ NDJSON 事件、错误码、生命周期状态机、renderer、stdin 控制
└─ contracttest/ 可复用的原始 NDJSON 契约断言库(后续命令一行注册接入)
internal/config/ 配置与受管目录布局的唯一来源
internal/gitrepo/ 版本 → 分支映射、浅克隆、受管仓库整体替换
internal/uv/ uv bootstrap、Python、主项目环境、后端启动命令
internal/backend/ 后端启动/健康/单次重启/关闭编排
internal/process/ Windows Job Object 与子进程管道
internal/health/ 后端健康与身份校验
internal/state/ 跨进程持久化操作状态
internal/lock/ Windows 命名 Mutex 并发协调
internal/mirror/ 四类下载源的轮换
internal/filesystem/ 路径校验、原子移动、受控删除
internal/logging/ stderr 诊断与轮转操作日志
testdata/ 组件与端到端测试夹具
doc/ 权威文档
包边界纪律(来自架构设计「Go 项目结构」):
cli只解析参数、调用应用服务,不写业务逻辑;protocol只定义契约,不感知具体命令;- 路径拼接只能来自
config,其他包不得散落硬编码路径(T2.1 起生效); - uv 子进程只能经
uv包的唯一执行器,其他包禁止自行exec.Command调 uv(T5.2 起生效); - 业务包不得直接向 stdout 写任何内容,机器事件统一经
protocol。
- Windows 10/11 + PowerShell 7(
pwsh); - Go 1.26(
go.mod声明go 1.26;本机当前为 Go 1.26.5); - MSYS2 UCRT64 GCC/G++ 16.1.0,
CGO_ENABLED=1; - golangci-lint 2.12.2+(可选,本机当前未安装)。
本机的 go、gofmt、gcc、g++ 均可由 PowerShell 7 直接从 PATH 解析,命令和文档不得
固化用户目录下的工具绝对路径。运行 CGO 或 race detector 前,应把实际 GCC 目录提升到当前
会话的 PATH 首位,避免 PostgreSQL 等软件目录中的同名 libwinpthread / zlib DLL 被优先加载:
$gccBin = Split-Path -Parent (Get-Command gcc -ErrorAction Stop).Source
$env:PATH = "$gccBin;$env:PATH"$env:GOCACHE = Join-Path $env:TEMP "auto-mas-runtime-verify"
$unformatted = & gofmt -l .
if ($LASTEXITCODE -ne 0) { throw "gofmt failed" }
if ($unformatted) { $unformatted; throw "gofmt found unformatted files" }
& go vet ./... ; if ($LASTEXITCODE -ne 0) { throw "go vet failed" }
& go build -buildvcs=false ./...; if ($LASTEXITCODE -ne 0) { throw "build failed" }
& go test ./... -count=1 ; if ($LASTEXITCODE -ne 0) { throw "tests failed" }
& git diff --check ; if ($LASTEXITCODE -ne 0) { throw "diff check failed" }并发相关改动追加重复跑:
& go test ./internal/protocol -count=100; if ($LASTEXITCODE -ne 0) { throw "repeated tests failed" },
并执行 5.3 的 race detector。
每个命令后必须检查 $LASTEXITCODE:PowerShell 不会因原生命令失败而中断脚本,
漏检会导致“测试没跑却宣称通过”。
-
本机已具备 CGO 和 C 编译器;提升 GCC 目录优先级后执行完整 race 验证:
$gccBin = Split-Path -Parent (Get-Command gcc -ErrorAction Stop).Source $env:PATH = "$gccBin;$env:PATH" $env:GOCACHE = Join-Path $env:TEMP "auto-mas-runtime-race" & go test -race ./... -count=1 if ($LASTEXITCODE -ne 0) { throw "race tests failed" }
-
当前 Codex 受管沙箱可能同时注入大小写不同的
PATH/Path,Go 重建 cgo 子进程环境时会使 旧顺序重新生效,表象仅为runtime/cgo: ... cgo.exe: exit status 2。确认 GCC 路径与 DLL 优先级正确后,应获批在沙箱外重跑同一命令;只有退出码为 0 的完整输出才能作为 race 通过证据; -
golangci-lint本机未安装,只在需要时按 README 安装固定版本。
.github/workflows/ci.yml:push / PR 触发,windows-latest + pwsh,
步骤 = checkout → setup-go(读 go.mod)→ gofmt 检查 → go vet → go build → go test。
本地基础验证门与 CI 保持一致;race detector 是并发相关改动的本地追加门,当前 CI 未覆盖,
不得把本机 race 结果表述成 CI 证据。
所有实现工作必须对应 doc/任务拆分.md 中的一个任务编号(T<里程碑>.<序号>)。
开工前确认:任务的「依赖」是否已完成、「内容」和「验收」写了什么。
清单里没有的需求,先补进任务拆分并登记变更记录。
设计 doc/current/M*/设计-T*.md → 计划 doc/current/M*/计划-T*.md → TDD 逐任务实现 → 审查 + 验收回写
- 设计:目标、范围与边界(含明确的「不负责」)、API 形态、并发/失败语义;
- 计划:拆成若干可独立提交的 Task,每个 Task 写明「文件 / 红灯 / 绿灯 / 验证与提交」, 固定测试函数名,验证命令直接可粘贴执行;计划不复制大段最终代码,任务完成后删除并由 Git 历史追溯;
- 实现:严格 TDD——先写失败测试并确认失败原因正确,再写最小实现;
- 审查:每个 Task 提交后独立审查,Critical/Important 修完才进入下一个 Task;
修复独立提交(
fix: ...)。
- 代码已提交到
main(或经 PR 合入); gofmt无 diff、go vet ./...无告警、go test ./...全绿;- 任务条目中的「验收」逐条满足;
- 不回退任何已通过的协议契约测试;
- 涉及对外契约的实现与
doc/架构设计.md一致。
在 doc/任务拆分.md 中:- [ ] 改 - [x],标题行尾追加 ✅ YYYY-MM-DD <commit 短哈希>;
进行中用 🚧,受阻用 ⛔ <一句话原因> 并登记第 7 章「变更记录」;
里程碑复选框只有在其下全部任务勾选后才能勾。
进度提交独立于代码提交,形如 docs: 记录 M1 协议层完成情况。
先改文档 + 登记变更记录,再写代码。 不允许用代码“事实上”推翻已冻结的契约。
特性开发在 .worktrees/<name> 下的 worktree 里进行(.worktrees/ 已被 .gitignore 忽略),
完成后回 AUTO-MAS Runtime 主 worktree 根目录执行 git merge --ff-only <branch>,
并确认 git rev-list --left-right --count main...<branch> 为 0 0。
git push、创建远端仓库/Release、向任何外部服务发送仓库内容,
必须先获得用户明确授权,每次都要单独授权,不因上次批准过就顺手推一下。
授权范围要说清楚:git push 推的是分支 tip,会连同全部未推送的祖先提交一起发布,
先用 git rev-list --left-right --count origin/main...HEAD 确认实际数量再请求授权。
-
Conventional Commits,type 使用英文小写,描述使用中文,标题结尾带任务号:
feat: 强制协议终态 result (T1.6) fix: 限制重复键诊断信息规模 (T1.6) test: 覆盖协议终态契约 (T1.6) docs: 记录 M1 协议层完成情况 -
常用类型:
feat/fix/test/docs/refactor/chore/ci; -
一个 Task 一个提交,只
git add该 Task 明确列出的文件(计划文档里会显式校验暂存清单); -
提交前跑
git diff --check;不要--no-verify,不要跳过签名。
| 对象 | 语言 |
|---|---|
| 标识符、包名、文件名 | 英文 |
| 注释(含包注释、导出声明的 doc comment、实现内注释) | 中文 |
Go error 字符串(errors.New / fmt.Errorf) |
英文、小写开头、无结尾标点 |
协议中用户可见的 message 字段 |
中文(如「正在安装 Python 依赖」) |
| 提交信息 | 英文 type + 中文描述 |
doc/ 下的设计与任务文档 |
中文,中英文之间留空格 |
中文注释仍遵循 Go 官方 doc comment 格式(Go Doc Comments):
以被注释的标识符开头,标识符保持英文原样,随后用中文说明;每个包必须有包注释或 doc.go。
// Package protocol 定义单次 Runtime 操作的事件、错误、生命周期、渲染和 stdin 控制契约。
package protocol
// Emitter 通过 ProcessOutput 写出类型化协议事件。
type Emitter struct{ ... }
// NewProcessOutput 创建进程内唯一的 NDJSON 输出所有者。
// output 一旦交出即由 ProcessOutput 独占,调用方不得再直接写入。
func NewProcessOutput(output io.Writer) (*ProcessOutput, error) { ... }注释写「为什么」,不复述「做了什么」;能用命名表达的不写注释。
存量代码: internal/protocol 现有注释为英文,不做批量重写(避免无意义 diff 掩盖真实改动)。
新增代码和被修改的声明改用中文,但同一函数/同一声明内不混排两种语言。
需要统一迁移时作为独立任务执行,单独提交。
本仓库采用 Go 社区与大厂的公开标准,不自造风格。冲突时按以下优先级:
- Effective Go 与 Go Code Review Comments —— 语言级惯例,最高优先级;
- Google Go Style Guide(Style Guide / Style Decisions / Best Practices)—— 大型代码库的一致性决策;
- Uber Go Style Guide —— 具体条目(并发、性能、错误)可作补充参考;
- 本文件 8.9~8.13 的项目特有约束 —— 覆盖以上通用规则。
工具层面由 gofmt + goimports + go vet + .golangci.yml
(errorlint、gocritic、misspell、nilerr、nolintlint、revive)强制,
风格问题优先靠工具解决,不靠人工争论。
- 包名:小写单字,不用下划线、驼峰或复数;禁止
util、common、base、helper等无信息量的包名; - 避免口吃:
protocol.Event而非protocol.ProtocolEvent;config.Layout而非config.ConfigLayout; - 缩写整体大小写一致:
ID、URL、HTTP、JSON、PID;operationID而非operationId(JSON 字段名operationId由 struct tag 表达,不影响 Go 字段名); - 单方法接口用
-er后缀:EventRenderer、Downloader; - getter 不加
Get前缀:o.Sequence()而非o.GetSequence(); - 变量名长度与作用域成正比:循环内
i、err可以,包级导出变量必须自解释; - receiver 用 1~2 个字母且同一类型全程一致(
func (o *ProcessOutput)就一直是o);不用this/self; - 导出的 sentinel error 用
Err前缀:ErrResultAlreadyEmitted;错误类型用Error后缀。
- 不忽略错误。 确实要忽略时写成
_ = f()并在同行/上一行用注释说明为什么安全; - 包装保留错误链:
fmt.Errorf("clone %s: %w", branch, err);判定一律用errors.Is/errors.As, 禁止err == ErrX和字符串匹配(errorlint会拦); - 错误字符串英文、小写开头、无结尾标点、不含换行;不要以 "failed to" 开头堆叠, 包装时只加本层上下文;
- 每层只包装一次,不重复堆同样的信息;
- happy path 左对齐:失败尽早
return,减少else与嵌套; - 库代码不
panic、不os.Exit、不log.Fatal;只有cmd/auto-mas-runtime的main可以决定退出码; panic只用于表示程序自身的不变量被破坏(且必须有测试覆盖该不变量);- 错误必须能映射到架构文档的错误码全集,见 8.11。
ctx context.Context永远是第一个参数,命名固定为ctx;不把 ctx 存进结构体;- 不传
nilctx;测试用t.Context()或context.Background(); - 超时与取消必须贯通到底层:HTTP 请求、子进程(
exec.CommandContext)、文件轮询都要接 ctx; - 谁启动 goroutine 谁负责它的退出路径,不留泄漏;退出条件写进注释;
sync.Mutex用零值、不用指针;mutex 紧邻它保护的字段声明,并注释保护范围 (internal/protocol.ProcessOutput是现成范例:单一线性化域覆盖 renderer、sequence、terminal、warning ledger);- 复制含 mutex 的结构体是 bug;需要传递就用指针;
- 禁止用
time.Sleep做同步(生产和测试都是);用 channel、sync.WaitGroup或 barrier。
- 接受接口、返回具体类型;
- 接口在消费方定义,不在实现方;保持小(1~3 个方法);
- 不做投机抽象:只有真的存在第二个实现或测试替身需求时才抽接口;
- 架构文档强制注入的依赖:网络、Git、uv、进程、时钟。这些必须以接口或函数字段注入, 单元测试不得触碰真实公网、真实 Python/Git(见第 9 节);
- 时钟注入沿用现有形态:
WithClock(func() time.Time)。
- import 分三组,组间空行,由
goimports维护:标准库 / 第三方 /github.com/AUTO-MAS-Project/AUTO-MAS-Runtime/...; - 禁止点导入(
import . "x");_空白导入必须写明用途注释; - 避免
init()和包级可变全局状态;配置显式传参;确需包级常量用const; - 文件内顺序:包注释 → import → 常量 → 类型 → 构造函数 → 方法 → 包内辅助函数;
- 一个文件聚焦一个主题(现有
emitter.go/renderer.go/lifecycle.go/control.go即此风格); - 测试文件与被测文件同名加
_test.go;需要白盒断言时用同包测试, 对外 API 用_test外部包(现有renderer_internal_test.go与renderer_test.go的分工)。
- 零值可用:
var buf bytes.Buffer而非new(bytes.Buffer);设计类型时优先让零值有意义; - 已知容量就预分配:
make([]T, 0, n)、make(map[K]V, n); - 字符串拼接用
strings.Builder,不在循环里+=; - 结构体字面量必须写字段名;
defer用于释放资源,注意不要在循环体内 defer;- 时间用
time.Duration,不用裸int秒;含单位的字段名带单位(timeoutSeconds只在 JSON 契约里出现); - 长函数禁止裸返回(naked return);
- 枚举用具名类型 + 常量组 +
String(),并提供合法性校验(现有 stage / status 即此模式); - 不引入非必要依赖;新增依赖需在任务文档中说明理由并固定版本。已批准方向:CLI 使用 Cobra、
Git 使用 go-git、Windows 系统调用继续使用固定版本
x/sys/windows;google/go-cmp仅可用于 测试结构比较。M12 仅允许 Sentry SDK 由internal/telemetryadapter 直接导入;Umami 已取消,不得新增 Umami SDK 或 HTTP adapter。业务包、protocol和logging禁止依赖观测实现; Sentry SDK 的默认 PII、日志与 tracing 能力必须按架构白名单关闭。具体边界见doc/maintenance/现成库替换评估.md和doc/current/M12/设计-T12.1-遥测与错误观测.md。
-
只有
cmd/auto-mas-runtime进程入口可以持有os.Stdout;internal业务包不得导入或保存它; -
--output ndjson时进程入口只创建一个protocol.ProcessOutput和唯一的protocol.Emitter(ProcessOutput会拒绝第二个 emitter);业务包只接收类型化事件出口; -
七种事件(
hello/progress/state/log/warning/error/result)全部经同一个 Emitter 发射, 不得直接fmt.Print*、log.Print*或json.NewEncoder写 stdout; -
Runtime 自身诊断写 stderr;受管进程的 stdout/stderr 转成
log事件 + 轮转日志文件; -
新增输出路径时执行并逐项审查:
rg -n 'os\.Stdout|fmt\.F?[Pp]rint|log\.[Pp]rint|json\.NewEncoder' --glob '*.go' . if ($LASTEXITCODE -gt 1) { throw "stdout ownership scan failed" }
首事件必为 hello;sequence 进程内从 1 严格递增;每行恰好一个 JSON object 且每行 flush;
result 恰好一次且最后,发出后拒绝一切后续事件;warning 由协议层权威汇总进
result.details.warnings(上限 256,超出置 truncated)。
- 错误码、退出码、
retryable、remediation四元组以架构文档「错误码全集」为唯一来源, 失败result必须复述主错误的四元组; - 新增错误码可在协议 v1 内追加;删除、改名或改变既有语义必须升级协议版本;
stage标识可追加,既有标识不得改名;- 调用方(Electron/测试)只按稳定字段判断,禁止解析中文文案、uv 输出或 Git 输出驱动流程—— 实现侧同样不许靠解析自然语言做业务分支。
- 任何递归删除前必须:规范化绝对路径 → 校验位于受管根内 → 排除安装根/用户数据根/盘符根/空路径 → 拒绝跟随未知 Junction/符号链接 → 按状态确认目录身份 → 写审计日志 → 身份不明即失败关闭,绝不猜测;
- 用户数据(
config/ data/ history/ script/ debug/ plugins/)、插件运行包和外部脚本目录 任何自动流程都不得删除或移动; - 禁止按进程名批量终止(
taskkill /im python.exe之类),进程树只能通过自己创建的 Job Object 回收。
- 一律
exec.CommandContext+ 参数数组,不拼 Shell 字符串; - 禁止直接调用
python.exe/pip/.venv\Scripts\python.exe,Python 工具链统一走受管uv.exe; - 禁止
uv self update、在线安装脚本(irm astral.sh/uv/install.ps1); - TLS 校验默认开启且不提供关闭开关。
- 分层:单元 / 组件 / 契约 / Windows E2E。必测场景见架构设计「自动化测试矩阵」, 实现某任务时对照该表逐行覆盖;
- 网络、Git、uv、进程、时钟必须经接口注入;单元测试不得依赖真实公网或用户机器上的 Python/Git;
- 夹具:本地裸仓库 + 本地 HTTP 服务(Git)、假
uv.exe(T5.8)、假后端进程(T6.6); - 所有测试使用临时受管根目录,结束后校验无残留进程、Mutex、临时目录;
- 并发/线性化用 barrier + 超时做确定性证明,不靠
time.Sleep撞运气,并用-count=100复跑; - 新命令接入契约测试的成本应保持为一行注册(
contracttest.Register)。
Go 测试惯例(Go Code Review Comments / Google Best Practices):
- 表驱动测试 +
t.Run子测试,用例结构体带name字段; - 测试辅助函数第一行写
t.Helper(),失败行号才会指向调用处; - 临时目录用
t.TempDir(),清理用t.Cleanup(),不手写defer os.RemoveAll; - 普通条件、错误链、顺序和副作用使用标准库显式断言;结构体、slice、map 的语义比较可使用
仅测试依赖
google/go-cmp;不引入 testify/gomega,不建立通用assert包; - 失败信息写成
got X, want Y形式,带上定位所需的输入; - 测试函数命名沿用仓库惯例
TestType_Scenario(如TestEmitter_ConcurrentResults); 计划文档中固定的测试函数名不得随意改动; - 用
-run跑定向测试时必须同时确认「退出码为 0」「输出不含[no tests to run]」 「出现--- PASS:」三件事,见 11 节。
- 业务包直接写 stdout,或绕过
protocol.Emitter发协议事件; - 改动已冻结的对外契约(字段、错误码、stage、state、环境变量、目录布局)却没先改文档;
- 未获授权执行
git push或把仓库内容发往外部服务; - 直接调用
python/pip,或让 Runtime 去管插件依赖; - 按进程名批量杀进程;
- 自动流程删除用户数据、诊断日志、插件目录或受管根之外的路径;
- 先删旧
repo再下载新版本(必须先克隆校验完成再整体替换); - 靠解析自然语言输出判断业务状态;
- 宣称“测试通过 / race 通过”却没有当次完整命令和退出码证据(工具可用不等于测试通过)。
- 工具从 PATH 解析:不要固化本机绝对路径;顺手把
$env:GOCACHE指到临时目录, 避免权限问题和工作区污染。 - GCC 能找到但 cgo 失败:先按 5.1 把 UCRT64
gcc.exe所在目录提升到PATH首位, 排除同名 DLL 冲突;Codex 沙箱内仍失败则按 5.3 获批在沙箱外复跑。 $LASTEXITCODE不检查等于没跑测试:PowerShell 不会自动中断。-run打错正则 →[no tests to run]却退出码 0:计划文档里的模板会同时校验 “退出码为 0”“输出不含[no tests to run]”“出现--- PASS:”,照抄这个模式。- 注释中文、标识符英文:注释(含 doc comment)写中文,doc comment 仍以英文标识符开头; Go error 字符串保持英文小写;不要把设计文档写成英文,也不要在同一声明里中英混排。
- 改协议前先看
doc/契约补充-v1.md和doc/契约补充-v1-增补1.md:架构设计里的概括描述常被它们进一步收紧; 增补 1 还修订了 C2 第 1 条(protocol由后端自报而非回显)与 C4 第 1 条(受监督但非管理员时记 warning 并继续运行)。 - 决策已冻结的事项不要重开:D1
D12 与 C1C11 是用户已确认的结论(D2/D4/D8/D9/D10 已被后续决策取代,原文只作追溯); 当前仍待决的是 D-open-4、D-open-5、D-open-7、D-open-10。