Why: the U4 branch is 89 commits behind main, which now carries the shared document renderer, two-trees project work, the SQLite instance guard and exec env layers (PR #209 merged asc76d8bd); it conflicted in storage migrations, host capabilities and the extension surface. The user authorized syncing U4 after the renderer line on 2026-10-18. Evidence: content is the agent-exec transport 3b64eb5 (cursor worker, unit backend-iam-u4-onto-main-c76d8bd-r1, run on a checkout whose tree equals main, receipt /tmp/cleanup-20261018/render/u4-backend-onto-run.json, SELF). Host check: main migrations 1-48 unchanged (migrate.go has no deleted lines versus main), U4 migrations moved from 35-36 to 49-50 with identical SQL, surface.txt is the sorted union, deps stay at main's pins. Impact: databases that ran unmerged U4 builds with the old numbering must be recreated. SurfaceVersion becomes 2.25.0-experimental. Main's admin password account creation now requires the system.users.create action like the other U4 account writes. Refs: Backend mainc76d8bd, PR #209 Co-authored-by: Cursor <cursoragent@cursor.com>
74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
package store
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestMigrationCompatRegistered(t *testing.T) {
|
|
if len(migrationBreaksOldReaders) != len(migrations) {
|
|
t.Fatalf("兼容登记 %d 条,迁移 %d 条", len(migrationBreaksOldReaders), len(migrations))
|
|
}
|
|
for _, m := range migrations {
|
|
if _, ok := migrationBreaksOldReaders[m.version]; !ok {
|
|
t.Fatalf("迁移 v%d %s 未登记是否破坏旧制品读取", m.version, m.name)
|
|
}
|
|
}
|
|
if SchemaTarget() != latestMigrationVersion() {
|
|
t.Fatalf("target=%d latest=%d", SchemaTarget(), latestMigrationVersion())
|
|
}
|
|
if SchemaCompatFloor() < 0 || SchemaCompatFloor() > SchemaTarget() {
|
|
t.Fatalf("compatFloor=%d target=%d", SchemaCompatFloor(), SchemaTarget())
|
|
}
|
|
}
|
|
|
|
func TestMigrationTailKeepsAdoptedExecEnvBeforeFeatureHistory(t *testing.T) {
|
|
want := []struct {
|
|
version int
|
|
name string
|
|
}{
|
|
{35, "exec_env_layers"},
|
|
{36, "instance_guard"},
|
|
{37, "work_task_bindings"},
|
|
{38, "trusted_context_manifests"},
|
|
{39, "workflow_step_sources"},
|
|
{40, "context_manifest_resolve_scope"},
|
|
{41, "scrub_candidate_context_scope_text"},
|
|
{42, "command_audit_attribution_snapshot"},
|
|
{43, "project_audit_committed_links"},
|
|
{44, "project_audit_committed_prefix"},
|
|
{45, "project_audit_all_writers_guard"},
|
|
{46, "project_work_observation_outbox"},
|
|
{47, "human_decision_proofs"},
|
|
{48, "document_render_deliveries"},
|
|
{49, "role_policy_authority"},
|
|
{50, "role_authority_import_stage"},
|
|
}
|
|
for _, item := range want {
|
|
if got, ok := MigrationName(item.version); !ok || got != item.name {
|
|
t.Fatalf("migration v%d=%q,%v want %q,true", item.version, got, ok, item.name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLegacyFeatureMigrationIdentitiesAreNeverAliases(t *testing.T) {
|
|
for version, legacyName := range legacyFeatureMigrationNames {
|
|
err := ValidateMigrationIdentity(version, legacyName)
|
|
if err == nil {
|
|
t.Fatalf("legacy v%d %q was accepted", version, legacyName)
|
|
}
|
|
if got := err.Error(); !containsAll(got, "migration identity mismatch", "legacy feature migration numbering") {
|
|
t.Fatalf("legacy v%d %q was not explicitly rejected: %v", version, legacyName, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func containsAll(value string, parts ...string) bool {
|
|
for _, part := range parts {
|
|
if !strings.Contains(value, part) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|