Merge branch 'main' into feat/drive-sync-family

This commit is contained in:
chichuan
2026-08-13 10:38:37 +08:00
committed by GitHub
4 changed files with 68 additions and 4 deletions
+1 -1
View File
@@ -122,7 +122,7 @@ scripts/policy/interface-migrations/approved-flag-migrations-v1.json
一条 base-owned、状态正确且前后快照精确匹配的记录,只会从普通兼容报告中移除以下两类预期 finding:
1. legacy flag 的 `flag_became_hidden`(visible → hidden);
2. required legacy 被新增的 required canonical 替代时产生的 `required_flag_added`。已有 canonical 的 requiredness 不允许借 rename 改变。
2. required legacy 被新增的 required canonical 替代时产生的 `required_flag_added`;如果 canonical 在 before 阶段只是 hidden 占位符,则允许它在转为公开拼写时继承 legacy 的 requiredness。已有的 visible canonical 不允许借 rename 改变 requiredness。
以下变化仍按普通兼容规则阻塞,不能被迁移记录掩盖:
+13 -3
View File
@@ -326,8 +326,9 @@ func (m FlagMigration) validate() error {
}
// Requiredness belongs to the one logical parameter. The hidden legacy
// spelling must not remain independently required, while the canonical
// spelling inherits the exact before-state contract. If the canonical flag
// already existed, a rename receipt cannot authorize changing it either.
// spelling inherits the exact before-state contract. An already-visible
// canonical flag cannot change requiredness; an existing hidden canonical
// placeholder may inherit it when promoted to the public spelling.
if m.Legacy.After.Required {
return fmt.Errorf("legacy compatibility alias must not remain independently required after migration")
}
@@ -336,7 +337,9 @@ func (m FlagMigration) validate() error {
"flag requiredness must be preserved from legacy before to canonical after",
)
}
if m.Canonical.Before.Present && m.Canonical.Before.Required != m.Canonical.After.Required {
if m.Canonical.Before.Present &&
!m.Canonical.Before.Hidden &&
m.Canonical.Before.Required != m.Canonical.After.Required {
return fmt.Errorf("canonical flag requiredness must remain unchanged when already present")
}
if m.Legacy.After.AliasOf != m.Canonical.Name {
@@ -690,6 +693,13 @@ func flagMigrationAuthorizesChange(
change.Kind == "required_flag_added" {
return true
}
if migration.Canonical.Before.Present &&
migration.Canonical.Before.Hidden &&
!migration.Canonical.Before.Required &&
migration.Canonical.After.Required &&
change.Kind == "flag_became_required" {
return true
}
}
return false
}
@@ -792,6 +792,35 @@ func TestCrossPlatformCoverageCompareAllWithFlagMigrationsInheritedAndOptionalCa
t.Fatalf("existing optional canonical migration = (%#v, %v), want compatible", report, err)
}
})
t.Run("hidden canonical inherits requiredness when promoted", func(t *testing.T) {
pending := coverageManifest(FlagMigrationPending)
pending.Migrations[0].Canonical.Before = FlagMigrationState{
Present: true,
Type: "string",
Hidden: true,
Scope: "local",
}
consumed := pending
consumed.Migrations = append([]FlagMigration(nil), pending.Migrations...)
consumed.Migrations[0].State = FlagMigrationConsumed
before := coverageMigrationSnapshot(pending.Migrations[0], false, false)
after := coverageMigrationSnapshot(pending.Migrations[0], true, false)
ordinary := Compare(after, before, "merge-base")
if !hasFlagChange(ordinary.Blocking, "flag_became_required", pending.Migrations[0].Command, pending.Migrations[0].Canonical.Name) {
t.Fatalf("fixture did not change canonical requiredness: %#v", ordinary.Blocking)
}
report, err := CompareAllWithFlagMigrations(
after,
map[string]Snapshot{"merge-base": before, "stable": before},
pending,
consumed,
)
if err != nil || !report.Compatible {
t.Fatalf("hidden canonical promotion = (%#v, %v), want compatible", report, err)
}
})
}
func TestCrossPlatformCoverageOptionalFlagMigrationLifecycleRemainsHostile(t *testing.T) {
@@ -5,6 +5,7 @@ package interfacesnapshot
import (
"errors"
"os"
"reflect"
"strings"
"testing"
@@ -52,6 +53,27 @@ func optionalFlagMigrationManifestJSON() string {
)
}
func hiddenCanonicalFlagMigrationManifestJSON() string {
return strings.Replace(
validFlagMigrationManifestJSON,
`"before": {"present": false}`,
`"before": {"present": true, "type": "string", "hidden": true, "scope": "local"}`,
1,
)
}
func TestApprovedFlagMigrationManifestRemainsValid(t *testing.T) {
manifest, err := os.Open("../../scripts/policy/interface-migrations/approved-flag-migrations-v1.json")
if err != nil {
t.Fatalf("open approved flag migration manifest: %v", err)
}
defer manifest.Close()
if _, err := ReadFlagMigrationManifest(manifest); err != nil {
t.Fatalf("approved flag migration manifest is invalid: %v", err)
}
}
func TestCrossPlatformCoverageReadFlagMigrationManifestRejectsUnknownFields(t *testing.T) {
_, err := ReadFlagMigrationManifest(strings.NewReader(`{
"version": 1,
@@ -128,6 +150,9 @@ func TestCrossPlatformCoverageReadFlagMigrationManifestValidatesExactEntries(t *
if _, err := ReadFlagMigrationManifest(strings.NewReader(optionalFlagMigrationManifestJSON())); err != nil {
t.Fatalf("ReadFlagMigrationManifest(optional rename) error = %v", err)
}
if _, err := ReadFlagMigrationManifest(strings.NewReader(hiddenCanonicalFlagMigrationManifestJSON())); err != nil {
t.Fatalf("ReadFlagMigrationManifest(hidden canonical promotion) error = %v", err)
}
tests := []struct {
name string