Files
go-sip/AGENTS.md
T

195 lines
36 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.
# go-sip:独立项目约束
## 宪法
- 任何涉及文件的调研或修改,如果当前是 git 仓库,需要先同步远程提交到本地,避免调研过时问题。
- 基于 TDD 进行功能的开发与业务变更,单元测试覆盖率要保证 65% 以上
- 任何时候我提出任何需求均需要理解并**结构化复述后与我进行确认,避免理解偏差**。
- 不要在代码里藏兜底逻辑来吞掉错误、隐藏问题。出了问题就应该让它爆出来,否则你永远找不到真实问题。
- 当一个问题出现时,不要用各种 small fix、针对性补丁来掩盖它。**必须定位真实根因,彻底修复**。在 bug 上糊纸只会让系统积累你不知道的危险暗病。
- 即使问题很难定位,也**绝不要偷懒做表面修复**。应该给项目增加充分的日志和可观测性,保证下次问题再现时你有足够信息去定位。问题无法修复时,只需要诚实告诉我信息不足、需新增日志,不要假装修好了。
- 始终注意在关键路径上给自己留足排查日志,确保每一个**关键节点都是可追溯**的。
- 当项目关键技术栈或产品方向发生变更时,同步更新 agents.md。文档必须随代码一起演进,不能让它变成过时的谎言。
- 大规模重构或实验性改动前,必须先切新分支。
- 不以维护向后兼容性为目标。**对于已经废弃的代码路径,应直接移除**,不再通过兼容层、回退机制或迁移方案予以保留。
- 在充分满足当前需求的前提下,采用**尽可能简单的实现方案**。避免引入缺乏实际需求依据的抽象、配置项和间接层。
- **采用渐进式、分层的方式构建系统**。首先完成能够端到端运行的最小版本,再基于稳定可用的产品逐步增加功能。不要以尚未成熟的复杂性取代已经可用的产品。
- **保持组件的模块化**,并明确划分不同职责与关注点。
- 当成熟且维护良好的库能够降低整体复杂度或提高可靠性时,应优先采用。除非有明确理由,不要重复实现通用功能。
- 在自行实现功能或新增依赖之前,应优先评估项目现有依赖的能力。应先查阅相关文档和类型定义,不应未经确认就认定某个库不具备所需能力。
- 架构决策**应着眼于长期演进**。不要采用仅能解决当前问题、且预期需要在后续替换的权宜方案。
- 在设计解决方案之前,**先研究成熟产品如何解决同类问题**。优先采用经过验证的模式和约定,避免从零开始另行设计一套方案。
## 禁止清单(不主动考虑、不主动提议、不实现,遇到只记入 TODO 技术债列表)
1. 法律合规:商业库授权、开源协议合规、GDPR/个保、隐私政策(法务负责)。
2. 依赖安全:NPM 及第三方包漏洞、安全补丁、依赖升级策略。
3. 访问安全:服务只需支持局域网访问(host 绑定 0.0.0.0 即可),不考虑公网暴露、HTTPS、认证/权限体系(登录、RBAC)、限流、防爬、数据加密、审计日志。
## 红线清单(快速阶段也不能省,现在便宜、以后极贵)
1. 数据模型/表结构:认真设计,建表慎重——改表成本远高于写代码。
2. 目录结构与模块边界:保持简单清晰,不堆一坨代码。
3. 基础错误日志:出错时至少能看到发生了什么。
4. Git:小步提交,保持历史清晰。
5. 基础输入校验:仅防止程序崩溃,不做安全加固。
6. 环境差异配置(端口、地址等)与代码分离(.env 或配置项)。
## 沟通方式
- 向使用者回报时,使用清楚直白的语言说明做了什么、结果如何。最终回复禁用术语、技术实现细节与工程腔。写法是:对一个聪明但没在看代码的人解释。
- 实际执行过程(思考、规划、写程序、除错、解决问题)保持完整的技术严谨度,这条规范只适用于对使用者的沟通方式。
## 回复风格
- 只写结论、实际改动、原因、验证结果
- 不描述推进动作,禁用「我先……再……」等叙述句式
- 不使用工程汇报腔(「落地」「落到」「推进」等类似用语)
- 直接、专业、去表演化
- 回复文字永远使用与对方相同的语系,专有名词维持英文
- 不使用口语化表达,说重点,简单明了
- 需要时搭配条列式与表格加强输出可读性
## 决策规则
- 当方案有多个选项时,列出每个选项的优缺点,并明确指出推荐选项与原因,先问我。
- 有多种实现方式时,选最简单能跑通的。
- 遇到"禁止清单"中的问题:不展开、不实现,追加到 TODO 技术债列表即可。
## Sub-Agent 使用时机
当任务符合以下任一条件时,直接 spawn sub-agent 分工执行,无需询问使用者:
- 任务可拆分为多个**平行且无依赖**的子任务
- 各子任务职责明确分离,合并执行会造成 context 混杂
- 大量结构相同的重复性任务(可用 `spawn_agents_on_csv` batch 执行)
- 各子任务需要不同的 model 配置或 sandbox 权限,例如:
- 探索型任务使用轻量 model + `read-only` sandbox
- 审查型任务使用高推理 model + `read-only` sandbox
- 修改型任务使用执行导向 model + `workspace-write` sandbox
## 验证标准
开始任务前先定义完成标准。交付前依此验证,发现问题就修好再测,不把未完成的工作交回给使用者。只有确认完成,或遇到真正需要使用者介入的障碍时,才回报。
## 当前范围
- 后续Agent必须先读 **`docs/plan-dispatcher-state-v0.1.md`** 和 **`docs/thirds/v0.4.md`**;历史 F 工作包索引见 `docs/plan-config-read-v0.1.md`:按 F 工作包/文档索引读取需求与契约,确认 C/L/M 和 I/M/G 前置、授权及写入边界后实施;并行时按该计划§9认领,子Agent只写独占模块/证据,§8本轮总台账、公共文件及合并状态由集成负责人单写。已恢复原内容的 `docs/archive/plan-0918.md` 仅保留旧 W00–W16 历史,不是现行计划入口。本地 Dispatcher v0.4 任务发现、MQ 控制及外呼入站规则另读 `docs/plan-dispatcher-state-v0.1.md`、`docs/thirds/v0.4.md`;`docs/plan-0926.md`、`docs/thirds/v0.3.md` 及 v0.2 状态仅作历史。**v0.4 的 Schema、隔离 Mock 与代码已在项目内实施,真实 SaaS/management 尚未签收或联调;仅显式条件清理已终止任务的任务配置副本,不自动清除现有 SQLite 数据。没有 SaaS 应用收讫的执行、幂等及 outbox 记录继续保留。日志不得记录密钥、完整音频或对话。** 计划不替代权威Schema或验收,不重复审批已确认方向,不自动授权真实云/付费/拨号。
- 当前MQ-only/OSS调整目标已获用户明确批准由当前Agent独立执行,**不启动子Agent**,不得再以子Agent模型/fast环境阻塞本目标;此前按任务类型自动分工规则在本目标不适用。若未来另获启动授权,仍遵守下条模型要求。
- 用户指定:若启动开发及配套审查子Agent,固定 **gpt-5.6-luna、max思考、fast模式**。启动前查询精确provider/model和runner支持并显式配置(当前工具用模型`:max`后缀及`fast: true`,不继承默认);不可用/不支持/无法核验则报告阻塞,不静默换模型、降思考档、关fast或换CLI。此为后续执行约束,本轮仅修复计划,未启动开发子Agent。
- 并行开发须先有获授权的可追溯Git/契约基线、一lane一工作区/测试资源、无交叠写集合及每批合并后回归;当前子项目尚未跟踪的文件不能假定存在于HEAD/worktree。不得自动提交、暂存或清理父项目无关改动;详情见 `docs/plan-config-read-v0.1.md` §9。
- 当前已获授权进行本项目开发:W01 项目内契约基线和 W02 Proto/stubs 已建立;仍不能把设计、Mock、Proto或88项测试清单写成真实供应商/生产验收已通过。入口和权威依据仍为 `docs/architecture/Go重写方案_v0.3.md`、`docs/acceptance/验证与切换验收_v0.3.md`、`docs/contracts/通信与事件数据交互_v0.1.md`、`docs/references/OpenAPI与MQ字段索引_v0.1.md`、`docs/dependencies/开源组件选型与复用清单_v0.2.md`。
- 开发准备见 `docs/architecture/G0开发准备与契约冻结提案_v0.1.md`:D01–D10的方案方向、双模式/许可/恢复机制及内部PoC初始profile已获用户确认;本项目已自行交付 W01/W02 开发基线,但外部权威发布、真实预算、供应商签收和 G0/PoC 仍需分别验证,不能混写为生产合同。缺失字段细节、实际预算及方案变更另行确认。本轮验收基线收敛为单节点/单 Agent/单 Cell/单租户;双节点、第二 Cell、第二租户及其公平/故障矩阵不在本轮开发或验收范围,跨 Cell/多租户能力保留为后续阶段。
- 用户已确认完整 Go Agent、分阶段替换:调度、Cell 执行、ARI/RTP/录音、AI 流及 Cell 配置接收。最终没有 Python 运行依赖;不重写 Asterisk、不实现第二套管理后台。
- 本项目已独立拆仓运营,源码、文档、依赖、配置、迁移、测试、部署、发布入口全部留在本目录。普通构建/测试/运行不读取父目录,不使用其它项目内部模块、环境文件或夹具,不共享其业务数据库。
- 当前已初始化独立 Git 仓库并绑定公开远程 `git.ipao.vip/rogee/go-sip`;未经授权不要重新 `git init`、改为 submodule、移动历史或更改父仓库跟踪关系。
## SIP 接入信息
以下为用户提供的 SIP 参数,服务商名称待补充;已记录不代表已完成真实线路验证。
| 服务商 | SIP 服务端 | 主叫号码/标识 | 被叫前缀 |
| --- | --- | --- | --- |
| 数企 | `61.132.228.221:5060` | `BD93205882` | `7089` |
| 中鼎 | `60.171.24.90:5060` | `mbkq` | 无 |
| 百应 | `160.202.254.79:5060` | `KQ91526` | `mka755` |
## SIP 全局共用定义:外呼号码白名单
- 外呼号码白名单:`15003164745`、`15830461047`。
- 所有 SIP 线路仅允许在此列表范围内发起外呼;不在列表内的号码必须拒绝。该列表仅用于已授权的 Mock/明确安排的测试;不得因写入此处而自动发起真实呼叫,原始号码保持不变。
- **现行真实/旧路径运行限制**仍为 Asia/Shanghai 每日 `09:00`(含)至 `20:00`(不含);窗口外 Dispatcher/Agent 必须 fail-closed,禁止等待、自动延迟、重试或换线。下述非生产和真实验证条款中的固定时间仍是**当前真实运行限制**。新增的 V3 执行入口只启用隔离 Mock,mixed/real 启动即拒绝;Mock 测试不能宣称 real 放行。
- **F04 项目内 Mock 已实现、外部未签收的后续目标**:仅 Dispatcher 在持久接纳与实际发出呼出指令前判断任务×已选 SIP 线路的允许时段、白名单、命令/授权/租户额度期限及任务/AI 较小通话时限;Agent 只校验会话及 Dispatcher 签发期限,不重算外呼业务策略。任务按周一至周日分别配置多个允许时段,可排除多个指定日期;线路只配置每周允许时段,**没有线路排除日期**。均按 Asia/Shanghai 判断,跨日拆分、左闭右开,任务排除日期全天拒绝;缺失/不确定时段拒绝并持久记录,不等下一窗口、不自动重试或换线。任务和线路时段**尚不能授权真实试拨**;F08 最终结果/额度收口、F09 完整验收及真实合同/部署授权分别未完成,不能据此放开固定真实门禁。
- 主叫标识保留原值(包括 `BD`),不能按纯数字手机号清洗,也不能直接当成 Digest 认证用户名;具体 From/PAI 等字段映射仍需确认。
- 业务原始被叫号码保持不变;使用该线路时按其规则构造 `7089<被叫号码>`,避免重复添加或把该前缀带到其他供应商线路。
- 传输协议、IP/Digest 鉴权、是否注册及并发限制仍需供应商确认;当前供应商已反馈需使用 PCMA,Asterisk 配置以 `allow=alaw` 表示,仍需真实线路验证。
- 每条线路目前只提供一个服务端地址,未提供独立备用地址。不能把同一地址重复填写成主备并宣称具备容灾;三条已登记线路应作为独立 trunk 配置,不为凑主备虚构供应商。
## ECS 部署环境与 Asterisk 运行约束
- ECS 部署环境固定优先使用 Debian 13(Trixie)minimal;仅当阿里云北京区域没有可用的 Debian 13 镜像时,才允许使用 Ubuntu 24.04 LTS。不得擅自切换到其他操作系统。
- Asterisk 必须直接部署在实际承载它的 ECS 主机上,由 systemd service 统一管理并启用开机自启动;部署验收必须确认 service 已 enabled 且 active,不得以手工前台进程或容器入口替代生产启动方式。
## 开发与非生产环境强制部署/诊断步骤
- 开发、Mock、mixed、real 的**非生产环境**必须默认开启环境部署与诊断步骤;这些步骤是必需的,不得因“只是开发”“环境已存在”“时间紧”或调用方参数而跳过、关闭、静默降级或默认禁用。任何显式关闭均视为配置错误,应失败并阻止验收。
- 每次新主机、新版本或新 Cell 验证至少执行并留存脱敏事实:ECS/EIP/网络资源只读核验、Debian/架构/磁盘/权限核验、`rogee` SSH 与 SSH 加固核验、发布包及依赖 SHA-256、Asterisk/systemd `enabled+active`、ARI/PJSIP endpoint/contact 状态、媒体 profile/监听端口和运行版本。
- 每次非生产 `mixed`/`real` 外呼验证,必须先通过 Asia/Shanghai `09:00`–`20:00`(左闭右开)时间门禁,再在拨号前启动受限 SIP/RTP 抓包和 Asterisk PJSIP logger,并在结束后采集 SIP 响应码、INVITE/180/183/200/4xx/5xx/BYE 或 CANCEL 时间线、SDP codec/媒体地址端口、RTP 包/字节计数、录音与 ASR/LLM/TTS 事实及 SHA-256;无拨号前抓包、状态快照或时间门禁不得宣称验证通过。失败呼叫同样必须保留状态和抓包证据,不能只报告一个 hangup cause。
- 抓包、日志、录音和识别文本只写入受限的非生产证据目录,聊天、源码、配置样例、提交和长期证据不得保存密钥、完整用户音频或完整用户对话;交付证据默认保存脱敏摘要、计数、状态码和哈希。若 tcpdump/CAP_NET_RAW、PJSIP logger、ARI/PJSIP 状态采集任一不可用,必须 fail-closed 报告阻塞,不得静默改成无抓包流程。
- 上述步骤由统一部署/验收入口自动执行;`mock`、`mixed`、`real` 只替换适配器,不能绕开同一套部署、诊断、状态和证据门禁。生产环境仍须另行授权和通过生产安全屏障,非生产默认强制开启不等于生产放行。
## 本次上线目标与分期(用户已确认)
- P1以稳定快速内测上线为目标:1个节点、1个Agent、1套Asterisk、1个单活Dispatcher/SQLite、1个启用租户;本轮不开发、不验收双节点、第二 Cell/第二 Asterisk或第二租户。用户已确认后续多 Dispatcher 目标为每 D 独立 ID/接收队列、独占 Agent/Asterisk 执行资源;同一租户可有多任务,但每个任务只能有一个 D 归属,SaaS 持久绑定租户+任务→D,呼叫/控制不得分发到其它 D,不能暗中迁移。单任务并发可由归属 D 本地判断;跨 D 租户/供应商总上限仍须先冻结有界额度份额,不能各 D 各按全局上限放行。本轮不把 D1/D2 隔离 fixture 冒充多 D 业务运行。
- 至少3家独立SIP trunk 的静态配置、路由/主叫/前缀/codec/额度约束和协议 Mock/mixed 覆盖仍需保持;真实供应商外呼和 ECS 仅作为第二阶段联调,不是本轮前置。
- ASR-only和ASR+LLM+TTS均按批准的不可变AI配置在本地/隔离链路验收;不擅自加MQ模式字段,不复用旧LLM/TTS。真实供应商未联调时必须明确标记为第二阶段,不能把 Mock 写成真实供应商通过。
- P1使用管理平台批准的静态单 Cell 快照和受控维护窗口,不做在线发布/回滚编排;静态配置必须关准入、排空、核验实际加载,旧直写通道不得并行。
- P1保留 tenant_key 原值、租户独立队列、复合幂等键、有界窗口及单租户配额/控制边界;不开发或验收双租户公平、第二 Cell 汇总配额和多实例协调。
- 本阶段上传按固定15分钟授权、单次PUT、原事实持久化及recording.uploaded可靠入队进行本地隔离验收;不申请SaaS上传会话、不等待complete/verified或OSS ID。RabbitMQ ACL/TLS和application receipt仅按适用版本化契约/隔离测试验证,不将通知入队称为SaaS已处理;真实SaaS/MQ联调延期第二阶段。
- 88项验收为跨阶段基线,当前只签收单节点/单 Cell/单租户适用子场景;双节点、第二 Cell、第二租户、真实 ECS/生产联调、容量/N+1及切换均不作为本轮门禁。
## 语言与工程
- 工具链基线为 Go 1.27.1。实施时锁定 CI/构建镜像和依赖,并校验实际工具链;不得自动修改其它项目的 Go 基线。
- 标准库优先、单Go module/二进制,用Cobra显式提供agent、dispatcher两个业务子命令,无默认双角色启动;同一制品分进程/权限/目录,升级受版本兼容和排空约束,不另造CLI框架。
- JSON v2、UUID 和新测试 API 的采用以契约兼容和实测为前提;既有标识、哈希规范不得随 API 更换。实验性 SIMD 不在当前范围。
- 用户已确认不接PG:独立Dispatcher持有SQLite权威任务/配额/outbox,Agent无业务DB,文本/录音及执行/上传恢复信息落文件。禁止NFS共享SQLite/两份DB双活发额度,自动跨机热备不在已实现承诺内。
- 已确认Unary gRPC,Dispatcher预配置Agent Endpoint;Agent业务只需D Endpoint,证书/监听/ARI/持久目录由部署提供。SDK复用连接,不增内部MQ或双向流,不因RPC超时重拨。
- 所有Agent共用mTLS证书,D身份独立;必须通过受控Endpoint主动激活/节点会话授权,不信自报身份/地址。共享私钥泄露影响整组,轮换/撤销和风险要签收,不关闭SAN/SNI校验。
- D感知健康/负载/软件协议/能力及供应商applied配置版本;样本过期/缺失为unknown,低CPU不突破租户/供应商/Cell/AI配额,新boot不清旧未知占用。
- 实施后至少执行本模块的格式化检查、`go vet ./...`、`go test -race ./...` 和构建;当前代码已有 W01/W02/本地 RPC/AI Mock 入口,真实 DB/MQ、媒体、供应商、容量及切换验收仍分别报告,不能用本地通过记录代签。
## 开源复用硬约束(用户已确认)
- SIP 及其它组件有适用开源库/官方 SDK 必须复用,禁止从零手写替代协议栈或客户端。优先标准库、Asterisk 原生能力、现成 SDK;自有代码限业务状态机、事务、权限、配额和薄适配。
- 不自写 SIP/ARI、RTP/RTCP 编解包、G.711、WS/AMQP/数据库驱动、OSS 签名、已有 SDK 覆盖的 AI 协议或 Schema 解析。库不满足先选替代、修上游或报告阻塞;例外须用户另行批准。
- 采用前核验 module/tag/commit、Go1.27.1、许可证/NOTICE、传递依赖/漏洞及真实协议兼容,留存 PoC;不得将 main README、未归档或可下载等同于生产通过。
- SDK 自动重试不得造成二次 originate、旧音频重播或重复收费;不因 SIP 库存在而用 sipgo/diago 替换已选定 Asterisk 架构。
## AI配置与参数(用户已确认)
- P1采用百炼/火山ASR、OpenAI兼容LLM、火山TTS;SDK首选及未通过门禁见组件清单§1.3/§4.3。基础栈方向确定不等于精确版本、许可证或参数能力已验收;不为补字段改为自写协议。
- **现行合同(尚未切换)**:Dispatcher按MQ任务agent_version_id,经RabbitMQ专用Topic向SaaS取得不可变AI配置/授权,响应回原Dispatcher;校验租户/源Schema/不可变摘要/能力并持久绑定后向Agent交付执行快照。过去已废弃的独立AI版本GET不复活;新获批准的方向是**任务配置只读接口内含智能体**,须另冻合同而非旧GET兼容层。Agent不直连SaaS,不从CLI/env/源码常量或SDK默认覆盖AI业务值,不新增任务MQ模式字段或调参后台。
- 已有model/prompt/voice/speed/ASR输入与识别/temperature/max_tokens/timeout及对话控制必须实际传入SDK或控制器;热词/VAD/top_p/音量/阶段时限等所需扩展先在上游补GAP-09,再生成校验。严格additionalProperties不放宽,不借metadata/raw_request透传。
- **现行 AI 合同**:SaaS新版本供新任务引用,无需改代码/重启D/A;在途/原排队任务固定快照,同版本异内容拒绝。缓存按租户+版本隔离,断SaaS无有效授权缓存拒新准入;显式0/false与未提供保真,并发通话不得共享可变SDK参数。
- **项目内配置与执行(已发布外部 v1 不变)**:项目内 v0.4 任务发现、控制及外呼入站依据 `docs/thirds/v0.4.md`;其它必要边界见 `docs/thirds/第三方对接事件与请求消费顺序_v0.1.md`。拟定 SaaS 只读路径为 `/internal/v1/dispatcher/sip`、`/internal/v1/dispatcher/task/:task_id`、`/internal/v1/dispatcher/tasks` 和 `/internal/v1/dispatcher/tenant/:tenant_id/quota`;均为项目内字段/路径,实际 SaaS 兼容性未验证。D 用 `X-DISPATCHER-id`/`X-DISPATCHER-SECRET-KEY` 按需读取,不在源码、配置样例或日志暴露凭据。SIP 启动先取获批全量并核验 Agent/Asterisk 加载后才准入;任务按租户+任务缓存约 60 秒,到期重新读取完整 200,无 ETag、过期缓存或 MQ 配置回退;已接纳执行固定原快照,暂停/停止控制不等待缓存。项目内 v0.4 `call.execute` 入站只有 `task_id/callee`,调用路由、主叫、AI 和时限绑定已授权任务快照;历史 MQ 命令不因年龄过期,但拨号前门禁不放宽。任务终止仅允许**显式、条件式**清理任务配置副本,不删执行恢复、幂等或 outbox。SIP 改动须关准入、排空及核验实际加载;外部 opt-out 现行 MQ 即时语义不可擅自改称已切换为最终 `call.result`。F01/F07 本地 Schema、正反例、来源/hash 与 Mock C 已通过,外部签收/连通仍未验证。
- 凭据/供应商端点来自受控引用且有授权校验;不再定义独立出口池标识或出口池授权名单,Dispatcher 仍校验任务允许线路、全局号码白名单、时段和额度,不能因可调参数绕过安全硬限额或启用不安全重试。OpenAI默认自动重试显式关闭;日志只留脱敏版本/摘要/有效参数,不打印prompt/变量/密钥。
- 静态发布只约束SIP/节点制品,不将AI配置硬编码;GAP-08/09及SDK参数PoC为P1门禁,验证入口见验收§5.1(现有E/L项子场景,不新增虚假通过数)。
## 契约与可靠性
- 本项目设计/运行/验收文档只在自身 `docs/` 维护。上游共享接口有唯一权威来源;导入带版本、来源和哈希的不可变契约包,再生成类型/校验,不维护重复手写 Schema。
- 新内部消息/许可/fencing 协议需先获批;不擅自改变 SaaS 路径、字段、状态、路由或控制语义。
- **现行已发布合同(新版本生效前必须遵守)**:SaaS↔Dispatcher的全部交互唯一经RabbitMQ专用Topic订阅,双方无HTTP请求/回调/兼容通道或故障回退,包括执行、控制、查询、整体补传、AI配置/授权及recording.uploaded上传事实通知;上传不申请SaaS会话或等待verified/OSS ID回复。OSS配置/TOKEN不来自SaaS:Agent领取及显式重申请TOKEN只经D↔A Unary;本规则不禁止Agent→OSS、ARI、AI供应商HTTP(S)或gRPC的HTTP/2。
- **本轮项目内目标(尚未替换真实外部运行)**:任务(含智能体)、SIP、任务发现和按 tenant_id 的租户额度走四条只读 HTTP;呼叫、控制及其必要回执/单份最终结果走 MQ,取消对外业务查询/补传和分散通话事件。不提供配置HTTP→MQ回退,也不恢复其它业务HTTP通道。SaaS须分发 management 已批准的唯一 SIP 版本,management 仍为唯一编辑/审批面。该本地语义按第三方契约及版本化 Schema/示例/hash 冻结,Mock C 是本地门禁,不等待外部签收;真实切换仍需另行授权。
- 新HTTP配置字段项目内 SIP 新版见 `docs/contracts/config-read-fields-v0.3-proposal.md`、`config-read-v0.3.schema.json`/mock示例;AI 授权和静态 Cell 制品的项目内新版见同一提案;旧 v1/v0.2 保留历史,不作为当前运行契约;任务/额度仍参照 v0.1;截图只证实UI含义,英文响应键为项目自定义,绝非SaaS现网接口已确认字段。用户新增任务排除日期、线路时段等未见截图项按项目需求设计;SIP传输/鉴权/注册及额度未知不能猜默认值。Schema/Mock 校验可满足项目内 C,但不代表 SaaS/management 已发布或真实兼容;真实响应、审批来源和 Agent/Asterisk 实际加载仍须单独验证。当前唯一权威运行契约不因草案变化。
- **每个Dispatcher必须有独立、全局唯一且不重复的ID及独立接收Topic/队列**;指定D的任务/现行MQ配置结果/上传结果不能由其它D抢收,也不能广播后仅靠正文过滤;新目标只读HTTP配置由该D UUID+SECRETKEY获取且须核对任务归属。身份与tenant/Agent/Cell ID、dispatcher_epoch分开;现行合同保留租户独立队列及原值tenant_key,完整新路由长度预算须重验。具体ID生成/持久化、Topic/绑定、消息字段/关联/错误/期限须随W01新版本冻结,不凭本文给旧严格Schema添加字段。
- **v0.4 任务发现与队列所有权硬边界**:SaaS 独占创建、维护、退役每 D 的独立控制队列与每任务任务队列及绑定;Dispatcher 仅消费,不能自行建队、绑定或删除。本地 RabbitMQ 无 `configure` 权限 Mock 已通过,真实兼容性未验证。新加入或重启 D 先 `GET /internal/v1/dispatcher/tasks?mode=snapshot` 逐页取得同一 `snapshot_id`/`watermark` 的完整清单,全部校验后一次 SQLite 事务提交;独立控制队列积压处理完成前不开任务准入。运行期 `GET .../tasks?after=<内存游标>` 仅发现归属变更,每页持久提交后推进内存游标;重启不恢复旧 v0.3 持久事件游标,分页或持久化失败关新准入、停任务消费,MQ 控制及结果恢复照常处理。HTTP 的偶发状态与 MQ 已应用状态冲突则关准入,不让发现页覆盖已持久的 pause/stop;只有 MQ resume 经单任务新鲜状态确认才恢复原积压。stop 挂断、排空后回自身控制回执,未接纳旧外呼静默 ACK、不拨号、不回逐条结果,也不删 SaaS 任务队列。历史 `task.control` 与 `call.execute` 不因消息年龄过期,外呼仍在接纳和拨号前独立检查任务/白名单/时段/授权/额度及通话时限,未来 `issued_at` 不提前接纳。保留原值 tenant_key、租户额度和未知占用;跨 D 份额仍待外部冻结。v0.1–v0.3 发现证据仅作历史,v0.4 本地证据见 `docs/evidence/dispatcher-v04-local-acceptance.md`;不能证明真实 SaaS/management、多 D 或生产可用。
- **OSS相关配置存于Dispatcher配置文件,Agent向Dispatcher领取临时上传TOKEN后直传OSS,不保存长期凭据;SaaS不再下发OSS配置/TOKEN。** D复用官方SDK提供受限TOKEN/目标信息,配置缺失/无效明确失败;不在样例、源码、日志或证据中保存实际密钥/完整TOKEN。过期只允许A显式向D重新申请,不自动续期或向SaaS申请TOKEN;精确配置格式/TOKEN形态/UploadGrant映射另行核验,不猜字段。
- **本轮项目内目标:上传仅负责 Agent 直传及 D 可靠通知 MQ,SaaS 后续处理不属本项目职责;外部 v2 的现行上传事实不因本地目标自动改变。** D保留签发能力、不转发文件;R13持久保存事实与recording.uploaded outbox,消息为persistent、进入指定durable队列/绑定、mandatory无return且publisher confirm成功后才记交付完成。只写本地outbox不算入队;不申请SaaS会话、不等待verified/OSS ID、不新增VERIFYING、不伪造SaaS结果。
- 新版recording.uploaded取代本项目recording.ready,字段为call_id/recording_id/upload_id/bucket/object_key/format/channels/sample_rate_hz/duration_ms/size_bytes/checksum_sha256;不含TOKEN/密钥/签名URL。MQ失败/确认丢失/重启只恢复原消息身份的交付,不重新PUT或新建资产。现行AI/控制等必要请求响应不受此收缩影响;新目标AI改用任务只读HTTP获取,控制仍走MQ。
- 前一轮MQ-only文档纠正已结束;以下是**现行 MQ-only v1 合同的历史基线**,不得误当作新只读配置HTTP方案的限制或验收通过:现行机器依据见 `contracts/upstream/v1/mq-topology.json`、`mq.schema.json` 和 `event-payloads.schema.json`,第三方顺序说明见 `docs/thirds/第三方对接事件与请求消费顺序_v0.1.md`:纯Topic精确绑定、拒绝独立通配词段、tenant_key预算196 UTF-8字节、稳定UUID v4、旧版严格JSON配置及15分钟SDK预签名PUT;新目标保留业务MQ及OSS规则,仅替换配置获取,须另发版本化合同,不原地复用旧Schema。当前仅保留现有代码需要的契约包;未发生契约迁移前不新增契约,旧快照不作为当前工作树输入。新版须完成Schema/正反例/哈希验证后发布,不把方案确认当实现完成。历史 W01/W02/W04/W05/W07/W08/W11/W12/W13/W14 范围见归档 `docs/archive/plan-0918.md` §8.2;项目内 v0.4 配置/控制路径以 `docs/plan-dispatcher-state-v0.1.md` 和本地验收证据为当前入口;外部合同另行签收。全局唯一D身份/专用Topic及本地D1/D2隔离fixture为当前合同要求,不授权双D业务运行、HA或共享额度。
- **现行已发布合同**中的实时文字事件名为transcript.updated,不新增call.transcript别名;OSS文本归档不能冒充当前实时文字/opt-out,缺少专用资产授权接口时明确未启用,不能伪装recording.ready。
- **用户已批准的项目内精简契约目标**见 `docs/plan-config-read-v0.1.md` §3.5/§4 和第三方对接契约:SaaS↔D 移除对外查询/补传命令及分散通话/转写/拒联/录音事件,保留呼叫/控制命令和必要回执;录音仍上传 OSS,D 每通话只回传一份含最终转写、拒联事实与 OSS 路径的 `call.result`。本地实现以 F01/F07 Schema、正反例、来源/hash 和 Mock C 为门禁,无需额外外部/业务签收;本地验收更新后不要求通话前实时文字或拒联。无录音按 `not_created` 收口;预期录音明确失败立即 `unavailable`,未知最迟于 `call.ended_at + 15m` 收口。通话确认终结释放执行资源后释放占用,不等待 OSS 或 MQ confirm;未知仍占用。现行外部 Schema/代码保持原样,真实兼容性未验证。
- 现有MQ信封command_type/command_id、event_type/aggregate_*与正文已对齐;事件payload专属约束尚需补齐,不把通用object校验当完整验收。字段索引只读生成,不手改成第二套Schema。
- `tenant_key` 原值一对一绑定,不清洗、编码或截断;旧布局224个UTF-8字节预算不能在加入D身份后直接照搬,W01须冻结并验证完整routing key/queue预算及分隔符/通配符边界;超限停止发布并保留源任务。
- 持久 inbox 后 ACK;状态与 outbox 同事务;confirm 不等于 SaaS 应用收讫。重复投递、未知执行和恢复不能触发重复拨号。
- 配额覆盖所有 Cell/实例及未知占用;租约过期不自动释放不明通话。**现行 v2** 控制 CAS 为 expected_task_revision,pause 与 stop 的 drain/hangup 区分;paused 可按新授权恢复,stopped 不可恢复。现行整体补传仅 call_id/source_command_id;下一版对外查询/补传目标取消但严格合同/代码未改。最后发起许可、权限和屏障须故障注入。
- **用户已批准的项目内精简契约目标(不能混写现行 v2;外部签收不阻塞本地 C)**:`call.execute.payload` 仅 `task_id/callee`,外呼信封身份仍用于防止重拨;路由/主叫/智能体版本与 `ring_timeout_ms/max_call_duration_ms` 均从已批准的任务配置取得并持久绑定。`task.control` 的 pause/resume/stop 均不带 `command_id` 或 `expected_task_revision`,不设计控制去重,但 D 必须回 task/action/status 处理结果;乱序、控制重投/回执丢失与 stop 后 resume 的本地判定写入第三方契约并由 Mock 测试;外部签收不是本地阻塞项,不偷偷重引入 CAS/去重掩盖。任务配置新增明确 `caller_profile_id`,按allowed_trunk_ids顺序选首个时段/额度/加载/主叫均匹配的线路,选后固定、不自动换线重拨;有效通话上限取任务与已授权AI两者较小值。旧running配置/发现不得解除已持久的paused/stopped,resume须强制最新任务核验,stopped同ID不可逆。拟定配置响应不再包含 `agent.content_sha256`;录音 checksum 另有用途,不误删;SIP SaaS 响应不再提供 snapshot_sha256 或静态制品。参见 `docs/plan-config-read-v0.1.md` 和 `docs/thirds/第三方对接事件与请求消费顺序_v0.1.md`。
- management是SIP配置唯一编辑/审批面。**现行 P1**通过批准的版本化静态制品和受控部署入口交付,D核验目标/准入屏障,Agent加载并报告;不要求在线发布控制面。静态交接合同须批准,旧直接写Agent面不能同时启用;成功必须证明精确快照已被Asterisk加载。
- **本轮项目内 SIP 配置读取目标(现行外部运行未切换)**:management 仍是 SIP 唯一编辑/审批方,SaaS 仅经只读 HTTP 提供该 D 资源分区的获批全量快照;新加入/重启 D 先查询、核验所属 Agent/Asterisk 实际加载的 SIP 线路 revision 后才消费执行队列;Agent/Asterisk 的部署配置由受控部署确定,不来自 SaaS。后续约每60秒核对版本,有变化就关执行准入、排空旧活动通话并确认新版已加载;控制MQ照常处理。SaaS/management 分属不同配置系统时须证明SaaS分发的是同一份获批线路配置版本;不引入共享业务DB或MQ配置回退。项目内 SIP 读取及准入链路已用隔离 Mock 验证;真实 Agent/Asterisk 加载与 SaaS/management 切换尚未验证。真实 SaaS/management 兼容性及多 D 资源配额份额仍未验证、不属本轮验收,详见 `docs/architecture/Dispatcher有界接纳与控制通道改造计划_v0.1.md` §3.2。
## 安全和真实验证
- mock/mixed/real 明确隔离;Mock 默认隔离真实外网,正式模式拒绝 Mock/测试凭据,不静默回退。
- 只允许复用既有 ASR 协议;禁止复用 `voice_test` 的 LLM/TTS。P1必须完成新LLM/TTS规范、SDK适配和本地/协议隔离验收;真实供应商联调延期第二阶段,不能以Mock冒充真实供应商通过,也不能把真实联调延期误写成当前 P1 已实测。
- 真实外呼只允许原始号码 `15003164745`、`15830461047`,但白名单和文档不是拨号授权;每次真实验证仍需明确安排,且仅可在 Asia/Shanghai `09:00`–`20:00`(左闭右开)执行。每条 SIP trunk 对每个原始手机号每天最多 3 次;某条线路失败时可在额度内经当前会话确认后改测另一条线路,但不得在窗口外等待、自动延迟、在同一条线路/号码上超额、自动重试或静默换线。
- 不把 SIP 白名单出口 IP 当作 SIP 服务端,不虚构备用线路,不逐呼重写共享配置,不自动重拨已接通/未知的执行。
- 生产使用多机器、多 EIP 直连;1000 路指完整 ASR/LLM/TTS 已接通通话,N+1 与供应商能力须实测,不采用单 EIP+NAT。
- 独立开发和测试不要求云账号。云创建、EIP 改绑、网络放行、供应商消费和测试资源清理必须另获明确授权;不得触碰无关资源。
- 不在源码、配置样例、文档、日志或证据中保存密钥、密码、私钥、完整用户音频/对话;注入受控凭据,诊断端点仅管理网可达。
- 旧 Python 与新 Go 不得同时写同一资源或各自发放共享额度。没有可验证的所有权/状态回迁方案就暂停切换,不以回滚镜像冒险重拨。