* H-60: harden Captain migration rollback and concurrency * chore(agent): baseline — uncommitted work from the local directory * fix: route Shangwutong events by display id --------- Co-authored-by: Rogee <rogee@ipao.vip>
2.5 KiB
审查结论:发现 2 个阻断项;H-53 的事务回滚根因已关闭,但迁移可逆性与并发回归测试仍不满足验收。
P1
-
backend/migrations/000079_make_captain_bindings_unique.down.sql:1-4不可逆:up 迁移会删除重复agent_bots、agent_bot_inboxes、captain_inboxes并重指向 conversation/rule/event;down 只删索引和captain_assistant_id列,无法恢复被删行、原引用或 assistant 绑定信息。生产回滚会造成永久数据丢失。最小修复:将该迁移明确标为不可回滚并阻止自动 down,或在 up 前做可恢复备份/保留映射并实现恢复型 down。 -
backend/internal/service/captain_binding_atomicity_test.go:44-51,55-87的“并发”测试设置SetMaxOpenConns(1),8 个 goroutine 被数据库连接池串行化,不能触发 select/insert 竞态,也不能证明 PostgreSQL 的唯一约束 + ON CONFLICT 在真实并发下有效。最小修复:使用至少 2 个连接,在真实 PostgreSQL(或允许并发连接的 SQLite)上用 barrier 同时进入,并断言所有调用成功且只存在一个 bot/binding。
非阻断残余风险
backend/migrations/000079_make_captain_bindings_unique.up.sql:87-92会静默保留最小 id 并删除同一 inbox 的其他 active CaptainInbox;若历史数据代表不同 assistant,这是业务绑定丢失。部署前应核对冲突数量并记录/人工决策,而不是仅依赖迁移中的删除。- migration 未显式锁表;在线写入可能在去重后、唯一索引建立前制造新冲突,导致迁移失败(通常停写/维护窗可规避)。
已核验
go test ./internal/service -run 'Test(WidgetConversationRollsBackCaptainBindingOnCreateFailure|TestEnsureCaptainAgentBotBindingConcurrentCallsStayUnique|TestDissociateInboxRollsBackCaptainDeleteWhenBindingDeleteFails)' -count=1:通过。go test ./internal/service -run 'Test(ConversationServiceAITakeoverRejectsMissingOrAmbiguousAI|TestCaptain)' -count=1:通过。go vet ./internal/service ./internal/repository ./internal/model、go build ./...:通过。- 事务实现确认:widget conversation、Captain bot、AgentBotInbox 在同一
Transaction;解绑两次删除在同一Transaction,失败会回滚。
因此:三个 P1 中“widget conversation 原子创建”和“解绑失败回滚”已关闭;“assistant/inbox 并发唯一性”代码路径有数据库约束,但当前新增测试没有有效验证真实并发;迁移回滚不可逆是新增阻断项。