16 KiB
go-sip:独立项目约束
宪法
-
任何涉及文件的调研或修改,如果当前是 git 仓库,需要先同步远程提交到本地,避免调研过时问题。
-
基于 TDD 进行功能的开发与业务变更,单元测试覆盖率要保证 65% 以上
-
任何时候我提出任何需求均需要理解并结构化复述后与我进行确认,避免理解偏差。
-
不要在代码里藏兜底逻辑来吞掉错误、隐藏问题。出了问题就应该让它爆出来,否则你永远找不到真实问题。
-
当一个问题出现时,不要用各种 small fix、针对性补丁来掩盖它。必须定位真实根因,彻底修复。在 bug 上糊纸只会让系统积累你不知道的危险暗病。
-
即使问题很难定位,也绝不要偷懒做表面修复。应该给项目增加充分的日志和可观测性,保证下次问题再现时你有足够信息去定位。问题无法修复时,只需要诚实告诉我信息不足、需新增日志,不要假装修好了。
-
始终注意在关键路径上给自己留足排查日志,确保每一个关键节点都是可追溯的。
-
当项目关键技术栈或产品方向发生变更时,同步更新 agents.md。文档必须随代码一起演进,不能让它变成过时的谎言。
-
大规模重构或实验性改动前,必须先切新分支。
-
不以维护向后兼容性为目标。对于已经废弃的代码路径,应直接移除,不再通过兼容层、回退机制或迁移方案予以保留。
-
在充分满足当前需求的前提下,采用尽可能简单的实现方案。避免引入缺乏实际需求依据的抽象、配置项和间接层。
-
采用渐进式、分层的方式构建系统。首先完成能够端到端运行的最小版本,再基于稳定可用的产品逐步增加功能。不要以尚未成熟的复杂性取代已经可用的产品。
-
保持组件的模块化,并明确划分不同职责与关注点。
-
当成熟且维护良好的库能够降低整体复杂度或提高可靠性时,应优先采用。除非有明确理由,不要重复实现通用功能。
-
在自行实现功能或新增依赖之前,应优先评估项目现有依赖的能力。应先查阅相关文档和类型定义,不应未经确认就认定某个库不具备所需能力。
-
架构决策应着眼于长期演进。不要采用仅能解决当前问题、且预期需要在后续替换的权宜方案。
-
在设计解决方案之前,先研究成熟产品如何解决同类问题。优先采用经过验证的模式和约定,避免从零开始另行设计一套方案。
禁止清单(不主动考虑、不主动提议、不实现,遇到只记入 TODO 技术债列表)
- 法律合规:商业库授权、开源协议合规、GDPR/个保、隐私政策(法务负责)。
- 依赖安全:NPM 及第三方包漏洞、安全补丁、依赖升级策略。
- 访问安全:服务只需支持局域网访问(host 绑定 0.0.0.0 即可),不考虑公网暴露、HTTPS、认证/权限体系(登录、RBAC)、限流、防爬、数据加密、审计日志。
红线清单(快速阶段也不能省,现在便宜、以后极贵)
- 数据模型/表结构:认真设计,建表慎重——改表成本远高于写代码。
- 目录结构与模块边界:保持简单清晰,不堆一坨代码。
- 基础错误日志:出错时至少能看到发生了什么。
- Git:小步提交,保持历史清晰。
- 基础输入校验:仅防止程序崩溃,不做安全加固。
- 环境差异配置(端口、地址等)与代码分离(.env 或配置项)。
沟通方式
-
向使用者回报时,使用清楚直白的语言说明做了什么、结果如何。最终回复禁用术语、技术实现细节与工程腔。写法是:对一个聪明但没在看代码的人解释。
-
实际执行过程(思考、规划、写程序、除错、解决问题)保持完整的技术严谨度,这条规范只适用于对使用者的沟通方式。
回复风格
- 只写结论、实际改动、原因、验证结果
- 不描述推进动作,禁用「我先……再……」等叙述句式
- 不使用工程汇报腔(「落地」「落到」「推进」等类似用语)
- 直接、专业、去表演化
- 回复文字永远使用与对方相同的语系,专有名词维持英文
- 不使用口语化表达,说重点,简单明了
- 需要时搭配条列式与表格加强输出可读性
决策规则
- 当方案有多个选项时,列出每个选项的优缺点,并明确指出推荐选项与原因,先问我。
- 有多种实现方式时,选最简单能跑通的。
- 遇到"禁止清单"中的问题:不展开、不实现,追加到 TODO 技术债列表即可。
Sub-Agent 使用时机
当任务符合以下任一条件时,直接 spawn sub-agent 分工执行,无需询问使用者:
-
任务可拆分为多个平行且无依赖的子任务
-
各子任务职责明确分离,合并执行会造成 context 混杂
-
大量结构相同的重复性任务(可用
spawn_agents_on_csvbatch 执行) -
各子任务需要不同的 model 配置或 sandbox 权限,例如:
- 探索型任务使用轻量 model +
read-onlysandbox - 审查型任务使用高推理 model +
read-onlysandbox - 修改型任务使用执行导向 model +
workspace-writesandbox
- 探索型任务使用轻量 model +
验证标准
开始任务前先定义完成标准。交付前依此验证,发现问题就修好再测,不把未完成的工作交回给使用者。只有确认完成,或遇到真正需要使用者介入的障碍时,才回报。
当前范围与权威入口
- 当前工作由使用者批准按 P01–P08 实施,K01–K16 已确认,不重复审批;本目标由当前 Agent 独立执行,不启动子 Agent。只有未来重新获得授权,才按使用者指定的
gpt-5.6-luna、max思考和fast: true逐项核验并显式配置,不静默换模型、降档或关闭 fast。 - 唯一现行 SaaS↔Dispatcher 业务说明是
docs/thirds/saas-dispatcher.md;当前项目内 Schema、拓扑、正反例及来源/hash 在contracts/local/;内部 Agent RPC 在proto/agent/agent.proto。进度与缺口见docs/plan-saas-dispatcher.md和docs/evidence/saas-dispatcher-implementation.md。文档不能代替机器合同或外部签收。 docs/plan-saas-dispatcher-v05-v0.1.md的原路径和原 SHA-256 已由contracts/local/manifest.json固定,只作不可变历史来源;旧 F/W 工作包、v0.1–v0.4 本地提案、旧 MQ-only 合同及docs/archive/不作为当前运行入口。固定 MQv1名称、HTTP/internal/v1/dispatcher/...路径和有业务意义的 revision 是通信规则,不是应删除的自有实现代次。不得为历史路径新建兼容层或配置回退。- 当前本地范围仅单节点、单 Dispatcher、单 Agent、单 Cell、单租户和隔离 Mock。根命令只接受显式
agent/dispatcher业务子命令,mixed/real 启动即拒绝;没有真实 SaaS、management、RabbitMQ、OSS、AI 供应商、Asterisk、SIP 线路、ECS 或生产签收。生产发布包仍为production_approval=false。本机 Mock HTTPS、双向 TLS、RabbitMQ 和哈希通过均不授权真实呼叫。 - 开发按 TDD 分批,小步提交;不得覆盖使用者现存修改/未跟踪文件,不自动清理、迁移或覆盖任何现存 SQLite、spool、outbox 和 Agent 恢复文件。旧
.executions及恢复根目录中旧.uploads、.upload-locks、逐执行state.json的发现须只读失败关闭,现存未交付事实由使用者确认处置。真实云账号、EIP、线路、拨号、生产部署和共享数据操作分别需要明确授权。
SaaS、Dispatcher 与 Agent 的现行边界
- SaaS→Dispatcher 的五类只读配置为
GET /internal/v1/dispatcher/sip、/task/:task_id、/tasks、/tenant/:tenant_id/quota、/ai-providers;路径前缀固定,均须校验 Dispatcher UUID/资源归属、数字tenant_id、完整快照、来源、有效授权和版本。配置读失败、过期、矛盾或不确定时关新准入;没有旧 MQ 配置回退、通用业务 HTTP、ETag 兜底或偷偷启用旧执行字段。已接纳任务持久绑定原快照。 - 呼叫、控制、必要回执和每通话唯一最终结果经固定
v1RabbitMQ Topic/队列,任务与控制队列由 SaaS 预建,Dispatcher 仅消费、不可自行建/删/绑定;结果进入指定共享 durable 队列。独立 D UUID 和接收队列不能广播后正文过滤;tenant_key原值保留,任务只能由归属 D 执行。入站先校验和持久 inbox 后 ACK,状态/outbox 同事务;persistent、mandatory、无 return、publisher confirm 成功才记交付,confirm 不是 SaaS 应用收讫。失败/确认丢失与重启只重发同身份消息,不重复拨号或捏造结果。 call.execute只带获批task_id/callee,调用线路、主叫、AI 和时限由该任务快照固定;task.control的 pause/resume/stop 无旧 CAS/版本字段,控制回 task/action/status 处理结果,stop 不可恢复。发现分页同快照先全部校验后提交,MQ 控制持久状态高于偶发 HTTP 状态;冲突关准入、resume 须重新核验。历史命令不因消息年龄过期,但实际呼出前仍检查任务/白名单/时段/授权/额度和有效通话上限;任务结束不删未确认结果、恢复、幂等或未知占用。- 独立 Dispatcher 的 SQLite 是任务、额度、inbox/outbox 的权威数据;Agent 无业务数据库,录音、执行与上传恢复只写受控私有文件。额度包含未知占用,新 boot/租约到期不得自动清除未知执行;不实现双活数据库、自动跨机热备、多 D 共享额度或第二租户公平。本轮不借本机 D1/D2 隔离夹具宣称多 D 运行。不得建立旧表/旧消息/旧 HTTP 执行兼容通道。
- Dispatcher↔Agent 复用 Unary gRPC 和受控 Endpoint;Agent 预绑定 D UUID 与服务端证书指纹,激活/会话代际、peer mTLS/SAN/SNI 和已签发期限须核对,新 boot 不清未知占用。Agent 不自行向 SaaS 取任务/AI/OSS 授权;Dispatcher 只用已经核验的 Agent
GetLoadedSIPrevision 开执行准入。本机 Mock 的加载回报不证明 Asterisk 已实际加载,SIP 配置的唯一编辑/审批面仍是 management。 - AI 使用任务内不可变授权快照:仅经获批准百炼/火山 ASR、OpenAI 兼容 LLM、火山 TTS 能表达的参数进入每通话实例;ASR-only 不启动 LLM/TTS,完整 AI 不借旧语音测试的 LLM/TTS。只有最终用户 ASR 文本的明确字面关键词可触发拒联/挂断;不由 SDK 默认值、环境、CLI、metadata 或宽松 Schema 改写业务参数,不因 SDK 重试产生第二次发起/收费或重播。日志只存脱敏版本/摘要/计数,不存密钥、prompt、完整对话或音频。
- Agent 录音经受控双向 TLS 向 D 领取短期 OSS 上传授权,每次尝试只作一次 HTTPS PUT;正常上传成功不写录音/结果业务文件。首次明确失败须先完整保存录音与结果两份恢复文件,才从该时刻启动 48 小时重试;按 1、2、4、8、16、32、60 分钟及其后每 60 分钟的固定节奏显式重新申请授权,同一 OSS 目标、同一消息身份。PUT 结果未知不得盲目重传;48 小时届满仍失败时保留文件待人工,不伪造最终结果或自动清理。D 不转发文件,已确认结束的通话及时释放执行占用;未知执行仍占用。只有真实终结后才通过唯一
call.execute.result回报录音路径、最终转写和拒联事实;无录音或录音生成失败以空recording={}和真实结果收口,生成失败须说明原因。不能恢复的录音不声称零丢失,也不伪造 OSS/SaaS 应用回执。凭据/TOKEN/签名 URL 不写入样例、日志、源码或证据。
SIP 与真实呼叫限制
| 线路 | SIP 服务端(历史登记,非已验证线路) | 主叫标识 | 被叫前缀 |
|---|---|---|---|
| 数企 | 61.132.228.221:5060 |
BD93205882 |
7089 |
| 中鼎 | 60.171.24.90:5060 |
mbkq |
无 |
| 百应 | 160.202.254.79:5060 |
KQ91526 |
mka755 |
- 全线路只允许原始号码
15003164745、15830461047,但白名单和上述登记绝非真实拨号授权。已授权的真实/旧路径仅在 Asia/Shanghai 每日09:00(含)至20:00(不含)放行,每条 trunk 对每个原始号码每天最多 3 次,窗口外直接拒绝,不等候/自动延迟/自动重试/静默换线。每次真实试拨仍须使用者明确安排并受现行程序 Mock-only 启动屏障约束;不能拿 Mock 时段测试宣称 real 放行。 - 任务按周一至周日多个时段与指定排除日期配置,线路只有每周允许时段(没有线路排除日期),Asia/Shanghai 左闭右开、跨日拆分;缺失或不确定 fail-closed,不自动重拨。由 Dispatcher 在持久接纳与实际发出指令前判定,并取任务/获批 AI 较小通话时限;Agent 仅校验会话和签发期限,不重算外呼策略。本地策略 Mock 与固定真实门禁必须分别报告。
BD等主叫原值不得清洗或当作 Digest 用户名;业务原始被叫号码不变,仅被选定数企 trunk 按规则构造7089<原号>(其它线路使用自己的前缀),不重复加前缀。三条 trunk 独立,不能把同地址伪造为备用线路或换线重拨;服务商反馈 PCMA,对应 Asteriskallow=alaw,传输/注册/鉴权/并发仍待真实签收。不以 sipgo/diago 另造 Asterisk 替代架构。
运行环境、诊断与开发门禁
- 项目是独立 Go module,工具链 Go 1.27.1;普通构建、测试、运行不读取父项目业务模块、数据库、env 或夹具。标准库和成熟官方 SDK 优先,Cobra 显式
agent/dispatcher,单制品分角色/权限/目录。禁止自行重写 SIP/ARI、RTP/RTCP/G.711、WebSocket、AMQP、SQLite 驱动、OSS 签名及 SDK 已覆盖的 AI 协议;核验现有依赖能力后再新增库。生产原生 Asterisk 仍由独立 Cell 的 systemd 统一管理,不声称当前 Mock 已完成真实媒体或 1000 路容量验收。 - ECS 优先 Debian 13(Trixie)minimal;只有阿里云北京无可用镜像时允许 Ubuntu 24.04 LTS。Asterisk 直接安装在承载 ECS 主机,由 systemd 启用自启动并核对
enabled+active;不得以前台进程或容器入口代替。 - 开发、Mock、mixed、real 的非生产主机部署与诊断步骤默认强制,不因时间/旧环境/调用方参数跳过或静默降级;显式关闭即失败。每次新主机/版本/Cell 至少留存脱敏 ECS/EIP/网络只读核验、Debian/架构/磁盘/权限、
rogeeSSH 与加固、发布包/依赖 SHA-256、Asterisk/systemdenabled+active、ARI/PJSIP endpoint/contact、媒体 profile/端口及运行版本。 - 非生产 mixed/real 呼叫必须先通过上述真实时间门禁;拨号前启动受限 SIP/RTP 抓包和 Asterisk PJSIP logger,结束后采集 SIP 响应/INVITE–BYE 时间线、SDP codec/媒体地址端口、RTP 包/字节、录音与 ASR/LLM/TTS 事实及 SHA-256。失败通话也保存状态和抓包;tcpdump/CAP_NET_RAW、PJSIP logger 或 ARI/PJSIP 状态任一不可用须失败关闭。原始抓包/日志/录音只写受限证据目录,聊天、提交与长期证据只存脱敏摘要/计数/状态码/hash,不含完整用户音频/对话或凭据。统一入口见
deploys/test/nonprod-call-evidence.sh;本地make check与make release-check-local不能代签主机诊断或生产门禁。 - 当前完成前至少检查格式、当前合同和 Proto 来源/hash、
go vet ./...、go test -race ./...、构建、确实运行的隔离 RabbitMQ/HTTPS/双向 TLS 端到端测试、业务单元覆盖率 ≥65% 及 A01–A12/K01–K16 对照。真实 SaaS/management/OSS/AI/Asterisk/ECS、第二节点/Cell/租户、多 D 额度、容量/N+1及生产切换必须另有事实与授权,任何本机 Mock 通过不得写成其签收。 - 不自动提交/暂存/清理使用者在父项目或本项目的无关修改;并行开发仍须有可追溯 Git/合同基线、一 lane 一工作区/测试资源、无交叠写集合、合并后回归。本目标明确禁用子 Agent,不能以模型、fast 环境或外部服务不可用阻塞本地 Mock 目标。问题根因不明时补可观测性并诚实报告,不能用静默兜底伪装修复。