Files
Agent-System-Backend/internal/store/migrate_compat.go
T

123 lines
5.2 KiB
Go
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.
package store
import "fmt"
// migrationBreaksOldReaders 登记每个迁移版本落地后,schema.target 更低的旧制品
// 还能不能读这个库。新增迁移漏登记时 TestMigrationCompatRegistered 失败。
// true 会抬高 SchemaCompatFloor:候选若要把库迁过该版本,而旧制品的 target
// 低于该下限,切换必须在停旧服务前拒绝,除非走已确认的 forward-only 迁移。
var migrationBreaksOldReaders = map[int]bool{
1: false,
2: false,
3: false,
4: false,
5: false,
6: false,
7: false,
8: false,
9: false,
10: false,
11: false,
12: false,
13: false,
14: false,
15: false,
16: false,
17: false,
18: false,
19: false,
20: false,
21: false,
22: false,
23: false,
24: false,
25: false,
26: false,
27: false,
28: false, // auth_version_account_events:仅加列与新表,旧读者不受影响
29: false, // redeem_attempts:新表,旧读者不受影响
30: false, // project_event_publication_proofs:新表,旧读者不受影响
31: false, // account_audit 给 audit_events 增加带默认值的列,旧制品按列名读取
32: true, // 账号有效态/凭据来源是安全协议边界;旧认证写者必须排除
33: true, // 本人证明与 grant 绑定协议;旧恢复写者和兑换者必须排除
34: false, // 游标签名密钥只新增内部列;旧读者按列名读取既有字段
35: false, // exec_env 新表;旧读者不读这些表
36: false, // instance_guard 是新表,旧制品不读取它
37: false, // work_task_bindings:新增绑定表,旧后台任务读面不受影响
38: false, // trusted_context_manifests:独立可信回执表,旧读者不受影响
39: false, // workflow_step_sources:新增逐步骤来源绑定表,旧读者不受影响
40: false, // context_manifest_resolve_scope:可信回执增加范围标记,旧读者不受影响
41: false, // scrub_candidate_context_scope_text:候选原文列清理,旧读者不受影响
42: false, // command_audit_attribution_snapshot:仅加列/索引,旧读者不受影响
43: false, // project_audit_committed_links:新表,旧读者不受影响
44: false, // project_audit_committed_prefix:PG 审计 ID 默认函数,旧读者兼容
45: false, // project_audit_all_writers_guard:PG 在线审计写入门禁,旧读者兼容
46: false, // project_work_observation_outbox:独立私域投递表,旧读者不读取
47: false, // human_decision_proofs:独立真人确认表,旧读者不读取
48: false, // document_render_deliveries:新增普通工作区文档交付回执表
49: false, // 角色权威仅新增独立表;消费者切换由公开提供者 readiness 单独围栏
50: false, // 角色导入 staging 为独立表;正式角色读取在激活前不变
51: true, // 超级管理员标记是账号权威边界;不认识它的旧账号写者必须排除
}
// SchemaTarget 是本二进制会迁移到的 schema 版本。
func SchemaTarget() int { return latestMigrationVersion() }
// MigrationName lets the offline copier reject an unpublished branch schema
// that reused a numeric version for a different migration before copying rows.
func MigrationName(version int) (string, bool) {
for _, migration := range migrations {
if migration.version == version {
return migration.name, true
}
}
return "", false
}
// legacyFeatureMigrationNames records the unpublished project-context/audit
// candidate numbering that collided with the adopted v35 exec_env migration.
// These identities are intentionally not aliases: accepting them would mark a
// different schema as applied. Operators must first move that candidate through
// an explicit, reviewed compatibility procedure.
var legacyFeatureMigrationNames = map[int]string{
35: "work_task_bindings",
36: "trusted_context_manifests",
37: "workflow_step_sources",
38: "context_manifest_resolve_scope",
39: "scrub_candidate_context_scope_text",
40: "command_audit_attribution_snapshot",
41: "project_audit_committed_links",
42: "project_audit_committed_prefix",
43: "project_audit_all_writers_guard",
44: "project_work_observation_outbox",
45: "human_decision_proofs",
}
// ValidateMigrationIdentity rejects any ledger row whose numeric version names
// a different migration. Known unpublished feature identities get a specific
// fail-closed error so they cannot be mistaken for the adopted exec_env history.
func ValidateMigrationIdentity(version int, actual string) error {
expected, known := MigrationName(version)
if !known {
return fmt.Errorf("migration identity mismatch at v%d; refuse to reinterpret another schema", version)
}
if actual == expected {
return nil
}
if legacyFeatureMigrationNames[version] == actual {
return fmt.Errorf("migration identity mismatch at v%d: legacy feature migration numbering %q conflicts with adopted history %q; refuse automatic reinterpretation", version, actual, expected)
}
return fmt.Errorf("migration identity mismatch at v%d; refuse to reinterpret another schema", version)
}
// SchemaCompatFloor 是旧制品仍能读取的最高破坏性版本。0 表示当前全部迁移都不破坏旧读。
func SchemaCompatFloor() int {
floor := 0
for version, breaks := range migrationBreaksOldReaders {
if breaks && version > floor {
floor = version
}
}
return floor
}