Document v0.3 Mock acceptance and enforce local release gates

This commit is contained in:
2026-09-26 21:37:44 +08:00
parent 210c728de8
commit a687351f25
10 changed files with 146 additions and 36 deletions
+4 -4
View File
@@ -4,11 +4,11 @@
## 首读顺序
1. [`plan-config-read-v0.1.md`](plan-config-read-v0.1.md):本轮两只读配置接口、有界消费及外呼时段的 F00–F06 执行入口、C/L/M 和 I/M/G 门禁。原 [`plan-0918.md`](archive/plan-0918.md) 已按 HEAD 原文归档,仅作旧 W00–W16 历史。
1. [`plan-config-read-v0.1.md`](plan-config-read-v0.1.md):四条只读接口、任务发现、有界消费及外呼时段的 F00–F09/F06 执行入口、C/L/M 和 I/M/G 门禁;任务发现 v0.3 另读 [`plan-0926.md`](plan-0926.md)。原 [`plan-0918.md`](archive/plan-0918.md) 按 HEAD 原文归档,仅作旧 W00–W16 历史。
2. [`architecture/Go重写方案_v0.3.md`](architecture/Go重写方案_v0.3.md):单节点、单 Cell、单租户的总体方案与分期。
3. [`contracts/`](contracts/):SaaS、Dispatcher、Agent、RabbitMQ 和 OSS 的项目内契约。
4. [`acceptance/验证与切换验收_v0.3.md`](acceptance/验证与切换验收_v0.3.md):验收门禁、证据要求和第二阶段边界。
5. [`evidence/20260922-mq-only-local-final.md`](evidence/20260922-mq-only-local-final.md):当前 MQ-only 本地/隔离范围的最新汇总证据。
5. [`evidence/f09-local-acceptance-v0.3.md`](evidence/f09-local-acceptance-v0.3.md) 和 [`evidence/f06-local-release-gates-v0.3.md`](evidence/f06-local-release-gates-v0.3.md):任务发现当前项目内 Mock 与发布阻断证据;[`20260922-mq-only-local-final.md`](evidence/20260922-mq-only-local-final.md) 仅作旧 MQ-only 本地基线。
## 按职责查找
@@ -23,7 +23,7 @@
### 契约与决策
- [`thirds/第三方对接事件与请求消费顺序_v0.1.md`](thirds/第三方对接事件与请求消费顺序_v0.1.md):只描述 SaaS↔Dispatcher 的配置读取、现行 MQ 呼叫/控制命令及回执、拟定单份最终通话结果;取消对外查询/补传和分散事件尚待签收,替代已删除的六份分散说明。
- [`thirds/第三方对接事件与请求消费顺序_v0.1.md`](thirds/第三方对接事件与请求消费顺序_v0.1.md):SaaS↔Dispatcher 的项目内配置与 MQ 业务契约;仅其中旧 §2.5 任务发现已由 [`thirds/v0.3.md`](thirds/v0.3.md) 项目内合同替换,[`v0.2`](thirds/v0.2.md) 为历史。取消对外查询/补传及分散事件仍待外部签收。
- [`../contracts/upstream/v1/mq.schema.json`](../contracts/upstream/v1/mq.schema.json)、[`event-payloads.schema.json`](../contracts/upstream/v1/event-payloads.schema.json)、[`mq-topology.json`](../contracts/upstream/v1/mq-topology.json):现行 MQ 信封、事件正文、路由的机器契约。
- [`contracts/config-read-fields-v0.1-proposal.md`](contracts/config-read-fields-v0.1-proposal.md):两只读接口字段来源、响应结构与项目自拟 Schema/Mock 示例;**不是现网 SaaS JSON 或正式合同**。
- [`decisions/`](decisions/):已记录的关键技术决策。
@@ -44,4 +44,4 @@
- 不在 `docs/` 复制上游 Schema;上游契约包、生成物和字段索引保持单一来源。
- 不把证据摘要改写成新的通过结论;范围、环境和未执行项必须保持可追溯。
- 新增文档先归入方案、契约、决策、证据或归档中的一个明确类别;本轮根目录的 `plan-config-read-v0.1.md` 是单一执行入口,不新增其它无类别根文件。
- 新增文档先归入方案、契约、决策、证据或归档中的一个明确类别;根目录 `plan-config-read-v0.1.md` 是总执行入口,用户指定的 `plan-0926.md` 仅说明 v0.3 任务发现分项,不另设第二个总台账;不新增无类别根文件。
@@ -0,0 +1,17 @@
# F06 P1 本地发布阻断:任务发现 v0.3
范围:单 Dispatcher/Agent/Cell/租户的项目内隔离 Mock;仅构建和检查临时制品,**未安装、部署、连接真实 SaaS/OSS/SIP、拨号或切换生产**。以前的 [`v0.2 本地制品记录`](f06-local-release-gates-v0.2.md) 仅作历史,不代替本次核验。
## 本地制品与合同
- `make release-check-local`:通过;从 Go 1.27.1 的独立项目构建一次性二进制及归档包,检查已存在 release/package 目录、压缩包或校验文件时均拒绝覆盖;校验二进制、归档、checksum/manifest。临时 release SHA-256:`243387b2441d0f88a156e955b821532c6f4246d98669ccbb9a3d91ddb4b2c0ea`。临时文件随测试删除,不冒充已发布制品。
- `scripts/build-release.sh` 的 `contract_attestation` 和本地制品检查一致:其他项目内业务协议 `local-contract-manifest.v0.1`,**任务发现 `local-contract-manifest.v0.3`**,MQ 拓扑 `project-saas-dispatcher.v0.1`(v3 队列草案),以及当前 Proto manifest。v0.3 的版本化来源为 [`docs/thirds/v0.3.md`](../thirds/v0.3.md),来源 SHA-256 `2fa8f5a10b1509044b04b4416a44496c5e9a2d9c741e5437862e2edcb92649ce`;[`local-contract-manifest-v0.3.json`](../contracts/local-contract-manifest-v0.3.json) SHA-256 `436de2fe5314deb6a2b773f0217b72c61140db4195f68dcb2f9adb5290b93286`。旧 v0.2 Schema/清单保留追溯但不进入当前运行制品的发现 attestation。
- `scripts/check-contracts.sh` 验证 v0.3 严格 Schema、8 个正例、2 个反例与 13 个来源/产物摘要;旧上游 `contracts/upstream/v1/` 没有更改。`./scripts/acceptance-local.sh`(含格式、`go test -race ./...`、`go vet ./...`、构建及受限 RabbitMQ)通过,具体矩阵与覆盖率见 [`f09-local-acceptance-v0.3.md`](f09-local-acceptance-v0.3.md)。
- 制品已直接启动测试 `dispatcher` 的 `mixed` 和 `real` 两种模式:均返回隔离 Mock 限制错误,在创建 SQLite 文件前拒绝;旧 `--tenant-key`、`--consume` 开关不在制品中。隔离 RabbitMQ 测试账号无 `configure` 权限,Dispatcher 不建队或绑定,真实模式没有因 v0.3 合同放行。
- 本地构建来源有未提交变更,制品仅标记 `local-development`、`production_approval=false`;Go/Proto/合同摘要可核对不等于发布、运行环境或真实配置已验收。
## 保持阻断的真实事项
1. SaaS/management 尚未签收 v0.3 精确响应、每页完整有序及无游标过期保证;响应仅有页级 `next_cursor`、无逐项 `event_id`,Dispatcher **不能独立证明页内未漏项**。撤销墓碑长期保留的容量、灾备后序号连续性和长期旧游标可读性没有外部验收,活动任务 256 上限不能代替累计墓碑预算。
2. 旧 v0.2 checkpoint 无法直接解释为 v0.3 事件序号。当前代码会拒绝静默迁移;任何真实旧队列/在途执行的排空、状态回迁及资源所有权移交都须另有获批且可核验的方案,不删旧任务、执行事实、幂等与 outbox,也不并行运行两套消费者。
3. 真实 SaaS/MQ/OSS、供应商与 Asterisk/ECS/systemd 部署、媒体/线路拨号、容量、生产准入/回滚/切换均未执行或未授权。本地 Mock 的成功与版本/hash 匹配不构成这些事项的通过记录;生产安全屏障仍须单独满足。
@@ -0,0 +1,27 @@
# F09 P1 本地 Mock 验收:任务发现 v0.3
仅验收单节点、单 Dispatcher、单 Agent、单 Cell、单租户的隔离 Mock。任务发现采用项目内拟定 `docs/thirds/v0.3.md`,其余 SaaS 项目内业务协议仍为 v0.1;`contracts/upstream/v1/` 未修改。下述结果不是 SaaS/management 或生产验收。
## 适用矩阵
| 场景 | 本地事实与测试 |
| --- | --- |
| 同一合同及分页 | 首次与后续均读取 `tasks[]`,`after` 是规范十进制事件游标;首次多页、空页保持游标、同任务后续更新、`removed` 墓碑均通过。响应不含逐项 `event_id`;请求中的 `page_token`、旧 `changes`/410 路径不运行,也无 HTTP→MQ 回退。见 `internal/configread/discovery_v03_test.go`、`internal/dispatcher/task_runtime_v03_test.go`。 |
| 并发翻页、页中断与重启 | Mock 在翻页时加入同任务更新事件,D 追至最终空页并应用较新状态;第二页 HTTP 失败时仅持久保存首个成功页,关新准入;关闭并重新打开 SQLite 后从已提交的游标续读,不从零重建,也不跳过页。见 `internal/dispatcher/task_runtime_v03_recovery_test.go`、`task_runtime_v03_test.go`。 |
| 故障与事务 | 非规范/倒退游标、异常响应及 HTTP 410 均报错,不伪造空页;发现服务中断时停止旧任务消费者但保留 MQ 控制。SQLite 触发器模拟分配写失败后,任务、游标和响应证据全部回滚;未物理填满磁盘。v0.2 checkpoint 无法直接当事件 ID 使用,阻断静默切换。见 `internal/configread/discovery_v03_test.go`、`internal/store/local_v03_discovery_test.go`、`local_v03_failure_test.go`、`internal/dispatcher/task_runtime_v3_test.go`。 |
| 控制与重复投递 | 发现页中的 `running` 不解除 MQ pause/stop 或已撤销墓碑;pause 保留积压、stop 对未接纳命令静默 ACK,在途终结仍出最终结果。重复执行恢复原回执,持久一次性拨号决定不产生第二次呼叫。见 `internal/store/local_v03_failure_test.go`、`execute_business_duplicate_test.go`、`local_origination_test.go`、`internal/dispatcher/task_control_v3_test.go`、`task_queue_v3_stop_active_test.go`。 |
| SaaS 建队与 MQ/最终结果 | 受限 Dispatcher RabbitMQ 用户的 `configure` 权限为空,只消费 SaaS Mock 预建任务/控制队列;队列缺失或满、确认丢失与重投不冒充已接纳。HTTP→SQLite→MQ→Mock 最终结果与 outbox 恢复集成通过。见 `internal/mq/amqp_v3_integration_test.go`、`amqp_v3_queue_full_integration_test.go`、`internal/dispatcher/local_v01_integration_test.go`。 |
| 既有门禁 | 号码白名单、时段、配额、超时、录音结果与最后拨号判断继续使用 F04/F08 本地测试;V3 mixed/real 入口在资源连接前拒绝,Mock 不发真实呼叫。 |
## 执行记录与覆盖率
- `./scripts/acceptance-local.sh`:通过。依次核对 gofmt、Proto/本地 Schema 正反例和 SHA-256 清单、`go mod verify`、`go test -race ./... -count=1`、`go vet ./...`、构建及受限 RabbitMQ 集成测试。首次执行发现一个旧集成夹具仍使用 v0.2 全量响应;改为 v0.3 `after=0` → `after=1` 并在载入任务配置前追平后复测通过。
- `scripts/check-contracts.sh`:v0.3 正例 8、反例 2、清单文件 13 均通过;旧 v0.2 清单仅作为历史,不参与运行。`docs/contracts/local-contract-manifest-v0.3.json` SHA-256 为 `436de2fe5314deb6a2b773f0217b72c61140db4195f68dcb2f9adb5290b93286`;`docs/thirds/v0.3.md` SHA-256 为 `2fa8f5a10b1509044b04b4416a44496c5e9a2d9c741e5437862e2edcb92649ce`。
- `go test -cover -count=1`:P1 业务包 `agent` 71.1%、`callwindow` 84.4%、`configread` 75.2%、`contract` 74.0%、`dispatcher` 70.5%、`rpc` 69.9%、`store` 67.4%、`tenant` 85.4%;RabbitMQ integration 下 `mq` 66.4%、`dispatcher` 70.6%。本轮 P1 业务包均 ≥65%。`cmd/sip-go-agent` 30.0%、历史 `internal/callruntime` 61.7% 单列技术债,不冒称全仓库达标;`mq` 未带 integration tag 的结果不用于验收。
- 工具链为 Go 1.27.1;RabbitMQ 本地镜像 `rabbitmq:4.1-management-alpine`,受限账号无 `configure` 权限。`git diff --check` 通过;测试时工作树未提交,不把当前产物宣称为可复现生产制品。
## 未通过的外部门禁
逐项无 `event_id` 是已确认的项目内响应形态:D 只能核验响应级游标进退,**不能独立证明 SaaS 页内顺序和没有漏项**。外部 SaaS 必须签收完整有序返回和无过期游标;长期保留撤销墓碑所需容量及灾备连续性仍未签收。v0.2 已运行状态不得按 v0.3 游标自动解释,也不删旧任务、执行/幂等/outbox;真实切换须另获受控回迁方案和授权。
真实 SaaS/management、OSS/SIP/云部署、拨号、第二节点/Cell/租户、容量与生产切换均未验证或未授权;本地通过不解除 F06 真实模式阻断。
+49
View File
@@ -0,0 +1,49 @@
# 任务发现统一事件游标分页计划(设计稿 v0.1)
> 状态:本文件保留用户确认的目标与门禁;**项目内 v0.3 合同、运行代码和本地 Mock/F06 检查已完成,外部 SaaS/management 未签收,也未部署或拨号**。当前本地任务发现依据为 [`docs/thirds/v0.3.md`](thirds/v0.3.md) 及其独立 Schema;[v0.2](thirds/v0.2.md) 仅保留历史。实施顺序及总体状态仍以 [`docs/plan-config-read-v0.1.md`](plan-config-read-v0.1.md) 为入口。
## 1. 目标和不变边界
当前 v0.2 首次返回全量 `tasks`,之后返回独立的 `changes`,还需处理过期游标与 410。目标是**只保留一种任务列表形状**:首次按页读取,后续沿同一事件游标读取更新;不再提供 `changes`、`operation` 或两套响应模式。`after` 是变更事件序号,**不是任务 ID,也不是按任务 ID 排序的翻页位置**。任务 `a01` 更新后可以在下一页或下一次查询中再次出现。
| 已确认方向 | 约束 |
| --- | --- |
| 统一 `tasks[]` | 新任务按 `task_id` 识别;已有任务只因 `status` 变化触发任务生命周期动作。其他已有字段仍用于身份、归属和一致性校验,不因其变化擅自重置运行中执行。 |
| 事件游标分页 | 首次查询和每约 30 秒的后续查询都允许多页;每页有界,Dispatcher 以返回的游标继续,直到本轮无更多任务。SaaS 不必一次返回该 D 的全部任务。 |
| 撤销 | 在同一 `tasks[]` 中以 `status=removed` 返回墓碑项;没有任务出现在某一页**不等于**撤销。撤销不删执行恢复、幂等或 outbox。 |
| 永不过期 | 不提供 `cursor_expired`/410 自动重建路径;SaaS 必须保证旧游标仍可继续看到尚未消费的任务变化及撤销。游标无效、记录丢失或无法证明连续时拒绝新执行并报错,不静默重置。 |
| 控制与队列 | MQ 的 pause/resume/stop 即时控制不等 30 秒轮询;SaaS 独占创建、绑定和退役任务队列,Dispatcher 只消费预建队列。 |
本轮仅实现并验证单 Dispatcher、单 Agent、单 Cell、单租户的本地 Mock 路径;单 D 当前任务上限 256 不因分页放宽。其他 SaaS 项目内协议维持 v0.1;不修改 `contracts/upstream/v1/`,不授权真实供应商、云资源、拨号或切换。
## 2. 项目内 v0.3 读取语义(外部未签收)
- 路径沿用 `/internal/v1/dispatcher/tasks`;使用现有受控 D 身份。首次从起始事件序号读取(项目草案记为 `after=0`),以后发送**上次已持久化**的 `next_cursor`。`next_cursor` 代表本页最后一个已返回任务的事件位置,不能跳到尚未返回的全局最新事件。
- 每次 HTTP 200 都使用 `tasks[]` 和 `next_cursor`,不再区分 `snapshot`、`changes`。`tasks[]` 可以为空;空页表示本轮追平,游标不跳跃。非空页的游标必须前进。项目内 v0.3 已冻结为规范十进制游标、单页最多 256 项、仅响应级 `next_cursor`,不增加 `has_more` 或逐项 `event_id`;必须读到空页,不能凭“本页少于上限”推断结束。
- SaaS 对该 D 的任务按**各自最新变更事件序号**升序分页;该序号必须持久、单调且不可复用。同一任务在两次查询之间多次更新,只需返回足以表达**最新状态**的记录,不要求保存每次中间状态。若分页期间再次更新,新的序号必须使该任务可再次被读到;绝不能因游标前进跳过尚未返回的任务。
- 普通任务沿用已确认的身份、原值 `tenant_key`、归属和状态字段。`removed` 墓碑必须至少能唯一定位原 D、租户和任务;其余必填规则由项目内 v0.3 Schema 定义;`task_revision` 是任务状态修订,不能代替事件序号,也不从旧 `changes[].operation=removed` 猜字段。已存在任务的租户/任务归属与本地绑定冲突时拒绝处理,不静默迁移。
- Dispatcher 对新 `task_id` 建立归属并核验 SaaS 预建队列;对已有任务只按最新 `status` 更新生命周期。`paused`/`stopped` 的本地持久屏障不能被较旧的 `running` 覆盖;`removed` 阻止新接纳,已有在途执行、最终结果和 outbox 按原身份收口,不由轮询触发重复拨号或擅自强挂。`status` 不变时可推进游标,但不重复执行控制动作。任务配置仍通过单独的只读任务接口核验,不让发现列表替代执行快照。
`tasks[]`、`next_cursor` 的项目内精确字段与正反例已按 [`v0.3 Schema`](contracts/task-discovery-v0.3-proposal.schema.json) 冻结并在 Mock 验证;**不是 SaaS 现网或对外正式合同**。逐项不带 `event_id`,Dispatcher 不能独立证明 SaaS 页内排序/没有漏项;完整有序返回、长期墓碑及授权绑定仍需 SaaS/业务另行签收。
## 3. 持久化、启动和失败边界
1. 新加入或重启的 D 先从本地已提交游标继续;没有新协议游标时从起始序号逐页读取。完成首次追平、核验队列和配置前,不消费执行队列或开放新拨号;MQ 控制仍可处理。每页校验 D 身份、任务数上限、身份绑定、状态和游标连续性。
2. **任务记录与本页游标必须在同一 SQLite 事务提交**。进程在提交前崩溃则重读原页;提交后重读只会按同一任务身份幂等应用。启动是否已经追平须单独持久标记,不能因为读到第一页就认为拥有完整任务清单。
3. 请求失败、响应不完整、页大小超限、非空页游标不前进、重复/倒退位置、身份冲突或 SQLite 提交失败时,不推进游标,不用部分列表推断缺席任务已撤销,拒绝新执行并保留现场错误日志。成功追平并重新完成当前准入核验后才可恢复;不等下一窗口自动拨号、不换线、不重拨。
4. 当前 v0.2 游标**不能**直接解释为新事件游标。切换前需有独立版本与受控排空/恢复核验;无法证明旧任务、积压及在途执行安全收口时停止切换,不清除旧执行事实或重建执行身份。不得同时运行 v0.2 与新任务发现消费者,也不提供新接口失败后回退旧增量路径。
## 4. “永不过期”的实际成本和阻断项
SaaS 可以维护每个任务的最新事件序号及状态,而不必为 `changes` 另建完整的逐次变更响应。但 D 可能长期离线且仍持有任意旧游标,因此**已撤销任务的墓碑和足以恢复顺序的序号不能提前丢弃**。删除墓碑、复用序号或无声截断历史都与“永不过期”冲突。活跃任务上限 256 **不限制历次撤销的累计数量**;墓碑存储量和首次分页追赶耗时会持续增长。
在 SaaS/业务签收容量预算、长期保留责任、备份恢复后事件序号不回退、旧 D 游标的可读性和极端积压上限之前,**不能把该方向称为可上线或有界容量方案**。若这些条件无法满足,必须另行确认恢复/清理合同,而不是在实现中偷偷设置过期、忽略墓碑或返回伪造的空页。
## 5. 本地结果与后续外部门禁
1. **F07 合同**:发布与当前 v0.2 并列区分的新项目内任务发现版本;冻结起始游标、排序/翻页结束、单页和总量边界、墓碑身份、状态及错误响应;提供正反例、哈希和严格 Schema。旧 v0.2 合同仅保留历史,不原地改写成已发布合同。SaaS/业务签收与项目内 Mock 通过分别标注。
2. **F03 实现**:在独立分支以先失败的测试驱动替换配置读取、逐页应用、SQLite 游标和启动追平门禁;移除旧 `changes`/410 运行路径,不保留双模式或故障回退。更新发布制品的合同版本与摘要核对,保持其他 v0.1 业务接口不变。
3. **F09 本地验收**:覆盖首轮多页、空页、同任务再次出现且状态变化、墓碑、分页并发更新、跨重启重读、控制与轮询竞态、SQLite 写失败、异常游标及错误页;证明不误删、不重拨、不绕过 SaaS 队列所有权。按本轮 P1 业务模块的覆盖率口径验证,Mock 结果不冒称真实 SaaS 或生产验收。
4. **F06 切换阻断**:只有新合同、容量责任、版本化制品、旧状态排空及实际 SaaS 联调各自签收后,才讨论真实部署;本文不授权真实外呼、OSS、ECS、供应商消费或生产切换。
项目内完成记录:F07 v0.3 Schema/正反例/哈希与 Mock C,F03 v0.3 按页持久化及失败拒新,F09 单节点/单租户本地矩阵见 [`f09-local-acceptance-v0.3.md`](evidence/f09-local-acceptance-v0.3.md);F06 本地发布阻断见 [`f06-local-release-gates-v0.3.md`](evidence/f06-local-release-gates-v0.3.md)。不把这四项本地完成记录外推为 SaaS 顺序、墓碑容量或真实部署签收。
+13 -11
View File
@@ -1,6 +1,6 @@
# Go SIP Agent:配置读取与有界外呼迭代计划 v0.1
**当前迭代唯一执行入口。状态:用户已授权 P1 本地迭代;项目内契约冻结与 Mock C、实现及本地验收进行中。** 现行 `contracts/upstream/v1/` 和代码仍是旧外部基线;本文不授权真实 SaaS、生产部署、拨号或切换。分项设计:[有界消费与控制通道](architecture/Dispatcher有界接纳与控制通道改造计划_v0.1.md);原本地 SaaS 结构契约:[第三方对接 v0.1](thirds/第三方对接事件与请求消费顺序_v0.1.md);任务发现单次响应的[修订草案 v0.2](thirds/v0.2.md)及[独立 Schema](contracts/task-discovery-v0.2-proposal.schema.json)不回写 v0.1 历史证据,待新合同及 F03 实现验收后切换。机器校验件:[Schema/正反例](contracts/)。分项材料须与本文一起更新,不能继续使用旧 ETag/304、控制 CAS 或即时反馈目标。
**当前迭代唯一执行入口。状态:用户已授权 P1 本地迭代;任务发现 v0.3 项目内合同、运行与 F09/F06 本地门禁已完成,外部签收与真实切换未完成。** 现行 `contracts/upstream/v1/` 仍是旧外部基线;本文不授权真实 SaaS、生产部署、拨号或切换。分项设计:[有界消费与控制通道](architecture/Dispatcher有界接纳与控制通道改造计划_v0.1.md);其他本地 SaaS 业务契约仍按[第三方对接 v0.1](thirds/第三方对接事件与请求消费顺序_v0.1.md);任务发现现用[计划 0926](plan-0926.md)、[v0.3 项目内合同](thirds/v0.3.md)及[独立 Schema](contracts/task-discovery-v0.3-proposal.schema.json),[v0.2](thirds/v0.2.md)仅保留历史。机器校验件:[Schema/正反例](contracts/)。分项材料须与本文一起更新,不能继续使用旧 ETag/304、控制 CAS 或即时反馈目标。
## 1. 范围和完成标准
@@ -12,7 +12,7 @@
| --- | --- |
| `/internal/v1/dispatcher/sip` | 用户指定路径;本 D 获管理面批准的 SIP 全量。 |
| `/internal/v1/dispatcher/task/:task_id` | 用户指定路径;任务归属、路由/主叫、智能体、时段及两项任务级超时。 |
| `/internal/v1/dispatcher/tasks`(可 `?after=<cursor>`) | 用户指定路径;启动一致全量快照,运行中每 30 秒按变更游标发现任务。 |
| `/internal/v1/dispatcher/tasks?after=<cursor>` | 用户指定路径;首次 `after=0`、重启从已提交事件游标续读,首次与后续均按统一 `tasks[]` 分页,约每 30 秒发现新变化。 |
| `/internal/v1/dispatcher/tenant/:tenant_id/quota` | 本地项目定义路径:取得任务后按其 `tenant_id` 读取该租户分配给本 D 的并发额度;真实 SaaS 路径兼容性未验证。 |
**任务队列及精确绑定只由 SaaS 创建、维护和退役;D 只消费,不建队、不绑定、不删除。** SaaS 先确认持久队列 ready 再发布 persistent 消息,mandatory 无 return 且 confirm 成功才记入队。D 离线时消息可积压;无队列时未成功入队的原消息由 SaaS 保留,就绪后按原身份重新发布,不能靠 D 重启倒灌。任务队列按 D+任务 ID 定位;租户身份保留原值用于核验和额度汇总。
@@ -49,12 +49,12 @@ SaaS 先持久修改权威任务状态,再向独立 D 控制队列发布 `task
1. **pause:**立即关闭新接纳并保存暂停屏障,停止从该任务队列继续取新执行;已投递但未接纳的有界消息退回原队列,不能 ACK 丢弃或搬进无界 SQLite 待拨队列。已有执行按 drain/hangup 处理。重启仍暂停。
2. **resume:**重新 GET 单任务配置(不使用约 60 秒旧缓存),只有 SaaS 最新状态为 running、归属/授权/租户额度/时段有效、且本地未 stopped,才解除暂停并恢复消费原积压。无需 SaaS 重新发原消息;已过 `not_after` 的旧消息仍不可拨,暂停不能冻结或延长有效期。过期/窗口外非 stopped 命令给明确拒绝回执,不等待次日自动拨号。
3. **stop:**持久化不可逆停止屏障,同任务 ID 不能 resume/重新启用;SaaS 停止新发布。D 不申请通话额度,继续小批量消费未接纳积压,仅计本地处置计数并 ACK,不建外呼结果/outbox,不拨号。已停止任务重投/重启、额度为 0、配置缓存失效时仍可排空;不得借此清掉别的任务、伪造已接纳执行终态或漏掉控制回执/既有通话结果。
4. **优先级:**本地 stopped 永久高于任何 running;本地 paused 只能由有效 resume 解除。`tasks` 增量/全量及缓存更新可使状态更严格,不能清除已持久的暂停/停止屏障,且低于已知 `task_revision` 的状态不得覆盖新状态。冷启动恢复本地屏障与 SaaS 全量后取更严格者;冲突/缺失关闭新准入,不丢已有执行事实。
4. **优先级:**本地 stopped 永久高于任何 running;本地 paused 只能由有效 resume 解除。`tasks[]` 事件页及缓存更新可使状态更严格,不能清除已持久的暂停/停止屏障,且低于已知 `task_revision` 的状态不得覆盖新状态。冷启动恢复本地屏障并从已提交游标追平 SaaS 事件页后取更严格者;冲突/缺失关闭新准入,不丢已有执行事实。
5. **无编号乱序:**控制重投可能重复返回回执,不保证按消息身份“只处理一次”。pause/stop 先关闭准入;与 SaaS 最新状态不符、不可核验或接收乱序时保持关闭并返回明确失败,不根据到达先后自动恢复。恢复必须重新发送有效 resume 并核对最新权威状态;不引入替代 command_id 或控制 CAS。SaaS 不可把发布成功视为控制已应用,丢失回执下状态不明不得主动扩量。
### 3.4 任务发现、发布与期限
D 启动/重启用 `/internal/v1/dispatcher/tasks` 拉一致全量快照和水位,运行中每 30 秒 `?after=<cursor>` 拉本 D 新增/更新/撤销。cursor 是不透明变更水位,不是最大 task_id。新版单次返回完整快照或完整变更集,最多 256 条且不分页;响应不带每个任务的 queue/key,D 按已约定的 D+task ID 命名规则推导并只消费 SaaS 预建队列。全量 `cursor`、增量 `next_cursor` 仅在完整校验和原子持久化后推进;空变更的 `next_cursor` 与请求 `after` 相同。`removed` 表示完成退役握手后的撤销归属,不等同于 stop;HTTP 410 `cursor_expired`(含增量超限)关闭新准入并重拉全量,禁止截断或跳过变更。发现清单/任务响应必须提供 tenant_id/tenant_key 以便取额度。无变化不撤销消费关系。
D 启动/重启从已提交的 v0.3 事件游标续读(无新游标时请求 `/internal/v1/dispatcher/tasks?after=0`),运行中约每 30 秒继续读取。首次与后续均返回统一 `tasks[]` 事件页,每页最多 256 项、每 D 活跃归属最多 256 项;`after` 是规范十进制事件序号,不是最大 task_id。非空页的 `next_cursor` 必须前进,空页的 `next_cursor` 保持请求游标并表示本轮追平;同一任务更新后可再次出现,`status=removed` 为撤销墓碑,不能根据某页未出现任务推断撤销。响应不携带 queue/key,D 按 D+task ID 推导并仅消费 SaaS 预建队列。每页任务、响应和游标同事务提交,首次未追平或任何错误页都拒绝新准入,控制 MQ 保持可用。**不设游标过期/410 自动重建,v0.2 checkpoint 不可解释成 v0.3 事件 ID;错误不可静默重置或回退旧 `changes` 路径。** SaaS 必须保证页内完整有序、旧游标及撤销墓碑长期可读;容量/灾备连续性仍待外部签收。发现项和任务配置须提供 tenant_id/tenant_key 以便核验额度;无变化不撤销消费关系。
**队列 ready 不等于 D 已开始消费。** 首条任务可能等待轮询、配置/额度读取和可用名额;30 秒是轮询间隔,不是端到端发现 SLA。SaaS 设置的 `not_after` 应覆盖允许的排队和准备时间,不能用固定 30 秒示例承诺离线恢复必拨。D 重启仅恢复原消息:未过期且有效的才接纳;过期明确拒绝(已 stopped 则静默 ACK),绝不顺延期限/自动造新 command_id 重拨。若要求更短首呼时限,必须在 F07 另定就绪通知协议,不能假设已存在。
@@ -78,10 +78,11 @@ SaaS 清单须保留已 stopped 但未排空任务;撤销握手按第三方契
| --- | --- | --- |
| F00 草案整理 | 集成负责人同步本文、分项设计、对接文档、配置 Schema/示例;标明用户给定路径与项目新增额度/路由字段。 | 正反例可验证,不冒充 SaaS 现网。 |
| F01 HTTP 与配置/额度合同 | 按第三方文档冻结四条 GET、两 Header、身份映射、任务主叫/候选优先级、两时限较小值、授权/缓存/配置不可变及租户额度份额/版本/有效期。 | 项目内严格 Schema、来源/版本/哈希、正反例;静态提示词或变量来源明确;Mock 验证,不等待外部签收。 |
| F07 MQ、发现及控制/结果合同 | 历史 F07 先冻结 v0.1 分页发现;仅任务发现随后由 F03 v0.2 单次响应修订取代。其余 SaaS 独占队列生命周期、v3 routing、精简 call.execute、无编号控制、pause/resume/stop、回执/唯一最终结果、录音边界及消息大小/期限维持原合同。 | 项目内严格 Schema、拓扑、正反例、来源/hash;与 F01 一致并由 Mock 端到端验证后 C 通过。移除旧 query/replay/配置 MQ/拆分事件;外部兼容另记未验证。 |
| F07 MQ、发现及控制/结果合同 | 历史 F07 先冻结 v0.1 分页发现,随后 F03 v0.2 单次响应已退为历史;任务发现现按 v0.3 事件游标合同。其余 SaaS 独占队列生命周期、v3 routing、精简 call.execute、无编号控制、pause/resume/stop、回执/唯一最终结果、录音边界及消息大小/期限维持原合同。 | 项目内严格 Schema、拓扑、正反例、来源/hash;与 F01 一致并由 Mock 端到端验证后 C 通过。移除旧 query/replay/配置 MQ/拆分事件;外部兼容另记未验证。 |
| F02 配置与额度读取(C 后) | 接入四条已冻结 GET(本地先由 Mock 提供);D 读取并校验 SIP 实际加载、任务租户映射、按 tenant_id 的额度,完整 200 缓存;有期限拒绝与持久快照。 | 断服务、降额、同租户多任务、过期/错身份、新旧配置竞态不超额/不漂移;真实 SaaS 未联调不冒称通过。 |
| F03 消费/发现/控制(F02 后) | D 移除旧 `--tenant-key` 自建租户队列路径,按 SaaS 已建任务队列消费;发现游标/暂停恢复/停止静默ACK/独立控制与原子额度;未接纳仍留 MQ。旧分页发现结果仅属历史。 | §5 的队列/控制矩阵通过;D 无建队权限仍可工作,stop静默但可排查。 |
| F03 v0.2 任务发现修订(F04 前) | 每 D 单次完整响应≤256,正文无 queue/key;失效游标 410 恢复全量,空变更原游标,退役 `removed`;完整响应、任务归属、游标原子持久化,发现失败关准入/停任务消费但不中断控制。 | v0.2 Schema/示例/hash 与 Mock/本地 RabbitMQ 再验;只运行新协议,不把旧 F03 证据当作新版通过。 |
| F03 v0.2 任务发现修订(历史) | 单次完整返回、`changes`/410 的前版本实现;已由 v0.3 项目内运行路径替换。 | 旧 Schema/证据留作追溯,不作当前运行或新版本验收。 |
| F03 v0.3 事件游标发现 | 首次/后续统一 `tasks[]` 分页;按提交游标追平、同任务更新/removed 墓碑、错误页关准入、SQLite 同事务;无 v0.2 兼容或 410 重建。 | [plan-0926](plan-0926.md) 与 v0.3 Schema/正反例/hash、Mock F09 及本地 F06 制品核对;SaaS 页内顺序/长期墓碑和旧状态受控切换仍待外部门禁。 |
| F04 时段及最后拨号屏障(F03 后) | 仅 Dispatcher 在持久接纳与发出呼出指令前复核任务×已绑定线路时段、任务排除日期、白名单、有效期及任务/AI 时限,持久化唯一签发/拒绝决定;Agent 只核验会话及 Dispatcher 签发期限。 | 本地 Mock 验证窗口边界/跨日/更新/暂停竞态不拨号、不等待或自动重试;真实路径固定时段只在外部合同、F09/F06 验收及授权后替换。 |
| F08 结果与受控切换(F04 后) | 组装 uploaded/unavailable/not_created 的最终结果与既有命令/控制回执;通话释放独立于上传;旧新版本互斥,恢复原身份 outbox。 | 本地全流程无重复拨号/PUT,停止积压不产生回传,已有执行结果不丢失。 |
| F09 本地验收(F08 后) | 集成负责人运行 §5 全矩阵;单 D 单租户多任务为 L,扩展 fixture 标为非 P1。 | gofmt、`go vet ./...`、`go test -race ./...`、`go build ./...`、本模块覆盖率≥65%,脱敏证据。 |
@@ -100,7 +101,7 @@ SaaS 清单须保留已 stopped 但未排空任务;撤销握手按第三方契
| stop 静默 | 未接纳积压100条、在途2通、stop;ACK丢失/重启/额度0 | 100条最终ACK,originate=0、新回执/最终结果outbox=0;本地计数可核查。stop控制有回执,2通按策略终结并各有最终结果;其他任务不受影响。 |
| 状态优先级 | pause/stop后收到旧running快照或低版本tasks;旧resume迟到/控制重复/HTTP断连 | 不自动恢复;resume未获最新running/未过屏障即明确失败;stopped不可逆。控制不按消息身份去重,不保证只回一次;回执不明不当成功。 |
| 新任务/离线期限 | 刚过轮询点新建队列;离线超过not_after;首条期限不足准备时间 | 消息先入已建队列;恢复只消费仍有效者,过期不拨不顺延,不自动新建外呼命令;30秒只是发请求周期。 |
| 发现/退役 | 较小ID任务变更、空变更、重复/超过256条、游标失效、removed 退役、SaaS创建前误发、stopped仍有积压 | 不漏旧任务变更;不接收分页或响应内队列字段,不截断超限结果,失效后重拉全量且只在原子持久化后推进游标;未入队原消息由SaaS保留;stopped保留清单直到静默排空,无未ACK/未知执行再退役。 |
| 发现/退役 | 首次多页、同任务较小 ID 在翻页中更新、空页、重复/超 256 项、游标倒退或 HTTP 410、removed 墓碑、SaaS 建队前误发、stopped 积压 | 不漏更新;每页限 256、活跃任务限 256,拒绝响应内队列字段、不截断结果;无 410 回退或重拉全量,只在同事务提交后推进游标;未入队原消息由 SaaS 保留,stopped 持续静默排空;旧状态或顺序无法证明时阻断切换。 |
| 队列权限/配额 | D禁止create/bind/delete、队列满、SQLite满盘、租户满额 | D只消费,不补建;SaaS保留未成功发布消息;事务失败不ACK已接纳;不会搬全部积压进SQLite,不阻塞控制/stop清理。 |
| 无录音/失败 | 无应答/忙线且无录音;应有录音却失败;OSS超时;停止未接纳命令 | 正常无录音not_created且不等待上传;明确授权/PUT失败立即unavailable,未知最晚15分钟收口;停止未接纳无回传;不能伪造call_id/成功路径。 |
| 释放与结果 | 已确认结束但上传慢、MQ confirm丢失或重启、完整转写超过8 MiB | 通话额度已释放、未知仍占额;原结果身份重投不重拨/PUT;超限 outbox 显式阻塞,不截断/拆分/丢弃。 |
@@ -108,7 +109,7 @@ SaaS 清单须保留已 stopped 但未排空任务;撤销握手按第三方契
## 6. 写入与实施边界
项目设计与本地目标契约在自身 docs 维护。`contracts/upstream/v1` 保持现行外部运行基线,不擅改;原 v0.1 本地合同与 F03 证据保留为历史;`docs/thirds/v0.2.md` §2.5 中任务发现单次响应已作为**本地运行修订合同**完成实现和 Mock 校验,独立 v0.2 Schema、正反例和来源哈希见新版 F03 证据;这不代表真实 SaaS 已发布或签收。其他业务合同沿用已有本地 v0.1 机器校验件,须记录规范文件与机器文件 SHA-256。该本地契约不冒称 SaaS/management 已发布,外部签收和连通不阻塞本地 C。本文/分项/guide/字段提案必须同步;源码、截图、真实凭据、无关父仓库不改动。TDD 先失败后实施,复用现有库,禁止隐藏错误、HTTP/MQ配置回退、重复外呼。大改另开分支,未获得子 Agent 授权由当前负责人执行。
项目设计与本地目标契约在自身 docs 维护。`contracts/upstream/v1` 保持现行外部运行基线,不擅改;原 v0.1 本地合同与 F03 证据保留为历史;`docs/thirds/v0.3.md` 的任务发现事件游标分页已作为**项目内本地运行合同**完成实现与 Mock 校验,独立 v0.3 Schema、正反例和来源哈希见 F09 v0.3 证据;v0.2 Schema/证据仅保留历史。这不代表真实 SaaS 已发布、有序返回或长期墓碑容量已签收。其他业务合同沿用已有本地 v0.1 机器校验件,须记录规范文件与机器文件 SHA-256。该本地契约不冒称 SaaS/management 已发布,外部签收和连通不阻塞本地 C。本文/分项/guide/字段提案必须同步;源码、截图、真实凭据、无关父仓库不改动。TDD 先失败后实施,复用现有库,禁止隐藏错误、HTTP/MQ配置回退、重复外呼。大改另开分支,未获得子 Agent 授权由当前负责人执行。
## 7. I/M/G 前置
@@ -124,11 +125,12 @@ SaaS 清单须保留已 stopped 但未排空任务;撤销握手按第三方契
| F07 | 项目内任务发现/队列所有权与生命周期、MQ v3 控制/回执、单份 `call.result`、大小/期限/退役规则已按第三方文档冻结;本地正反例已校验。`contracts/upstream/v1` 仍是现行外部基线,真实兼容性未验证。 | `python3 scripts/validate-local-contracts.py` 通过:发现 13 个正例、命令 6 个、结果 4 个,各 Schema 负例均拒绝;source 与 18 项产物共 19 个 SHA-256 文件通过。F03 运行时本地交付见下行;外部兼容性仍未验证。 |
| C | 本地 Mock SaaS 通过四条只读 GET、`call.execute`、`command.result` 与 synthetic `call.result` 的 Dispatcher 端到端交互;缺少 result queue 时 outbox 保留并在恢复后交付。 | 证据:[`local-mock-saas-c-v0.1.md`](evidence/local-mock-saas-c-v0.1.md)。契约验证、包测试及 `bash scripts/mq-integration-local.sh` 通过。仅属项目内 Mock;没有真实执行、拨号、录音上传或外部验收。 |
| F02 | 本地配置与额度读取模块完成:四条 GET 严格校验,四份完整响应按版本/hash/有效期持久化,任务/租户身份绑定,task+tenant 配额与 call.execute reservation 原子接纳;SIP Agent applied-config 核验、断连/过期/不匹配 fail-closed、同租户多任务和配置竞态均有 Mock 覆盖。F02 涉及四包覆盖率为 65.1%–75.0%。 | 证据:[`f02-local-config-read-v0.1.md`](evidence/f02-local-config-read-v0.1.md)。包测试、race、`go test ./...`、vet、build 和契约校验通过。F09 按用户确认的本轮 P1 业务模块 ≥65% 口径另验;CLI/历史包低覆盖率单列;F03 应用启动/消费现有本地证据见下行,真实 SaaS/Asterisk 加载仍未验证。 |
| F03(历史分页证据) | 单 D/单租户 v3 运行时曾在本地交付:只被动消费 SaaS 预建队列,持久发现游标/任务归属,暂停保留积压,恢复使用原队列,停止先持久屏障与权威状态、后静默排空并 ACK,排空完成后才写控制回执。RabbitMQ ACL Mock 证明 Dispatcher 无 `configure` 权限仍可消费、排空和发布;旧 tenant-queue consumer、旧 per-call control worker、CLI 旧消费参数及 MQ-only v1 acceptance runner 已移除。 | 证据:[`f03-local-task-runtime-v0.1.md`](evidence/f03-local-task-runtime-v0.1.md)。本地 acceptance、Race、vet、build、契约与无 `configure` 权限的 RabbitMQ 集成测试通过;`internal/dispatcher` 覆盖率 66.2%。仅是本地隔离验证,外部 SaaS/management、云、线路和生产均未验证;F09 新版本地矩阵见下行,历史分页证据不代签。 |\n| F03 v0.2 修订 | 本地运行已采用单次完整发现:每 D 最多 256 个归属任务、响应不含队列地址;队列名按 D+task ID 推导且只能被动消费 SaaS 预建队列。空变更保持 `next_cursor`,过期游标 HTTP 410 重拉全量,`removed` 退役,超额拒绝且不推进游标;发现故障关闭新准入/停任务消费但保留 MQ 控制。旧 F03 v0.1 证据只作历史。 | 证据:[`f03-local-task-discovery-v0.2.md`](evidence/f03-local-task-discovery-v0.2.md)。新版 Schema/正反例/hash 与本地 Mock、race、vet、构建和无 `configure` 的 RabbitMQ 测试通过;F09 本地全矩阵/覆盖率见下行,真实 SaaS/management/拨号/生产未验证。 |
| F03(历史分页证据) | 单 D/单租户 v3 运行时曾在本地交付:只被动消费 SaaS 预建队列,持久发现游标/任务归属,暂停保留积压,恢复使用原队列,停止先持久屏障与权威状态、后静默排空并 ACK,排空完成后才写控制回执。RabbitMQ ACL Mock 证明 Dispatcher 无 `configure` 权限仍可消费、排空和发布;旧 tenant-queue consumer、旧 per-call control worker、CLI 旧消费参数及 MQ-only v1 acceptance runner 已移除。 | 证据:[`f03-local-task-runtime-v0.1.md`](evidence/f03-local-task-runtime-v0.1.md)。本地 acceptance、Race、vet、build、契约与无 `configure` 权限的 RabbitMQ 集成测试通过;`internal/dispatcher` 覆盖率 66.2%。仅是本地隔离验证,外部 SaaS/management、云、线路和生产均未验证;F09 新版本地矩阵见下行,历史分页证据不代签。 |\n| F03 v0.2(历史) | 前版单次完整发现、增量 `changes` 和 410 重拉全量曾在本地验证,当前运行代码已移除该路径。 | 证据:[`f03-local-task-discovery-v0.2.md`](evidence/f03-local-task-discovery-v0.2.md),仅作历史,不代表 v0.3 通过。 |
| F07/F03 v0.3 | 项目内 `tasks[]` 事件游标页及来源/hash 冻结;Dispatcher 与 SQLite 按页原子提交,首次追平前和异常页拒绝新执行;同任务更新、撤销墓碑、断页重启从已提交游标续读、控制竞态与无重拨已完成 Mock。旧 `changes`/410 运行路径移除,SaaS 队列仍独占建队。 | 证据:[`f09-local-acceptance-v0.3.md`](evidence/f09-local-acceptance-v0.3.md)。外部 SaaS 有序返回、长期墓碑容量、旧状态受控切换和真实兼容仍未签收。 |
| F04 | 本地隔离 Mock 已将任务×已选线路时段、任务排除日期、白名单/有效期、绑定快照及任务/AI 较小通话时限接入接纳与发起前门禁;执行身份只有一次持久 `issued`/`refused` 决定,队列消费后由 D 经版本化 Unary 向 Mock Agent 下发,Agent 不重算业务策略、不发送 SIP。V3 mixed/real 启动拒绝,原真实固定门禁未放宽。 | 证据:[`f04-local-dial-policy-v0.1.md`](evidence/f04-local-dial-policy-v0.1.md)。Proto/合同、本地 Mock、race、vet、build、RabbitMQ 无 `configure` 权限及 `scripts/acceptance-local.sh` 通过;外部合同/真实拨号未验证。F08 后续本地结果见 [`f08-local-final-result-v0.1.md`](evidence/f08-local-final-result-v0.1.md);F09 本地矩阵与覆盖率见 [`f09-local-acceptance-v0.2.md`](evidence/f09-local-acceptance-v0.2.md)。 |
| F08 | 单份最终 `call.result`、确认终态后独立释放额度、uploaded/unavailable/not_created、本地 Agent→D 录音失败事实与原身份 outbox 已完成隔离 Mock 验证;V3 Mock 不并行写旧分散事件,V3 mixed/real 启动拒绝。证据:[`f08-local-final-result-v0.1.md`](evidence/f08-local-final-result-v0.1.md)。 | `scripts/acceptance-local.sh`(含 race、vet、构建及受限 RabbitMQ)通过;Mock 录音成功/失败由合成事实注入,默认 Mock 只模拟无应答,无实际媒体/OSS PUT,publisher confirm 不等于 SaaS 应用签收。F09 本地验证见 [`f09-local-acceptance-v0.2.md`](evidence/f09-local-acceptance-v0.2.md);F06 真实部署/切换仍未获授权。 |
| F09 | 任务发现 v0.2 的 ≤256 单次完整返回、空变更/removed/410 恢复及计划 §5 单节点/单租户适用矩阵均已重新进行本地 Mock 验证;stop 前两条已发起执行的 Agent 归属与一次性拨号决定现由同一事务持久化,stop 可对两条发 hangup 且旧执行仍返回结果。证据:[`f09-local-acceptance-v0.2.md`](evidence/f09-local-acceptance-v0.2.md)。 | `scripts/acceptance-local.sh`(格式/合同/Proto/hash、race、vet、构建及受限 RabbitMQ)通过;本轮 P1 业务模块均 ≥65%,MQ 仅带 integration tag 时为 66.4%。CLI 29.6% 和历史 callruntime 61.7% 未达线,按用户确认口径单列技术债,**不声称全仓达标**。队列满真实 RabbitMQ Mock 拒绝;SQLite 满盘仅作写入错误注入,未物理填盘。外部/真实验收未完成。 |
| F06 | 本地发布准备与切换阻断已核对:Go 1.27.1 一次性制品/校验和、v0.1 其他协议+v0.2 任务发现+项目 v3 MQ 队列及 Proto manifest 的版本/hash 写入制品清单;已有 release/package 输出及归档拒绝覆盖,mixed/real V3 执行在触碰 DB/MQ 前 fail-closed,旧消费 CLI 和旧分散事件不能并行写入新路径。证据:[`f06-local-release-gates-v0.2.md`](evidence/f06-local-release-gates-v0.2.md)。 | `make release-check-local` 与本地 acceptance 通过;来源 dirty,制品仅 local-development、`production_approval=false`。未获真实部署/拨号/切换授权,旧 Python 资源移交、ECS/systemd/Asterisk 实际加载和生产签收均**未执行**;本地阻断不代替真实切换。 |
| F09 | v0.3 首次多页、空页、同任务重现及墓碑、翻页中更新、断页重启、坏游标/410 失败、SQLite 写失败同事务回滚、MQ 控制竞态、重复执行不重拨完成单节点/单租户本地 Mock 验证;旧 F09 v0.2 证据仅作历史。证据:[`f09-local-acceptance-v0.3.md`](evidence/f09-local-acceptance-v0.3.md)。 | `scripts/acceptance-local.sh`(格式/合同/Proto/hash、race、vet、构建、受限 RabbitMQ)通过;P1 业务包 66.4%–85.4%(MQ 含 integration)。CLI 30.0% 和历史 callruntime 61.7% 单列技术债,不声称全仓达标;SQLite 写失败用触发器注入,未物理填盘。外部有序返回/墓碑容量/真实验收未完成。 |
| F06 | Go 1.27.1 一次性本地制品/校验和将 v0.1 其他业务+v0.3 任务发现+v3 MQ 拓扑及 Proto 版本/hash 写入清单;已有 release/package/归档拒绝覆盖,制品 mixed/real 在开 DB 前拒绝;旧 CLI 和分散事件不在新运行路径。证据:[`f06-local-release-gates-v0.3.md`](evidence/f06-local-release-gates-v0.3.md)。 | `make release-check-local` 与本地 acceptance 通过;来源 dirty、`production_approval=false`。外部 SaaS 有序返回/长期墓碑容量、v0.2 旧状态受控切换、真实部署/拨号与生产签收均**未完成**;本地阻断不代签真实切换。 |
| F05 | 多D/第二租户不在本轮运行范围。 | 另获阶段与额度/资源授权。 |
## 9. 协作与版本记录