Files
go-sip/docs/thirds/v0.4.md
T

36 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SaaS ↔ Dispatcher:任务清单、控制与临时状态 v0.4(项目内目标草案)
**项目内 v0.4 Schema、隔离 Mock、运行代码及本地验收已完成(见 [`dispatcher-v04-local-acceptance.md`](../evidence/dispatcher-v04-local-acceptance.md));真实 SaaS 尚未签收或联调。** 已发布外部合同仍以 `contracts/upstream/v1/` 为基线;v0.3 历史发现见 [`v0.3`](v0.3.md),其余历史规则见[第三方对接顺序 v0.1](第三方对接事件与请求消费顺序_v0.1.md)。本文件不授权真实呼叫或部署。实施步骤与待冻字段见 [`plan-dispatcher-state-v0.1.md`](../plan-dispatcher-state-v0.1.md)。
## 1. 不变的两类 SaaS → D 队列
- 每个 Dispatcher 一条 SaaS 预建、独占的**控制队列**,接收 `task.control` 的 pause/resume/stop;每个归属任务另有一条 SaaS 预建**任务队列**,接收 `call.execute`。D 只消费,不能创建、绑定或删除。D→SaaS 的控制/命令回执和 `call.result` 仍走既有 per-D 结果路由,不能把结果队列误认为入站任务队列。
- 控制须先于任务新接纳生效,SaaS 先持久任务状态再按每任务顺序发布控制;控制回执是应用事实,RabbitMQ publisher confirm 不是 SaaS 已处理。不可将控制积压按 task 只保留最后一条:中间挂断、stop 排空及逐条回执仍须执行。
- SaaS 先停止向被 stop 的任务发布,D 持久屏障、处理在途执行并静默 ACK 所有未接纳积压;仅在原任务队列排空后回 stopped/applied,SaaS 确认回执后退役任务队列。无回执不得提前删队列。`resume` 不得重新启用本地已 stopped 的同一 task ID。
## 2. 重启全量、运行中增量(项目内已替换 v0.3 §2.5)
- **每次 D 进程启动/重启**,在关闭新执行的状态下读取 SaaS 对此 D 的完整归属清单;如需多页,各页必须属同一个有界、一致的快照。清单包含仍需排空的 stopped 任务,不能仅列 running;明确撤销后的任务不得被当成仍归属。全量页不完整、身份冲突、归属缺失或列表不可用时保持关闭,不能拿旧 SQLite 游标跳过全量。所有页核验完成后才应用任务归属,继续处理重启期间积压的控制;控制队列在发现失败时也不得静默停摆。
- 项目内拟定同一路径 `GET /internal/v1/dispatcher/tasks?mode=snapshot` 返回 `schema_version=task-discovery.v0.4-proposal`、`mode=snapshot`、`dispatcher_id`、UUID v4 `snapshot_id`、十进制事件 `watermark`、`tasks[]`、`next_page_token`(最后一页 `null`)。后续用 `?snapshot_id=<snapshot_id>&page_token=<token>` 取同一快照下一页;每页 ≤256、全 D 当前归属/待退役任务合计 ≤256(不能重复/跳项),各页 `snapshot_id/watermark` 不得变化;空页有非空 token 或有新 token 却零任务都按不完整失败。快照不可继续时返回 HTTP 409 + `snapshot_unavailable`,丢弃整个未提交快照并从头重取,**不**回退旧游标;page token 不受客户端解析。起始快照的水位覆盖快照生成前所有任务归属事件,不用任何旧 v0.3 SQLite 游标。
- 在线 `GET /internal/v1/dispatcher/tasks?after=<watermark-or-current_cursor>` 返回 `schema_version=task-discovery.v0.4-proposal`、`mode=changes`、`dispatcher_id`、`tasks[]` 和 `next_cursor`。非空页严格前进,空页等于本次请求游标;SaaS 保证每 D 事件连续、分页完整、有序、不得提前丢失未消费增量,无法满足即显式报错并关闭新执行、重新全量。HTTP 400 不合法请求、403 D 无归属、503 服务不可用;错误响应严格见 Schema,**不复用** v0.2 `changes[]`/410。具体身份验证仍按现有只读 HTTP 配置合同。
- **仅在本次进程运行期间**按发现水位定时查询增量,用于新增任务归属、撤销/退役和必要身份校验。水位不是最大 task_id;异常页/缺页不得推进游标或视为空变更。重启重新全量,不要求从上一次进程的永久事件游标续读;旧 v0.3 的 `after=0` 事件回放和 SQLite 持久游标不得被当作新全量响应。
- 任务列表的任务状态可以作为启动快照的初始状态及增量身份/一致性校验,**运行中 pause/resume/stop 由独立 MQ 控制队列生效**;增量页 `running` 不能自动解除暂停或不可逆停止。若列表状态与已应用的 MQ 控制矛盾,关闭该任务新接纳并报错、等待受控恢复,不按 HTTP 到达顺序偷偷切换状态。`GET /internal/v1/dispatcher/task/:task_id` 的授权配置和 resume 的新鲜状态核验仍保留,不等同于恢复“发现页控制状态”机制。
- 项目内发现字段已在 [`task-discovery-v0.4-proposal.schema.json`](../contracts/task-discovery-v0.4-proposal.schema.json) 独立严格声明,任务条目与游标等通用定义在 v0.4 Schema 内完整声明,不再依赖历史 v0.3 Schema;控制入站严格格式见 [`task-control-v0.4-proposal.schema.json`](../contracts/task-control-v0.4-proposal.schema.json)。机器 Schema 只约束消息结构;多页相同水位、完整性和快照与 MQ 积压的交接顺序须另由 Mock/代码验证。真实 SaaS 的这些字段、应用收讫、增量保留期限**仍未签收**,不能以项目内 Schema/Mock 自证兼容;不直接引用 v0.2 的 `changes`/410 或原地复用 v0.3 的严格 Schema。
## 3. 控制、通话与积压命令边界
- 新控制入站使用 `schema_version=task-control.v0.4-proposal`、原始信封 `dispatcher_id/tenant_id/tenant_key/trace_id/issued_at/command_type` 与严格 `payload={task_id,action,reason}`;**不再携带 `active_call_policy`**,逐条回执格式沿用现行 `command.result` v0.1,不能把旧 v0.1 控制请求误认为新请求。**有效 pause**:立即持久关闭该任务新接纳,停止消费任务队列并退回已交付但未接纳消息;向该任务所有已接纳且仍在途的执行发挂断。**有效 stop**:不可逆关闭新接纳,挂断全部在途执行,同时按 §1 排空未接纳积压;已接纳呼叫按原身份形成最终结果。两者不再提供 `drain` 行为;`resume` 仅在新鲜任务状态为 running 且授权有效、本地未 stopped 时恢复原任务队列,不挂断。
- 在途挂断的“已发命令”“Agent 已应用”和“实际通话终结”是三个不同事实;不因 RPC 成功伪称已终结。失败或终态未知时维持关闭、保留未知占用与可追查错误,何时回控制的 applied/failed、终结最长等待及 retry 边界须由新控制合同与 Agent 能力验证后冻结。不得因自动重投二次 originate。
- 两类 SaaS→D 入站命令 `task.control`、`call.execute` 均**不带 `not_after`,不因积压时间拒绝**。历史 pause/resume/stop 逐条按控制队列顺序处理,不合并、延迟或悄悄丢弃;stop 依 §1 排空未接纳积压并回逐条结果。新版外呼请求严格见 [`call-execute-v0.4-proposal.schema.json`](../contracts/call-execute-v0.4-proposal.schema.json),旧 v0.1 入站请求不能当作新版请求;已有出站 `command.result` 仍按其原合同校验。
- 未来 `issued_at` 的 `call.execute` **不得提前接纳**,这是时间先后校验而不是命令到期。历史外呼仍须在持久接纳及实际拨号前核对当前任务运行状态、原值号码白名单、任务及选中线路允许时段、SaaS 授权与额度、租户及供应商份额、任务与 AI 中较小通话时限;任何条件缺失、过期或不确定均拒绝新执行,不等下一窗口、不换线、不自动重拨。删除 MQ 消息期限不放宽这些独立授权期限。
## 4. Dispatcher SQLite 与日志
- SQLite 是单 D **临时可靠事务账本**,不要求多节点高可用,也不是 SaaS 的永久业务库。执行中仍需短期保存命令幂等、未知占用、执行固定快照、上传/最终结果以及未交付 outbox;文件日志只能排查,不能取代这些用于恢复与防重复拨号的事实。
- 本地只提供**显式且有条件**的已终止任务配置副本删除:仍有未知执行/额度、待上传或未发布 outbox 时拒绝;保留任务归属、执行快照、幂等命令、终结事实、上传、占用及 outbox。无自动扫描或迁移删除现有 SQLite 数据。SaaS 应用层回执/可查询恢复事实与最长重投期限尚未冻结;MQ publisher confirm **不等于** SaaS 收讫,不能据此删除依赖应用收讫的历史和防重证据。阻断原因、实际删除数量及 SQLite 错误可追查。
- 文件系统日志记录原值任务 ID、执行 ID、号码、状态、时间、错误及清理阶段;**不写入密钥、密码、私钥、完整用户音频或完整对话**。用户另提“全部内容无需脱敏”,与项目现行日志禁令冲突,不作为本版本合同已批准项。
## 5. 版本与验收边界
项目内 F07 的发现、控制与外呼严格 Schema、正反例、来源与 SHA-256 已校验;隔离 Mock C 与 TDD 回归已覆盖重启多页、积压控制/外呼、挂断失败、stop 排空、未来 `issued_at`、独立拨号门禁、条件清理及复投。已发布外部合同、真实单任务配置字段、SaaS 可恢复/应用回执与重投期限仍待 F01/F07 外部核对;`v0.3` 和 v0.1 历史证据不自动升级成 v0.4。真实 SaaS、生产、云和拨号仍须单独授权与验证。