From b3beaf5e191f9db1acee5ad0799655354a4fb3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Wed, 22 Apr 2026 02:46:17 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20add=20reflex=20semantics=20=E2=80=94=20?= =?UTF-8?q?interval=20origin,=20event=20compensation,=20idempotency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 小橘 --- docs/rfc-001-observation-engine.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/rfc-001-observation-engine.md b/docs/rfc-001-observation-engine.md index b154633..b98e01f 100644 --- a/docs/rfc-001-observation-engine.md +++ b/docs/rfc-001-observation-engine.md @@ -118,16 +118,35 @@ reflexes: on: ["disk-usage"] ``` -三种触发条件: +两种触发条件: | 条件 | 含义 | |------|------| | `interval` | 定时触发 | | `on: [patterns]` | 当指定的 Sense 产生新记录时触发 | -| `demand` | 被外部查询时触发(API 调用等) | 一个 Sense 可以有多个触发条件(如 `active-tasks` 同时有事件触发和定时兜底)。 +OnDemand(按需触发)不需要声明——引擎内置提供,任何 Sense 都可以被外部 API 调用触发。 + +#### Reflex 语义规则 + +**Interval 起点**:以库中记录的上次 compute 完成时间为准,不是 daemon 启动时间。daemon 重启时,若已过期则立即执行一次,然后恢复正常节奏。不会对停机期间的缺失进行逐次补偿。 + +**Event 补偿**:OnEvent 的语义是"有新数据了,该重新算一下",不是"每个 event 都要处理一次"。daemon 重启时最多触发一次 compute,compute 内部通过 `pullSince(lastTimestamp)` 拉取所有积压数据。 + +**合并与幂等**:同一个 Sense 同一时刻最多一个 compute 在执行。多个触发条件同时满足时合并为一次调用。compute 执行期间收到新 trigger,标记为 pending,当前完成后再执行一次。 + +``` +┌─ OnInterval 到了 ──┐ +├─ OnEvent 来了 ─────┤──→ 合并 → 一次 compute +└─ OnEvent 又来了 ──┘ + +compute 执行中 → 新 trigger 到达 → pending → 当前完成后再执行一次 +``` + +这些规则与 Sense 的语义一致——compute 是"重新感知当前状态",不是"处理某个具体事件"。无论触发几次,做的是同一个动作。 + ### 4.3 Workflow(Post-MVP) Workflow 定义一个有状态的工作流执行上下文(Thread)。内部包含: @@ -157,7 +176,7 @@ data Reflex = Reflex data ReflexCondition = OnInterval Interval | OnEvent [EventPattern] - | OnDemand +-- OnDemand 是引擎内置能力,不需要声明 -- Workflow 内部 moderate :: Thread -> CommandEvent -> (RoleId, Prompt) -- 纯函数 ✅