AGENTS.md@src/host/scheduler · git:20260928.0bc633c · 2026-09-28 · sha256 d7e27d74c15c97c0

AGENTS.md@src/host/scheduler git:20260928.0bc633cA

Immutable. This exact content never changes and is served at /api/v1/blob/d7e27d74c15c97c0.

# Scheduler Module Rules

## 范围与职责

适用于 `src/host/scheduler/`。

按用户配置的**执行窗口**与**触发策略**,驱动既有编排运行时运行所选工作流模板的实例:

- 任务配置的校验、规范化与持久化;
- 时间语义:时区换算、触发点推算、窗口判定;
- 决策与推进:何时触发、何时挂起、何时续跑、何时跳过;
- 触发时的实例化语义(模板 → 实例)与会话策略分派。

判断归属:该修改是否改变**定时任务的配置契约、时间语义或触发/挂起/续跑决策**?若主要属于时间基元之外的其他领域,应放到对应模块。

## 时间语义契约

时间语义必须确定、可测、与时区显式绑定:

- 时间的解析/格式化/换算/推算一律为**纯函数**:相同输入 → 相同输出,不读系统时钟、不读环境时区、不依赖全局状态;需要"当前时刻"时经参数传入;
- 绝对时间在存储与比较层面统一用 UTC 毫秒;用户可见的时刻("HH:mm"、日期)一律按任务自身声明的时区解释——**禁止**使用进程本地时区或隐式时区;
- 跨天区间(结束不晚于开始)必须与跨天触发点、跨日期窗口扫描的语义一致,不得各处自行解释;
- 调度语义分两层且语义固定:「执行窗口」决定何时允许运行,「触发策略」决定何时应当触发;**触发成立的条件是两层同时满足**。

## 子域边界

模块内部存在变化原因不同的子域:

- 子域之间只通过明确的输入输出协作,不得互相承担对方职责;
- 时间基元不理解"任务";窗口判定与触发计算不理解持久化;配置契约不读盘、不决策;决策引擎不重复实现时间算法;
- 新增能力先判断属于哪个子域,再放到该子域的职责中,不得为就近而堆进已有位置。

## 依赖边界

- 只允许依赖共享契约层(任务实体与窗口/触发配置的形状)与本模块内部;
- 对外部能力的依赖必须是抽象缝(接口 + 注入)。

## 验证补充

- 时间相关断言全部使用**固定日期与时区**,不依赖运行机器的本地时区与当前时间;
- 窗口边界、跨天区间、跨日期扫描、无解配置(永不触发)等边界行为均有测试锁定;
- 决策路径的关键分支均有测试锁定;
- 重叠扫描、重复启动、终止后再启动等并发与生命周期行为有测试锁定;

## 核心原则

1. 时间语义确定且时区显式,纯计算不读时钟。
2. 窗口与触发两层语义固定,缺一不触发。
3. 收敛、校验、规范化各有唯一实现且顺序固定。
4. 扫描可重入安全,终止后不复活。