docs/specs/ 是行为语义的来源真相,改行为先改 spec,再改代码,两者在同一个 PR 里落地。本页把 AGENTS.md、docs/specs/code-style.md 和 CI 配置整合成一份贡献者清单;AGENTS.md 是这些约定的权威版本。
三条设计原则
三条原则同时约束 spec 和代码。展开说明与代码示例见 设计原则与代码约定。 Sans-IO 是默认规则。新子系统先定义纯内存 core:显式的输入事件、状态迁移和输出命令;RPC、UDS、存储、时钟、日志、指标都放到 adapter。判断标准是 core 能否在没有任何 IO 的情况下用表驱动测试完整回放。Worker、Coordinator、Dispatcher 都是这种形态。 Scoped Resource Context 用于以资源拥有权和回收为中心的子系统,典型是 IO 访问子系统。把 Worker 级共享资源和 task 级局部资源建成显式作用域(如WorkerIOScope / TaskIOScope),quota、cache、singleflight、deadline 和清理都绑定到作用域生命周期,清理是 scope 退出的结构性属性,而不是”稍后再发一条释放命令”。当把一个模块硬拆成事件/命令流反而让所有权变模糊时,用这条。
Occam’s Razor 对两者都适用。不新增 struct、interface、错误码、队列、状态或服务,除非能说清楚”为什么现有 module / core / adapters / scope 边界装不下它”。如果一个行为既不能表达成一小组可枚举的状态、事件、命令,也不能表达成一小组 scope 的获取与释放规则,说明设计还太模糊,先回去改 spec。
提交一个改动的流程
1
读对应 spec
找到
docs/specs/ 中定义该子系统的文件(如 worker.md、io-subsystem.md、call-execution-subsystem.md),确认你要改的行为当前的定义,理解它的设计意图。2
改行为语义就先改 spec
协议、生命周期、超时、错误码语义有变化时,先在同一个 PR 里更新 spec,再写代码。
api/ 下的结构体不能偷偷成为新的协议真相。3
写 core 逻辑与表驱动测试
在
internal/<module>/core/ 里改状态机、幂等判定、阶段推进;测试放在同目录 *_test.go,覆盖 spec 里写的 happy path 与失败 / 超时路径。4
接 adapter 与协议映射
在
internal/<module>/adapters/ 里把 core 的命令翻译成副作用,把外部回调重新包装成 core 事件。adapter 测试只覆盖协议映射、错误翻译和编排,不重复 core 的状态组合。5
本地验证
make test 会依次跑 fmt 检查、go vet 与带覆盖率的单测。6
跑相关 E2E
按改动范围选:
go test -v -timeout 300s ./cmd/worker/...(worker 进程 E2E)、./cmd/bundle_worker/...、./cmd/syncinvoker/...、./e2e/contract/...、./e2e/system/...。这些都要先 uv sync --project python。7
提 PR
目标分支
dev。PR 描述写清目的、涉及的 spec / 模块路径、跑过的验证命令和后续工作(见下文)。代码约定速查
以下条目从docs/specs/code-style.md 提炼,是 review 中最常被指出的问题。完整约束以该文件为准。
cmd/只做装配与启动。不放领域判断、准入策略或协议分支;worker / coordinator 入口只是app.Profile清单,公共装配在internal/*/app/。core/不直接依赖 JSON-RPC、gRPC、etcd client、数据库 client、日志与指标实现。core/不自己取当前时间、生成随机值或启动 goroutine。时间、随机数由 adapter 作为输入传进来;并发属于 adapter。core/里尽量不用context.Context。取消、超时、TTL 到期、deadline 推进建模成显式事件或输入字段。core/的输出是可枚举命令、决策结果或状态快照;adapter 负责执行,模式是”输入事件 → core 决策 → adapter 执行命令”,不让 core 持有反向 callback。- interface 定义在真正的消费侧。adapter 调 core 直接依赖具体类型(
WorkerCore、CoordinatorCore),不为 core 抽 interface;没有第二个实现或测试替身需求前不提前抽接口。 - 不引入
pkg/utils、common、shared这类没有边界的汇总目录。 - 导出名避免
Manager、Util、Data、Info这类弱语义后缀;状态、事件、命令直接反映领域语义,如WorkerCore.HandleTaskPhaseFinished、PhaseTransitionResult(internal/worker/core/)。 - 需要多个布尔字段组合才能理解的对象状态,改成显式状态枚举;不滥用
map[string]any与零散字符串字面量。 - 错误不靠字符串判断。稳定语义依赖错误码、枚举或命名结果类型;预期业务结果在 core 里建成显式结果,不滥用
error。 - 先区分”准入 / 协议错误”与”已进入执行后的终态结果”,不要混成一套返回。
api/只放跨模块共享的协议结构、消息包络和字段约定,不放 handler、存储模型或状态机;改协议优先加可选字段或新枚举值,不静默改既有字段含义。- 时间语义集中建模。slot TTL、task deadline、结果保留窗口收敛在 Worker 模块及其 timer adapter,不在多个 adapter 里各自复制”超时后怎么判定”。
- scope-oriented 模块里,谁拥有资源谁就是真相来源;不让调度层、hook 层和 backend adapter 各自维护影子计数器。
- goroutine 的创建、退出和回收路径必须清楚,不能靠进程退出兜底。
Commit 与 PR 规范
分支模型。 日常开发合入dev;CI(.github/workflows/test.yml)只在 PR 目标为 dev 或 push 到 dev 时运行。GitHub 上的默认分支是 main,但它明显落后于 dev(本地检查时 main 停在 2026-06 的 #335,dev 在 2026-08 的 #495),镜像 tag(v1.0.x、dev-v1.0.x-n)都从 dev 打出。所以:从 dev 拉分支,PR 回 dev。.github/ 下没有 PR / issue 模板,也没有 CODEOWNERS。
Commit 信息。 祈使语气、一个 commit 只做一件事(spec 更新、core 逻辑、adapter 接线、测试分开提)。格式用 模块: 摘要,例如 worker: tighten slot idempotency;仓库近期历史里中英文都有(io: keep idempotent BlockDB writes retryable、deploy: 支持从 S3 pointer 加载 worker.env),关键是范围前缀清楚、摘要具体,不要只写 fix。
PR 描述至少包含:
- 目的:解决什么问题。
- 影响的 spec 与模块路径(如
docs/specs/worker.md、internal/worker/core/)。 - 跑过的验证命令(贴出实际命令)。
- 后续工作或已知未覆盖的场景。
- 行为有变化时,链接对应 spec 并说明兼容性影响。
测试要求
Go 测试与实现放在同一目录(*_test.go),状态机、协议映射、core / adapter 边界优先用表驱动测试;新行为要同时覆盖 spec 里的成功路径和失败 / 超时路径;改协议或生命周期语义时,测试和 spec 在同一个变更里更新。CI 会跑 Go 单测、Python 单测、分 8 片的 Worker Process E2E、bundle worker / contract / system E2E 和 -short 的 Perf E2E。测试的目录组织、命令与 E2E 说明见 测试。
AI agent 协作
AGENTS.md是仓库级协作说明的权威文件:目录约定、构建 / 测试命令、编码风格、设计原则、测试与 PR 规范。人和 AI agent 都以它为准。CLAUDE.md只有几行,指向AGENTS.md,避免两份文件漂移。.claude/在.gitignore里,是本地工作目录,不入库。当前本地里放的是性能排查产物(pprof-blockx-worker-*、profile-*、pyspy-*里的 pprof / py-spy 采样文件、optimization-priority.md之类的分析笔记)和一个worktrees/目录(供 agent 开 git worktree 用)。里面没有共享的 agent 配置、命令或 hook;不要把它当作团队约定的来源。- 让 agent 改代码时,把
AGENTS.md和对应 spec 一起给它读;agent 产出的 PR 同样要满足上面的 commit / PR 规范和验证要求。
相关文档
blockx 仓库:AGENTS.md— 仓库协作与开发规范的权威版本。docs/specs/code-style.md— 模块边界、Sans-IO / Scoped Resource Context 的实现约束、错误与时间语义。docs/specs/architecture.md— 系统架构与模块划分。docs/specs/worker-test-organization.md、docs/specs/python-test-organization.md、docs/specs/system-e2e-testing.md— 测试组织约定。README.md— 三条设计原则与仓库结构。
设计原则
Sans-IO、Scoped Resource Context、Occam’s Razor 的展开说明与代码示例。
仓库结构
cmd/、internal/、api/、python/ 各放什么。测试
单测、E2E、perf 测试的组织与命令。
本地开发环境
Go、uv、etcd 与依赖 stub 的准备。