AGENTS.md 和 docs/specs/code-style.md 把它们展开成了具体的模块边界、依赖规则、错误语义和时间语义。这一页是这两份文件的导读,帮你在写代码前知道”什么会被 review 打回来”。
三条原则
Sans-IO:默认规则
Sans-IO:默认规则
新子系统先定义纯内存 core,用显式事件和命令描述行为,再在外面包 adapter。core 只维护状态机、幂等判定、阶段推进和结果收敛;RPC、UDS、etcd、数据库、时钟、日志、指标全部留在 adapter。仓库里的
WorkerCore(internal/worker/core/)、CoordinatorCore(internal/coordinator/core/)、DispatcherCore(internal/worker/core/dispatcher.go)都是这种形态。它们是代码边界,不是新增进程或角色。Scoped Resource Context:资源治理型子系统的规则
Scoped Resource Context:资源治理型子系统的规则
IO 访问这类以”谁拥有资源、什么时候释放”为中心的模块,不强行拆成事件/命令流。它们显式建模 Worker 级共享作用域和 task 级局部作用域,把 quota、cache、singleflight、deadline 和清理绑定到作用域生命周期上。作用域退出是结构性清理边界,不依赖”稍后再发一条释放命令”。
internal/io/ 是这种形态,入口是 WorkerIOScope / TaskIOScope 这样的同步接口。Occam's Razor:同时约束 spec 和代码
Occam's Razor:同时约束 spec 和代码
如无必要,勿增实体。新增 struct、interface、错误码、队列、状态或服务前,先问现有概念能不能复用或简化。如果一个新实体说不清”为什么现有
module / core / adapters / scope 边界装不下它”,先不要加。AGENTS.md:如果一个行为是生命周期重的(slot、task、call 的状态推进),用显式状态、事件、命令表达;如果它是资源治理重的(连接池、配额、缓存),用显式作用域拥有权、获取和清理规则表达;如果两种框架都给不出一组小而可枚举的规则,说明设计还太模糊。
分层与依赖规则
不要引入没有明确边界的
pkg/utils、common、shared 汇总目录。仓库里现有的 internal/common/ 只放 argspool、clientid、types、unsafebytes 这几个有明确用途的小包,不是通用杂物箱。
adapter 与 core 的交互模式
推荐”输入事件 → core 决策 → adapter 执行命令”的单向模式,而不是让 core 持有一组反向 callback。docs/specs/code-style.md 给的示意:
interface 使用
- interface 定义在真正的消费侧。
- adapter 调用 core 时通常不需要再为 core 抽 interface,直接依赖
WorkerCore、CoordinatorCore等具体类型。 - 只有当 core 确实需要一个同步 port,且这个 port 能保持纯、窄、可替换时,才在
core/内定义最小 interface 由 adapter 实现。 - 没有第二个实现或明确测试替身需求前,不要为”以后可能扩展”提前抽接口。
命名与建模
- 包名短、稳定、领域化,优先名词。
- 导出标识符用明确名字,避免
Manager、Util、Data、Info这类弱语义后缀。 - 状态、事件、命令直接反映领域语义,例如
TaskPhaseFinished、PrepareTaskActivation、ReleaseSlot。 - 优先显式 struct 和命名枚举,不滥用
map[string]any、any或零散字符串字面量。 - 需要多个布尔字段组合才能理解对象状态时,改成显式状态枚举。
NewXxx只在能建立不变量时使用;字面量包装不必强行写构造器。
错误与结果表达
- 先区分”准入 / 协议错误”和”已进入执行后的终态结果”,不要混成一套错误返回。在 Worker 上,边界是 slot 是否已从
ALLOCATED激活到RUNNING:激活前的错误是提交 / 准入层错误,激活后的失败统一进入TaskResult。 - 稳定语义依赖错误码、枚举或命名结果类型,不依赖错误字符串。
- 对外协议已有稳定错误码约定时以协议字段为准,不在 adapter 内再发明平行语义。
- 在 Sans-IO core 里,预期业务结果建模成显式结果,不滥用
error。 TaskResult、InvalidSlot、NoSlot、Unavailable等边界必须与docs/specs/architecture.md、docs/specs/worker.md一致。
时间语义
- 时间语义集中建模,不散落在 handler、Plugin、driver 各自判断。
- Worker 侧的 slot TTL、task deadline、结果保留窗口收敛在 Worker 模块及其 timer adapter,以
docs/specs/worker.md为准。 - Coordinator 侧的视图新鲜度、候选重试和选址相关时间语义收敛在 Coordinator 模块,以
docs/specs/task-resource-coordinator.md为准。 - 在 scope-oriented 模块里,生命周期结束优先靠 scope
Close()、context 取消和结构性 cleanup 保证,再辅以迟到结果防御。 - goroutine 的创建、退出和回收路径必须清楚,不能把生命周期管理留给进程退出兜底。
测试与文档同步
core/测试重点覆盖状态迁移、幂等、TTL、deadline 和失败收敛,优先表驱动。- scope-oriented 模块测试重点覆盖 quota 获取 / 释放、scope 关闭、迟到结果丢弃、singleflight 行为和资源无泄漏。
- adapter 测试重点覆盖协议映射、错误翻译、命令执行编排,不重复 core 已覆盖的状态组合。
- 修改协议或生命周期语义时,测试与对应 spec 在同一变更中一起更新。