Files
go-sip/docs/evidence/dispatcher-v04-local-acceptance.md
T

5.6 KiB
Raw Blame History

Dispatcher v0.4 项目内验收证据

**记录时间:**2026-09-27 UTC。仅限单 Dispatcher、单 Agent、单 Cell、单租户的隔离 Mock;没有真实 SaaS、OSS、ECS、供应商、生产部署或真实拨号。

合同和环境

  • Go go1.27.1 linux/amd64;分支 feat/dispatcher-state-v04。未修改 contracts/upstream/v1/,未自动暂存或提交。
  • python3 scripts/validate-local-contracts.py:v0.4 发现、控制、外呼三类 Schema,10 个正例、4 个反例、20 个带 SHA-256 的文件全部通过;内嵌 Schema 与项目内源文件逐字节一致。历史 v0.1/v0.3 校验仍通过。v0.4 是项目内提案,不是 SaaS 已签收的外部合同。
  • scripts/mq-integration-local.sh:使用本地缓存的 rabbitmq:4.1-management-alpine(镜像 ID sha256:fcc273cebb0880ec25845c9bfd97687122ac9cc391538f053cb5873f4181f35f)。Mock SaaS 预建每 D 控制队列、每任务任务队列及结果队列;Dispatcher 的 RabbitMQ configure 权限为 ^$,不能自建任务队列。仅在隔离本机 Docker 中测试,运行后临时容器已由脚本清理。

故障与恢复矩阵

场景 本地证据与结果
重启全量/多页完整性 TestRuntimeCommitsCompleteSnapshotBeforeControlAndTaskAdmission:完整页先提交,控制积压处理前准入保持关闭;TestRuntimeInterruptedSnapshotRestartsFromFirstPage:第二页故障不提交部分清单,从第一页重读。
重启不继承旧游标、在线归属变化 TestRuntimeRestartDiscardsLiveCursorAndReloadsCompleteSnapshot、TestRuntimeCatchesChangesArrivingAfterSnapshotWatermark、TestRuntimeCatchesChangeCommittedDuringSnapshotPagination:每次重启全量,运行内存水位接续,撤销不丢;Mock HTTP 实际请求 mode=snapshot 后 after=42。
状态冲突与控制积压 TestV04LiveChangesOnlyManageMembershipNotExistingStatus、TestRuntimeHTTPRunningAfterPauseNeedsMQResume、task_runtime_v04_control_test.go:HTTP 增量不代替 MQ resume,状态冲突关准入;控制先于任务消费。
历史 pause/resume/stop TestOldQueuedPauseResumeStopPreservesOrderAndEveryReceipt:一个月前发出的三条命令逐条按序应用并各有回执;TestOldQueuedStopStillHangsUpAndDrains:旧 stop 不因年龄拒绝。RabbitMQ Mock 在真实预建控制队列验证旧 stop、原消息身份重排队、stop 排空未接纳任务队列并发布回执。
挂断与确认 task_queue_v3_stop_active_test.go、task_control_v3_test.go:pause/stop 发挂断、Agent 终态未知或失败不伪报完成;resume 不挂断;stop 回执在排空后。
历史外呼、新鲜门禁、未来命令 TestAcceptLocalV01CommandPersistsReceiptAndAcceptsOldBacklog:旧外呼不因年龄拒绝;TestOldQueuedCallRejectsCurrentlyUnlistedCallee:积压一个月仍检查当前号码白名单;TestOldQueuedCallOriginationRejectsPauseAndStop、TestOldQueuedCallOriginationRechecksBoundWindowAndClaimsOnlyOnce:旧请求在拨号前仍检查最新任务控制和绑定的时间/授权截止,不二次发起;TestFutureIssuedCallExecuteNeverReservesOrDials:未来 issued_at 不提前接纳。local_origination_quota_test.go 和 dial_policy_test.go 另覆盖额度、任务/线路时间窗及较小通话时限。
结果发送、确认丢失与复投 TestLocalDispatcherMockSaaSEndToEndWithOutboxRecovery:先存事实再 ACK,结果队列不存在时 outbox 保留,恢复后原消息发出;确认只说明 RabbitMQ 接收,不等于 SaaS 已处理。
安全的 SQLite 局部清理 TestTerminalTaskCacheEvictionPreservesRecoveryAndDedupRecords:只显式删除终止任务的任务配置副本,命令重复投递继续使用原身份和回执;inbox、outbox、归属与租户绑定均保留。TestTerminalTaskCacheEvictionFailClosedWhileWorkOrDeliveryIsUnknown:未知/在途执行、额度占用、上传中和待发送结果均阻断;TestTerminalTaskCacheEvictionDatabaseFailureRetainsSnapshot:SQLite 写失败回滚。无现有数据自动扫描/删除。
历史任务增长 TestSingleTaskControlLookupUsesIndexedIdentityWithGrowingHistory:600 条归属历史,按 Dispatcher+task ID 直接查询,SQLite 查询计划使用索引而非全表扫描。

工具检查与覆盖率

bash scripts/acceptance-local.sh 已通过合同校验、格式检查、go vet ./...、go test -race ./...、go build ./... 和 RabbitMQ 隔离集成测试;额外执行 go test -cover 统计相关业务模块。覆盖率以实际执行测试集为准:

模块 覆盖率 测试集
internal/dispatcher 70.3% 隔离 RabbitMQ 集成测试
internal/store 67.6% 单元测试
internal/configread 75.9% 单元测试
internal/contract 77.4% 单元测试
contracts 100.0% 内嵌文件读写及错误路径单元测试
internal/mq 67.5% 隔离 RabbitMQ 集成测试;纯单元测试单独执行不足 65%,不能混称

不可代签的外部阻断

  1. SaaS/management 尚未提供或签收真实的 v0.4 分页快照、水位、增量保留和控制交接合同;本地 Schema 与 Mock 不证明接口真实兼容。
  2. SaaS 应用收讫、可查询恢复依据和最长命令重投期限尚未确认。本轮不删除执行身份、幂等、未知占用、上传、终结事实或 outbox;RabbitMQ publisher confirm 不能替代应用收讫。任务配置副本的局部清理仅能显式调用且全部条件通过,不能宣称数据库已整体清理。
  3. 真实供应商/OSS/ECS/生产部署与拨号、容量及切换均不在本次本地验收范围;需要独立授权和实测。