Files
go-sip/docs/evidence/sqlite-cleanup-v0.1-local.md
T

111 lines
16 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.
# SQLite cleanup v0.1 本地迭代记录
## 范围与状态
- 开发分支:`feat/sqlite-cleanup-v0.1`;首期本地开发及复审根因修复完成;修复后完整 `make check`、覆盖率和Python测试通过,最终干净制品检查记录见文末。
- 用户确认:仅本项目内部数据保留周期调整,不新增 `execution_id`,源 `event_id`(包括 numberID)原样回传;SaaS 如何处理再次返回的同 ID 结果不在范围内。
- 初轮固定 `ef3009d`。复审后用户明确批准仅必要一句文字及共享发布,`7b4448f3586104cde91509a5d5951575c37a8b2c` 已发布并固定本项目引用,43个JSON和8项合同检查通过;Schema、接口字段、消息类型、路由不变。
- 没有合入或推送本项目 main、部署、操作现存运行数据库/恢复目录、退役主机 `.approved`、拨号、抓包或调用真实 AI/OSS。
## 已完成的分批验证
### Agent 永久标记退役(`f07bf90`)
- 先新增并运行反例,原实现因创建 `.approved`、依赖旧标记及完成后不允许重用而失败;删除相关生产读写代码后通过。
- 验证同身份活动期间不能重叠执行,结束后可再次执行;旧 `.approved` 文件/目录不读取、不改写、不删除,新运行不重建该目录。
- 仅在临时目录验证私密备份字节、长度和 SHA-256 一致后删除准确标记路径,相邻会话、`.results`、`.executions`、录音、上传恢复、锁及 Dispatcher 数据均保留。
- `go test -race ./internal/rpc ./internal/agent ./internal/store ./internal/dispatcher` 通过。
### SQLite 实时清理
- 新增测试先因缺少清理入口失败,实现后全部通过。
- 已派发呼叫需要已确认终结、通过现有结果 RPC 验证后持久提交的结果,以及派发回执、最终结果各自的 MQ publisher confirm。结果提交之后没有额外可能失败的业务验收步骤;不增加第二次 Agent 确认,不把 RPC 响应的网络到达或 MQ confirm 当作 SaaS 应用收讫。
- 删除事务重新检查类型、源 ID、归属、号码、线路、冻结快照及上传结果;矛盾证据保留并报错。SQLite 结构仍为 4,没有新表或迁移。
- 未发起拒绝仅清理已确认拒绝;原始拒绝文件仍须由后续文件收尾步骤保护其回执。活动、pending、dispatching、dispatched、unknown、任一确认缺失均保留。
- stopped 的取消记录逐条事务、分批处理;单条失败不阻止其他记录,停止回执到剩余取消/待拨记录清完后才删,任务停止状态不删。205 条取消记录的批次、取消中断和 SQL 故障恢复测试通过。
- 持有待拨指令或原派发调用期间排除清理;重新核对缓冲指令,停止/删除/替换后的旧批次不再拨号。极速终结与原派发返回并发时,先完成原调用再清理。
- MQ publisher confirm 后触发清理;清理故障记录身份与原因,不作为业务准入故障返回。
- 原 `event_id` 清理后可再次接纳、执行和回传;只删除本通数据,共享配置和任务状态保留。报告的是删除的逻辑行/正文字节,不声称 SQLite 文件立即变小。
- `go test -race ./internal/store ./internal/dispatcher ./internal/rpc` 通过。
### 已交付录音文件
- 先添加反例:原逻辑不能读取音频已删但 `info.json` 仍为 delivered 的合法中间状态,且不会删除已交付文件;实现后通过。
- 仅持久 delivered、上传成功回执和原身份/长度/校验和等信息有效、且原事件无未完成 `.results` 引用时删除。prepared、ready、end_pending 引用都保留原恢复文件,引用完成后可以继续收尾。
- 删除前先把原 delivered 信息原样持久保存至私有 `.recording-cleanup` 临时副本;依次删除本条 `recording.wav`、同步目录、删除 `info.json`、同步并删除准确且空的叶目录,同步父目录后才删副本。共享父目录、`.results`、未知侧文件/空目录与 OSS 对象不删除;返回错误及硬退出均保留原信息或副本,下次启动只补删除,不申请授权、PUT 或重报。
- delivered 且原音频已经缺失时,只放行这一已确认删除的中间状态;其他状态缺音频仍报错。原校验和严格保持有效的小写 SHA-256,上传回执、长度和身份校验不弱化。
- 同一录音跨不同 recovery 实例使用临时按路径互斥;结果引用写入/确认与删除协调,锁使用结束即移除,不形成永久身份历史。并发实例仍只有一次 PUT、一次回报;完成后不存在该记录,后续直接调用明确返回不存在而非虚构已完成历史。
- 既有恢复扫描能续处理 delivered 中间状态,避免清理后同次遍历把已删除音频误报成孤立文件;单条坏目录不妨碍其他合法记录。没有新增十秒全目录清理任务,既有恢复调度保持原用途。
- 信息/目录删除失败后重启、未完成引用、无音频的坏回执、未知文件、跨实例并发及互斥清退测试通过;`go test -race ./internal/agent ./internal/rpc ./cmd/sip-go-agent` 通过。
### 已确认拒绝原始文件
- 新增资格/事务/文件失败反例后实现。call.execute、task.control、sip.config 结构拒绝须有对应 typed publisher confirm;无回执、未确认、非拒绝及已接纳执行的冲突不会删原始文件。
- 按接收 Dispatcher、原类型/ID、租户及完整回执字节关联,验证原消息身份、记录结构、私有普通文件和完整记录 SHA-256。关联或内容冲突保留本组原件及完成依据。
- 新文件名仅增加回执正文 SHA-256 前缀,保证即使本条记录无法解析也能保留正确回执、而不阻止独立组;这是内部磁盘索引,不新增业务编号或协议字段。现有仅记录 SHA-256 命名的文件仍以完整内容验证,不改写或迁移;旧文件若连关联身份也无法读取,保留文件及潜在完成依据,日志明确要求人工核验,不猜测删除。
- 一回执多原件先逐条删除并同步目录,全部完成后才删回执;文件删除半途失败和原件删完后回执事务失败都能补收尾。未生成回执的孤立原件、未确认组、未知名称和既存 .pending 临时文件不删。
- RejectData 写入和清理共享生命周期排除;清理结束后同源再来的新拒绝保留新原件和未确认回执,不误删为旧记录。移除了此前 admitted rejected 的“只要整个拒绝目录非空就保留”保护,改为精确本组资格。
- MQ 确认后的真实控制器入口已验证三类拒绝,未产生执行或伪造最终结果;多原件、两阶段失败、损坏组与独立组、既有文件、未知临时文件和并发写入回归通过。`go test -race ./internal/store ./internal/dispatcher ./internal/rpc` 通过。
### 每日午夜补扫
- 采用固定 Asia/Shanghai 日历边界,启动只安排下一次午夜,不在启动时额外清理、不在 12:00 运行、不按消息年龄删除;每次重新计算下一日期。系统时钟回退不会提前执行,清理失败等待下一午夜,不形成高频重试。
- Dispatcher 使用独立且可取消的后台任务,分页扫描 completed 候选并复用 MQ 确认后相同的逐条事务/原件资格;单条失败继续其他记录,不变更准入、任务状态、停止状态或发布消息。停服取消并等待清理任务结束。
- 配置录音恢复根目录的 Agent 启动独立午夜任务,复用已有扫描和 delivered 删除;其他状态只校验保留,不申请授权、PUT 或上报结果。既有十秒真实恢复的用途和节奏不变。
- 每条日志记录身份、保留原因或错误、实际文件数量与字节;Dispatcher 汇总扫描、保留、失败、删除行、逻辑数据字节、文件数量/字节及耗时。没有永久扫描进度或二次确认记录。
- UTC/上海转换、12:00 不清理、午夜启动安排次日、时钟回退、失败等待次日、取消计时器,以及 205 条跨页候选、未确认/待拨邻居保留、取消后续处理、只清 delivered 不重试其他录音验证通过。
- `go test -race ./internal/daily ./internal/store ./internal/dispatcher ./internal/agent ./cmd/sip-go-agent` 通过。
## 初轮固定提交验证(复审修复前的历史记录)
- `make check`:格式、合同固定引用/43 JSON及8合同测试、Proto来源、`go vet ./...`、`go test -race ./...`、二进制构建及隔离 MQ 检查通过。
- `make release-check-local`:在干净固定代码提交 `afa4fe2` 重新通过,`source dirty=False`、`production_approval=False`;制品 SHA-256 为 `e03c42d8f6b7b2cfd6c95e810c4ec1461b2f06d515b1f53c17719a1c7b9978ac`,合同固定 `ef3009df3a90f6e941ca0b24e46134aef17a374d`。同提交 `make check` 和 `make coverage` 重新通过,业务覆盖率72.9%。此制品及覆盖率属于复审修复前,不能作为修复后最终代码的制品证据,也不将本地制品批准为生产。
- 实际运行的隔离 RabbitMQ + HTTPS + gRPC mTLS 端到端通过。更新旧“完成后永不重用”断言:收到原 ID 最终结果、两个消息类型分别确认、本地清理后,再通过 MQ 投递同一源 ID,Agent 再次接纳且 ID 不变。没有以孤立单元测试代替 MQ/HTTPS/mTLS 运行事实。
- 业务覆盖率 **72.9%**(新增纯测试后复核),高于 65%;Python生产部署 **26** 项、脚本 **9** 项通过。
- SQLite增长:4轮各40通、同源 numberID 重用及重启,完成后 inbox/outbox/recordings 都为0,共享task/config仍各1;预热后 page_count 不继续增长,不执行 VACUUM、不要求数据库文件立即缩小。
- 录音/拒绝文件增长:各3轮×20条重复身份,完成后原件/回执或录音叶目录不存在;保留共享目录,不留 `.approved` 或内存永久完成身份历史。
- 没有修改部署主机或现有运行数据库/文件,未 main 合入/推送、部署、重置、迁移、拨号、抓包、实际 AI/OSS 调用或 OSS 对象删除。SaaS收到、判重、覆盖和真实通话/生产验收不在本次范围。
## 复审根因修复
- 独立审核发现初轮 info 删除后、空叶删除前的硬退出窗口没有依据;不是普通删除返回错误。新增子进程 `os.Exit(23)` 先复现:info 删除后空叶仍留存。修复后音频、info、叶、副本四个实际删除边界 × 启动/午夜两入口均通过;无 defer、恢复信息回写或有序退出掩盖窗口。
- `.recording-cleanup/<原bucket/objectKey路径SHA>.json` 仅是现有 delivered 信息的私有临时副本,不是外部 ID、二次确认或永久完成历史。副本在删除任一原文件前持久保存;空叶 durably gone 后才删副本。没有根据前缀或“空目录”推测完成,读取原 delivered 身份/上传回执/长度/校验和并校验精确副本路径。
- 副本缺失/损坏/身份冲突/错名/非delivered/假上传回执不能清原件;原副本持久化失败时音频/info都保留。info已删只允许从有效副本续处理,且音频必须已不存在;其他缺失/损坏仍报错。
- 空叶已删、副本删除失败时仍保留依据;同OSS目标新恢复写入明确拒绝,避免旧副本误删新记录。独立合法记录照常清理,下一实例重试最终只删副本,目标随后可复用;副本清完不留完成文件。
- `go test -race ./contracts ./internal/agent` 通过。`contracts/cleanup_scope_test.go` 固定文字测试保留原值/tuple/尚未清理的防重规则;机器Schema无改动。
### 修复后全量检查
- `make check` 重新通过,含格式、固定合同43 JSON及8测试、Proto、vet、全量race、构建和实际隔离RabbitMQ/HTTPS/mTLS;新合同范围回归与四个删除边界硬退出的启动/午夜续收尾均包含在全量测试中。
- `make coverage`:业务覆盖率 **73.0%**。生产Python **26** 项、脚本Python **9** 项均重新通过。日志 `/tmp/go-sip-cleanup-audit-final-{check,coverage,python,script-tests}.log`。
- 两项审核缺口均有对应根因修复及测试,不以普通返回错误模拟硬退出,不忽略共享首次事实的必要文字。
### SaaS开发同步说明(不等待外部适配)
共享版本:`7b4448f3586104cde91509a5d5951575c37a8b2c`。仅把“同类型同身份保留首次事实”明确为 Dispatcher 本地执行/回执仍保留期间;完成且按条件清理后,同源 `event_id` 可再次执行,回执/结果仍原值,不增加 `execution_id`。接口字段、Schema、类型、路由不变。此项不规定 SaaS 重复结果接收/判重/覆盖/区分规则,也不以 SaaS 处理或验收为开发条件;本说明供开发同步,不声称对方已收到、正确处理或完成适配。
### 计划验收逐项对应
| 项目 | 本地证据 |
| --- | --- |
| finished需结果成功与派发/最终结果各自confirm;任一缺失保留 | store/cleanup_test.go、dispatcher/cleanup_test.go及隔离runtime集成 |
| rejected需正式未发起拒绝confirm,不要求不存在的最终结果 | store/cleanup_test.go、rpc definitive-no-dial及原有占用释放回归 |
| suppressed需durable stopped和成功stop confirm | store/cleanup_control_test.go:205条、单条SQL故障、取消中断及补收尾 |
| Stop回执后删;停止状态/共享配置/未决/unknown保留 | store清理/占用恢复、dispatcher缓冲旧批次/并发派发及既有恢复测试 |
| .approved不生成;活动并发仍受保护 | rpc/approved_retirement_test.go:活动重叠拒绝、结束/重启后重用、旧标记不读改 |
| 已存主机.approved受控退役 | 仅临时目录验证私密备份bytes/size/SHA和相邻边界;主机操作范围外未执行 |
| 音频删、delivered info仍在时续处理;其他状态缺音频报错 | agent/recording_cleanup_test.go,信息/叶目录失败和坏SHA,重启不PUT/report |
| 未完成.results引用、未知侧文件/坏记录保留,独立记录继续 | agent录音清理/扫描及全量结果日志回归;临时锁释放和跨实例一次PUT |
| 原始拒绝准确关联;一回执多文件;孤立/未确认不删 | store/cleanup_rejected_test.go,完整回执/身份/内容/文件索引证明 |
| 两阶段删除失败/并发新捕获不会提前清回执 | 原件半途失败、回执SQL触发器失败、capture-race及独立坏组回归 |
| .results正常成功收尾、SIP来源、既有临时行为不退化 | 全量agent/result_journal、store/sip_source及cmd/rpc回归;未知.pending保持 |
| 实时与午夜同条件;0点非12点;故障/取消不关准入 | daily/midnight_test.go、dispatcher/cleanup_scan_test.go、Agent delivered-only回归 |
| 同源ID原值重用,不新增字段,不验证SaaS重复处理 | controller单元与隔离MQ最终结果/再次执行;Schema/Proto均未改,submodule仅获批文字更新 |
### A01–A12 / K01–K16 范围核对
- A01–A03、K01–K02:固定共享合同、来源检查、事件身份及入站/出站边界由本次完整检查和现行Schema回归核验;不另复制或修改运行契约。
- A04–A06、K03–K10:HTTP完整配置、任务控制优先级、租户/任务/线路占用、停止/缓冲并发、publisher confirm及未决重启保护由全量回归及实际隔离MQ/HTTPS/mTLS核验;已完成数据只在本地条件满足后释放记录。
- A07–A09、K11–K14:Agent会话/原值派发、执行终结、上传绑定/未知PUT/恢复与结果交付由rpc/agent/store回归核验;本次只清理成功delivered,不扩大重试或真实云授权。
- A10–A12、K15–K16:可观测性、构建制品、本地门禁和单节点边界检查通过;真实SaaS/management、真实通话/AI/OSS、ECS、容量、多节点/租户及生产签收不适用且未宣称通过。