Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 52 additions & 18 deletions internal/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -1224,37 +1224,71 @@ func (s *Store) RepairCloudUpgrade(project string, apply bool) (CloudUpgradeRepa
if err != nil {
return CloudUpgradeRepairReport{}, fmt.Errorf("diagnose legacy cloud upgrade mutations: %w", err)
}

// Apply the repairable subset first. Holding the entire repair pass hostage
// to a single unrecoverable mutation forces operators into manual SQLite
// surgery for the rest of the queue; instead we let recoverable findings
// make forward progress and surface the residual blockers afterwards.
appliedRepairs := false
if apply && legacyReport.RepairableCount > 0 {
if err := s.applyCloudUpgradeLegacyMutationRepairs(project); err != nil {
return CloudUpgradeRepairReport{}, fmt.Errorf("apply cloud upgrade legacy mutation repairs: %w", err)
}
appliedRepairs = true
}

if legacyReport.BlockedCount > 0 {
first := legacyReport.Findings[0]
// Pick the first non-repairable finding so the user sees the actual
// blocker. Findings[0] is ordered by sync_mutations.seq and may be a
// repairable one, which previously produced misleading error messages.
var blocked CloudUpgradeLegacyMutationFinding
for _, f := range legacyReport.Findings {
if !f.Repairable {
blocked = f
break
}
}
var msg string
switch {
case appliedRepairs:
msg = fmt.Sprintf("applied %d repairable payload(s); %d remain blocked: manual-action-required: %s (seq=%d entity=%s entity_key=%q op=%s)",
legacyReport.RepairableCount, legacyReport.BlockedCount, blocked.Message, blocked.Seq, blocked.Entity, blocked.EntityKey, blocked.Op)
case legacyReport.RepairableCount > 0:
msg = fmt.Sprintf("%d repairable payload(s) would apply; %d would remain blocked: manual-action-required: %s (seq=%d entity=%s entity_key=%q op=%s)",
legacyReport.RepairableCount, legacyReport.BlockedCount, blocked.Message, blocked.Seq, blocked.Entity, blocked.EntityKey, blocked.Op)
default:
msg = fmt.Sprintf("manual-action-required: %s (seq=%d entity=%s entity_key=%q op=%s)",
blocked.Message, blocked.Seq, blocked.Entity, blocked.EntityKey, blocked.Op)
}
return CloudUpgradeRepairReport{
Class: UpgradeRepairClassBlocked,
ReasonCode: UpgradeReasonBlockedLegacyMutationManual,
Message: fmt.Sprintf("manual-action-required: %s (seq=%d entity=%s op=%s)", first.Message, first.Seq, first.Entity, first.Op),
Applied: false,
Message: msg,
Applied: appliedRepairs,
}, nil
}
if legacyReport.RepairableCount > 0 {
report := CloudUpgradeRepairReport{
Class: UpgradeRepairClassRepairable,
ReasonCode: UpgradeReasonRepairableLegacyMutationPayload,
Message: fmt.Sprintf("project %q has %d repairable legacy mutation payload issue(s)", project, legacyReport.RepairableCount),
PlannedAction: "repair_legacy_mutation_payloads",
Applied: false,
}
if !apply {
return report, nil
}
if err := s.applyCloudUpgradeLegacyMutationRepairs(project); err != nil {
return CloudUpgradeRepairReport{}, fmt.Errorf("apply cloud upgrade legacy mutation repairs: %w", err)
if !appliedRepairs {
return CloudUpgradeRepairReport{
Class: UpgradeRepairClassRepairable,
ReasonCode: UpgradeReasonRepairableLegacyMutationPayload,
Message: fmt.Sprintf("project %q has %d repairable legacy mutation payload issue(s)", project, legacyReport.RepairableCount),
PlannedAction: "repair_legacy_mutation_payloads",
Applied: false,
}, nil
}
report.Applied = true
report.Message = fmt.Sprintf("applied deterministic legacy mutation payload repairs for project %q", project)
_ = s.SaveCloudUpgradeState(CloudUpgradeState{
Project: project,
Stage: UpgradeStageRepairApplied,
RepairClass: UpgradeRepairClassRepairable,
})
return report, nil
return CloudUpgradeRepairReport{
Class: UpgradeRepairClassRepairable,
ReasonCode: UpgradeReasonRepairableLegacyMutationPayload,
Message: fmt.Sprintf("applied deterministic legacy mutation payload repairs for project %q", project),
PlannedAction: "repair_legacy_mutation_payloads",
Applied: true,
}, nil
}

requiresBackfill, err := s.projectSyncBackfillRequired(project)
Expand Down