# P6 无外键新装基线验证 验证日期:2026-09-20。此次补齐的是数据库初始化边界:历史迁移文件保持不可变,已有库仍从原账本前向升级;空库由迁移器直接执行当前版本基线,再登记 1–28 的迁移名称和校验和。基线不包含 `FOREIGN KEY`、`REFERENCES`、迁移账本表或固定 `DEFINER`,因此新库初始化不会先创建历史外键。 ## 实现 - [迁移入口](../../internal/storage/mysql/migrate.go) 在取得数据库级迁移锁后区分空库和已有 Orbit 表;存在业务表但没有账本,或账本为空而已有业务表时拒绝猜测历史。 - [无外键基线](../../internal/storage/mysql/baseline.sql) 由当前 v28 最终结构生成,保留表、索引、唯一约束、CHECK、生成列和不可变触发器;不包含外键、引用约束或客户端 `DELIMITER` 脚本。 - 基线执行前把所有历史版本写成 `dirty=true`,全部 DDL 成功后统一清除脏标记。中断会阻断后续迁移,必须由运维核对实际结构后处理,不能自动跳过。 - [无外键单元检查](../../internal/storage/mysql/no_foreign_keys_test.go) 禁止基线重新出现引用 DDL,并要求基线版本和迁移末版本一致。 ## 实际验证 | 场景 | 结果 | 证据 | | --- | --- | --- | | 空 MySQL 8.4 数据库执行 `orbit-migrate up` | PASS | `TestIntegrationFreshInstallUsesNoForeignKeys`,迁移账本 28 条、`information_schema.REFERENTIAL_CONSTRAINTS` 为 0、`CheckSchema` 通过 | | v7 历史库升级到当前版本 | PASS | `TestIntegrationNoForeignKeysUpgrade`,历史 70 条外键删除为 0,323 个既有索引组件和任务数据保留,手工外键漂移被拒绝 | | CLI 结构核验 | PASS | `orbit-admin verify` 输出 `schema_version=28`、`migration_count=28`、`foreign_key_count=0`、`complete=true` | 验证命令使用 Docker `golang:1.25` 临时工具链和 MySQL 8.4 一次性容器;不是 Go 1.27.1 标准全量回归,也不代表复制、切换、RPO/RTO 或生产拓扑验收。 ## 运维边界 升级旧库仍必须停用不兼容写节点,在维护窗口执行正式迁移并随后运行 `orbit-admin verify`。新装基线只解决初始化阶段的外键约束问题,不会替代应用事务中的命名空间、资源归属和权限校验;数据库关联字段仍由服务端显式核对。