Files
Agent-System-Backend/internal/store/migrate_compat.go
T
weichenandCursor 84a6f6ff56
governance / governance (pull_request) Successful in 17s
ci / vet-and-test (pull_request) Successful in 1m2s
Merge Backend main into the shared renderer and two-trees work
Why: PR #209 is behind main by 14 commits (admin passwords, managed
interpreter path, U8 SQLite instance guard, EXT-20 regulations) and conflicted
in app wiring, host capabilities, migrations and the extension surface; the
user authorized merging the renderer line on 2026-10-18.
Evidence: content is the agent-exec transport 87a99ece (cursor worker, unit
backend-task10-sync-main-56a7f9f-r2, receipt
/tmp/cleanup-20261018/render/backend-sync-run2.json, SELF): gofmt, go build,
go vet and go test ./... (43 packages) passed. Host check: main migrations
1-36 unchanged, feature migrations moved from 36-47 to 37-48 in order with
identical SQL, surface.txt is the sorted union.
Impact: main's migration 36 instance_guard stays authoritative; databases that
ran unmerged feature builds with the old numbering must be recreated.
SurfaceVersion becomes 2.24.0-experimental.
Refs: PR #209, Backend main 56a7f9f

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 12:34:42 +00:00

120 lines
5.0 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:新增普通工作区文档交付回执表
}
// 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
}