4. Outbox 回复¶
域内 `reply` 决定「能否发、发什么 purpose」;**Outbox 适配器**是唯一写 receipt 的地方,把消息排进 Effects,再调用 Source 的 channel API。ack、answer、result、attention 都走这条链。
在主线中的位置¶
accept 通常会产出一笔 acknowledgement pending receipt。worker ready 后可能 result;attention 路径有 answer。本章不重复 Intake,只描述 Replies → Outbox port → Store receipt → reply effect → Source.send。
一步事务里做什么¶
Engine.reply(core/replies.ts)校验 purpose 与 Ticket 状态,例如:
- acknowledgement:需 human actor、channel,且 Trigger
reachesTicket;可能takeUpdisposition。 - answer:Ticket 的
answers须含相关 trigger 或已有 outbox 记录。 - result:Ticket 须 ready/completed/merged/dropped,或 live Ticket 且最新 report 为 ready。
- attention:question 须匹配
ticket.attention。
通过后调用 Outbox port 的 send(app/outbox.ts):
- 渠道侧校验(如飞书 reply 长度,
infra/text.ts)。 receipts.add写入 SQLiteoutbox表(pending)。- enqueue
replyeffect(与域行同一atomic)。
commit 后 Outbox handler deliver:检查同 ticket+conversation 前序 pending(有则 Later);调用 SourceRegistry.send;成功则 receipt → sent,Source 消失/忽略则 gone/ignored;连续失败可 settle 为 dropped(旁路 outbox.spec.ts 覆盖behind 与重试)。
Outbox id 常由 ids.ts 内容派生,如 key('ack', triggerId),保证幂等与去重。
为什么 Engine 不直接调 GitHub/飞书¶
Source 插件各自实现 send;Registry 按 channel 路由。Engine 只认 Outbox 端口,适配器持有 Store 与 Registry,保证 receipt 与 enqueue 同事务,避免「域认为已 ack 但库中无 receipt」或反之。
涉及模块¶
| 路径 | 职责 |
|---|---|
core/replies.ts |
reply 规则 |
app/outbox.ts |
send/deliver、receipt 写者 |
app/effects.ts |
reply kind、kick |
sources/*-channel.ts |
实际 API send |
app/store.ts |
outbox.pending 工作集 |
写者与不变量¶
- Receipt 行:仅 Outbox 适配器(Engine 只调 port)。
- Effect 行:Engine 事务内 enqueue;handler 删行或退避。
边界¶
| 情况 | 行为 |
|---|---|
| 同 conversation 前序 pending | Later,保持顺序 |
| Source 未安装 | Later,等待注册 |
| 三次失败(非 delivery 类) | health error;reply 可能 dropped |
| Feishu 超长 | send 前 UserError / 校验失败 |
测试¶
- 旁路:
outbox.spec.ts。 - Python:
test_flows.test_flow_outbox_reply(accept → report ready →engine.replyresult → reply 含 id);accept 路径常断言 outbox 含 pending ack。
sequenceDiagram
participant Eng as Engine Replies
participant OB as Outbox adapter
participant ST as Store receipts
participant FX as Effects reply
participant Src as SourceRegistry
Eng->>OB: send message
OB->>ST: add receipt atomic
OB->>FX: enqueue reply
FX->>Src: send
Sources 发送与 GitHub/飞书文件族见 reference-semantics.md Sources 一节。